@lion/ui 0.18.0-menu-system.5 → 0.18.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 (242) hide show
  1. package/collapsible.js +0 -1
  2. package/components/button/src/LionButton.js +0 -4
  3. package/components/button/test-suites/LionButton.suite.js +0 -1
  4. package/components/calendar/src/LionCalendar.js +1 -3
  5. package/components/combobox/test/lion-combobox.test.js +0 -1
  6. package/components/form-core/src/form-group/FormGroupMixin.js +0 -7
  7. package/components/form-core/src/registration/FormRegistrarMixin.js +0 -11
  8. package/components/form-core/test/FormControlMixin.test.js +0 -1
  9. package/components/form-core/test/validate/Validator.test.js +0 -2
  10. package/components/form-core/test-suites/ValidateMixin.suite.js +0 -2
  11. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +0 -1
  12. package/components/input-datepicker/src/localizeNamespaceLoader.js +0 -1
  13. package/components/input-datepicker/test/lion-input-datepicker.test.js +6 -5
  14. package/components/listbox/test-suites/ListboxMixin.suite.js +1 -7
  15. package/components/localize/src/date/utils/normalizeIntlDate.js +2 -3
  16. package/components/localize/test/date/formatDate.test.js +2 -3
  17. package/components/overlays/src/OverlayController.js +110 -278
  18. package/components/overlays/src/OverlayMixin.js +11 -58
  19. package/components/overlays/src/OverlaysManager.js +2 -2
  20. package/components/overlays/src/configurations/withDropdownConfig.js +2 -22
  21. package/components/overlays/src/configurations/withPopoverConfig.js +32 -0
  22. package/components/overlays/src/utils/adopt-styles.js +5 -4
  23. package/components/overlays/src/utils/get-focusable-elements.js +0 -4
  24. package/components/overlays/src/utils/is-equal-config.js +6 -10
  25. package/components/overlays/test/OverlayController.test.js +21 -128
  26. package/components/overlays/test/utils-tests/is-equal-config.test.js +1 -1
  27. package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
  28. package/components/overlays/types/ArrowMixinTypes.ts +1 -3
  29. package/components/overlays/types/OverlayConfig.ts +5 -20
  30. package/components/select-rich/test/lion-select-rich.test.js +0 -3
  31. package/components/switch/src/LionSwitchButton.js +8 -3
  32. package/components/switch/test/lion-switch-button.test.js +38 -0
  33. package/custom-elements.json +17566 -30468
  34. package/dist-types/components/button/src/LionButton.d.ts +0 -1
  35. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  36. package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
  37. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  38. package/dist-types/components/dialog/src/LionDialog.d.ts +1 -5
  39. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  40. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  41. package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
  42. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  43. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  44. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
  45. package/dist-types/components/listbox/test-suites/ListboxMixin.suite.d.ts.map +1 -1
  46. package/dist-types/components/localize/src/date/utils/normalizeIntlDate.d.ts.map +1 -1
  47. package/dist-types/components/overlays/src/OverlayController.d.ts +12 -24
  48. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  49. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  50. package/dist-types/components/overlays/src/configurations/withDropdownConfig.d.ts +0 -1
  51. package/dist-types/components/overlays/src/configurations/withDropdownConfig.d.ts.map +1 -1
  52. package/dist-types/components/overlays/src/configurations/withPopoverConfig.d.ts +6 -0
  53. package/dist-types/components/overlays/src/configurations/withPopoverConfig.d.ts.map +1 -0
  54. package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
  55. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  56. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  57. package/dist-types/components/overlays/types/OverlayConfig.d.ts +2 -12
  58. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  59. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +2 -10
  60. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  61. package/dist-types/components/switch/src/LionSwitchButton.d.ts +6 -0
  62. package/dist-types/components/switch/src/LionSwitchButton.d.ts.map +1 -1
  63. package/dist-types/exports/overlays.d.ts +1 -3
  64. package/dist-types/exports/overlays.d.ts.map +1 -1
  65. package/dist-types/tsconfig.tsbuildinfo +1 -1
  66. package/docs/components/checkbox-group/overview.md +2 -2
  67. package/docs/components/collapsible/overview.md +1 -1
  68. package/docs/components/combobox/api-table.md +8 -21
  69. package/docs/components/combobox/overview.md +1 -1
  70. package/docs/components/combobox/use-cases.md +1 -1
  71. package/docs/components/dialog/api-table.md +6 -31
  72. package/docs/components/dialog/overview.md +1 -1
  73. package/docs/components/fieldset/overview.md +5 -5
  74. package/docs/components/form/overview.md +3 -3
  75. package/docs/components/form/use-cases.md +2 -2
  76. package/docs/components/icon/use-cases.md +1 -1
  77. package/docs/components/input/overview.md +1 -1
  78. package/docs/components/input-amount/overview.md +3 -3
  79. package/docs/components/input-date/overview.md +3 -3
  80. package/docs/components/input-datepicker/api-table.md +4 -21
  81. package/docs/components/input-datepicker/overview.md +5 -5
  82. package/docs/components/input-email/overview.md +2 -2
  83. package/docs/components/input-file/overview.md +1 -1
  84. package/docs/components/input-iban/overview.md +2 -2
  85. package/docs/components/input-range/overview.md +2 -2
  86. package/docs/components/input-stepper/overview.md +1 -1
  87. package/docs/components/input-tel/overview.md +1 -1
  88. package/docs/components/input-tel/use-cases.md +6 -6
  89. package/docs/components/input-tel-dropdown/overview.md +1 -1
  90. package/docs/components/listbox/use-cases.md +1 -1
  91. package/docs/components/radio-group/overview.md +3 -3
  92. package/docs/components/select/use-cases.md +1 -1
  93. package/docs/components/select-rich/api-table.md +5 -21
  94. package/docs/components/select-rich/use-cases.md +2 -2
  95. package/docs/components/switch/api-table.md +2 -0
  96. package/docs/components/tabs/examples.md +1 -1
  97. package/docs/components/tooltip/api-table.md +11 -36
  98. package/docs/fundamentals/index.md +4 -4
  99. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  100. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  101. package/docs/fundamentals/rationales/accessibility.md +1 -1
  102. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  103. package/docs/fundamentals/systems/core/overview.md +1 -1
  104. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  105. package/docs/fundamentals/systems/form/model-value.md +1 -1
  106. package/docs/fundamentals/systems/form/overview.md +28 -28
  107. package/docs/fundamentals/systems/form/validate.md +2 -2
  108. package/docs/fundamentals/systems/localize/overview.md +4 -4
  109. package/docs/fundamentals/systems/overlays/api-table.md +34 -36
  110. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  111. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  112. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  113. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  114. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  115. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  116. package/docs/guides/how-to/create-a-form.md +4 -4
  117. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  118. package/docs/guides/how-to/index.md +1 -1
  119. package/docs/guides/index.md +8 -8
  120. package/docs/guides/principles/index.md +5 -5
  121. package/docs/guides/principles/styling.md +1 -1
  122. package/exports/collapsible.js +0 -1
  123. package/exports/overlays.js +1 -6
  124. package/overlays.js +1 -6
  125. package/package.json +1 -1
  126. package/components/collapsible/src/DisclosureMixin.js +0 -313
  127. package/components/collapsible/test-suites/DisclosureMixin.suite.js +0 -30
  128. package/components/collapsible/types/DisclosureMixinTypes.ts +0 -48
  129. package/components/menu/CHANGELOG.md +0 -37
  130. package/components/menu/README.md +0 -335
  131. package/components/menu/index.js +0 -2
  132. package/components/menu/lion-menu-overlay.js +0 -3
  133. package/components/menu/lion-menu.js +0 -3
  134. package/components/menu/lion-spinbutton.js +0 -3
  135. package/components/menu/lion-toolbar.js +0 -3
  136. package/components/menu/lion-tree.js +0 -3
  137. package/components/menu/package.json +0 -46
  138. package/components/menu/requirements.temp.md +0 -12
  139. package/components/menu/src/InteractiveListMixin.js +0 -838
  140. package/components/menu/src/LionMenu.js +0 -250
  141. package/components/menu/src/LionMenuHybrid.js +0 -46
  142. package/components/menu/src/LionMenuOverlay.js +0 -155
  143. package/components/menu/src/LionSpinbutton.js +0 -213
  144. package/components/menu/src/LionToolbar.js +0 -94
  145. package/components/menu/src/LionTree.js +0 -52
  146. package/components/menu/src/MoreButtonMenuMixin.js +0 -287
  147. package/components/menu/src/MultiLevelListMixin.js +0 -274
  148. package/components/menu/src/utils/isInView.js +0 -26
  149. package/components/menu/src/utils/listItemInteractions.js +0 -123
  150. package/components/menu/src/utils/uuid.js +0 -3
  151. package/components/menu/test/lion-menu.test.js +0 -4
  152. package/components/menu/test-suites/InteractiveListMixin.suite.js +0 -304
  153. package/components/menu/types/InteractiveListMixinTypes.d.ts +0 -82
  154. package/components/navigation-bar/README.md +0 -1
  155. package/components/navigation-bar/src/LionNavigationBar.js +0 -439
  156. package/components/navigation-bar/src/types.js +0 -41
  157. package/components/overlays/NEXT.md +0 -49
  158. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +0 -3
  159. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +0 -1
  160. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts +0 -2
  161. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts.map +0 -1
  162. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +0 -24
  163. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +0 -1
  164. package/dist-types/components/menu/index.d.ts +0 -3
  165. package/dist-types/components/menu/index.d.ts.map +0 -1
  166. package/dist-types/components/menu/lion-menu-overlay.d.ts +0 -2
  167. package/dist-types/components/menu/lion-menu-overlay.d.ts.map +0 -1
  168. package/dist-types/components/menu/lion-menu.d.ts +0 -2
  169. package/dist-types/components/menu/lion-menu.d.ts.map +0 -1
  170. package/dist-types/components/menu/lion-spinbutton.d.ts +0 -2
  171. package/dist-types/components/menu/lion-spinbutton.d.ts.map +0 -1
  172. package/dist-types/components/menu/lion-toolbar.d.ts +0 -2
  173. package/dist-types/components/menu/lion-toolbar.d.ts.map +0 -1
  174. package/dist-types/components/menu/lion-tree.d.ts +0 -2
  175. package/dist-types/components/menu/lion-tree.d.ts.map +0 -1
  176. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +0 -617
  177. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +0 -1
  178. package/dist-types/components/menu/src/LionMenu.d.ts +0 -565
  179. package/dist-types/components/menu/src/LionMenu.d.ts.map +0 -1
  180. package/dist-types/components/menu/src/LionMenuHybrid.d.ts +0 -19
  181. package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +0 -1
  182. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +0 -1013
  183. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +0 -1
  184. package/dist-types/components/menu/src/LionSpinbutton.d.ts +0 -58
  185. package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +0 -1
  186. package/dist-types/components/menu/src/LionToolbar.d.ts +0 -8
  187. package/dist-types/components/menu/src/LionToolbar.d.ts.map +0 -1
  188. package/dist-types/components/menu/src/LionTree.d.ts +0 -447
  189. package/dist-types/components/menu/src/LionTree.d.ts.map +0 -1
  190. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +0 -40
  191. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +0 -1
  192. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +0 -495
  193. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +0 -1
  194. package/dist-types/components/menu/src/utils/isInView.d.ts +0 -9
  195. package/dist-types/components/menu/src/utils/isInView.d.ts.map +0 -1
  196. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +0 -48
  197. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +0 -1
  198. package/dist-types/components/menu/src/utils/uuid.d.ts +0 -2
  199. package/dist-types/components/menu/src/utils/uuid.d.ts.map +0 -1
  200. package/dist-types/components/menu/test/lion-menu.test.d.ts +0 -2
  201. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +0 -1
  202. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +0 -14
  203. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +0 -1
  204. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +0 -238
  205. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +0 -1
  206. package/dist-types/components/navigation-bar/src/types.d.ts +0 -85
  207. package/dist-types/components/navigation-bar/src/types.d.ts.map +0 -1
  208. package/dist-types/exports/define/lion-item.d.ts +0 -2
  209. package/dist-types/exports/define/lion-item.d.ts.map +0 -1
  210. package/dist-types/exports/define/lion-menu-overlay.d.ts +0 -2
  211. package/dist-types/exports/define/lion-menu-overlay.d.ts.map +0 -1
  212. package/dist-types/exports/define/lion-menu.d.ts +0 -2
  213. package/dist-types/exports/define/lion-menu.d.ts.map +0 -1
  214. package/dist-types/exports/define/lion-navigation-bar.d.ts +0 -2
  215. package/dist-types/exports/define/lion-navigation-bar.d.ts.map +0 -1
  216. package/dist-types/exports/define/lion-toolbar.d.ts +0 -2
  217. package/dist-types/exports/define/lion-toolbar.d.ts.map +0 -1
  218. package/dist-types/exports/define/lion-tree.d.ts +0 -2
  219. package/dist-types/exports/define/lion-tree.d.ts.map +0 -1
  220. package/dist-types/exports/menu-test-suites.d.ts +0 -2
  221. package/dist-types/exports/menu-test-suites.d.ts.map +0 -1
  222. package/dist-types/exports/menu.d.ts +0 -7
  223. package/dist-types/exports/menu.d.ts.map +0 -1
  224. package/dist-types/exports/navigation-bar.d.ts +0 -2
  225. package/dist-types/exports/navigation-bar.d.ts.map +0 -1
  226. package/docs/components/menu/api-table.md +0 -455
  227. package/docs/components/menu/applyMenuDemoStyles.js +0 -173
  228. package/docs/components/menu/extensions.md +0 -262
  229. package/docs/components/menu/index.md +0 -13
  230. package/docs/components/menu/overview.md +0 -422
  231. package/exports/define/lion-item.js +0 -3
  232. package/exports/define/lion-menu-overlay.js +0 -3
  233. package/exports/define/lion-menu.js +0 -3
  234. package/exports/define/lion-navigation-bar.js +0 -3
  235. package/exports/define/lion-toolbar.js +0 -3
  236. package/exports/define/lion-tree.js +0 -3
  237. package/exports/menu-test-suites.js +0 -2
  238. package/exports/menu.js +0 -7
  239. package/exports/navigation-bar.js +0 -1
  240. package/menu-test-suites.js +0 -2
  241. package/menu.js +0 -7
  242. package/navigation-bar.js +0 -1
@@ -1,94 +0,0 @@
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
- }
@@ -1,52 +0,0 @@
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 > 0) {
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
- }
@@ -1,287 +0,0 @@
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: 1px;
22
- width: 1px;
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
- moreButtonWrapper.appendChild(moreButtonMenu);
79
- this._listNode.appendChild(moreButtonWrapper);
80
-
81
- const isElementDirectFocusableItemUnderMoreButtonMenu = (/** @type {Element} */ element) =>
82
- this.listItems.includes(element) && moreButtonMenu.contains(element);
83
-
84
- moreButtonMenu.addEventListener(
85
- 'focusin',
86
- /** @type {FocusEvent} */ event => {
87
- const target = /** @type {HTMLElement} */ (event?.target);
88
- if (!isElementDirectFocusableItemUnderMoreButtonMenu(target)) return;
89
-
90
- // A user did `Shift + Tab` from L2 menu to More menu
91
- if (target?.getAttribute('aria-expanded') === 'true') {
92
- // close L2 menu
93
- target?.click();
94
- }
95
- moreButton?.setAttribute('aria-expanded', 'true');
96
- moreButtonMenu.setAttribute('data-open', '');
97
- },
98
- );
99
-
100
- moreButtonMenu.addEventListener('focusout', () => {
101
- // We need this timeout for Safari/WebKit.
102
- // Unfortunately, an in progress click gets canceled when overflow:hidden is applied.
103
- // Although mousedown would work instead, the consuming developer should have the freedom to apply all possible interaction pattterns.
104
- // Especially, we should be compatible with 'withClickInteraction'
105
- setTimeout(() => {
106
- if (isElementDirectFocusableItemUnderMoreButtonMenu(this._getDeepActiveElement())) return;
107
- moreButton?.setAttribute('aria-expanded', 'false');
108
-
109
- moreButtonMenu.removeAttribute('data-open');
110
- }, 100);
111
- });
112
-
113
- this.hasMoreButtonMenuAnyFocusedFirstLevelItems = false;
114
-
115
- moreButton?.addEventListener('mousedown', () => {
116
- this.hasMoreButtonMenuAnyFocusedFirstLevelItems = false;
117
- const focusableFirstLevelItems = moreButtonMenu.querySelectorAll(
118
- ':scope > [role="listitem"] > :is(a, button)',
119
- );
120
-
121
- // @ts-ignore Type 'NodeListOf<Element>' must have a '[Symbol.iterator]()' method that returns an iterator.
122
- for (const focusableFirstLevelItem of focusableFirstLevelItems) {
123
- if (this._getDeepActiveElement() === focusableFirstLevelItem) {
124
- this.hasMoreButtonMenuAnyFocusedFirstLevelItems = true;
125
- }
126
- }
127
- });
128
-
129
- moreButton?.addEventListener('click', () => {
130
- if (this.hasMoreButtonMenuAnyFocusedFirstLevelItems) return;
131
- /** @type {HTMLElement | null} */
132
- const firstInteractiveItem = moreButtonMenu.querySelector(
133
- ':scope > [role="listitem"] > :is(a, button)',
134
- );
135
-
136
- firstInteractiveItem?.focus();
137
- moreButtonMenu.setAttribute('data-open', '');
138
- });
139
- }
140
-
141
- getMoreButtonSlotProjection() {
142
- return this.querySelector('[slot="more-button"]');
143
- }
144
-
145
- getMoreButtonMenu() {
146
- return this.querySelector('[data-more-button-menu]');
147
- }
148
-
149
- getMoreButtonMenuWrapper() {
150
- return this.querySelector('[data-more-button-wrapper]');
151
- }
152
-
153
- displayMoreButton() {
154
- this.getMoreButtonMenuWrapper().style.display = 'block';
155
- this.isMoreButtonShown = true;
156
- }
157
-
158
- hideMoreButton() {
159
- this.getMoreButtonMenuWrapper().style.display = 'none';
160
- this.isMoreButtonShown = false;
161
- }
162
-
163
- doItemsFit() {
164
- this.style.display = 'none';
165
- const parentWidth = this.parentElement.clientWidth;
166
- this.style.display = '';
167
- return (
168
- this._listNode.scrollWidth === this._listNode.clientWidth &&
169
- this._listNode.scrollWidth <= parentWidth
170
- );
171
- }
172
-
173
- getListItems() {
174
- const listNode = this._listNode;
175
- return Array.from(listNode.querySelectorAll(':scope > [role="listitem"]'));
176
- }
177
-
178
- /**
179
- * @param {Node} listItem
180
- */
181
- getListItemWithAdjacentNodes = listItem => {
182
- const markerNodeType = this.nodeType && Node.COMMENT_NODE;
183
- /** @param {Node | null | undefined} node */
184
- const isMarkerComment = node => node?.nodeType === markerNodeType && node?.nodeValue === '';
185
-
186
- const previousNodes = [];
187
- let { previousSibling } = listItem;
188
- while (previousSibling) {
189
- previousNodes.unshift(previousSibling);
190
- if (isMarkerComment(previousSibling)) {
191
- break;
192
- }
193
- ({ previousSibling } = previousSibling);
194
- }
195
-
196
- const nextNodes = [];
197
- let { nextSibling } = listItem;
198
- while (nextSibling) {
199
- nextNodes.push(nextSibling);
200
-
201
- if (isMarkerComment(nextSibling)) {
202
- break;
203
- }
204
-
205
- ({ nextSibling } = nextSibling);
206
- }
207
-
208
- const fragment = document.createDocumentFragment();
209
- const nodes = [...previousNodes, listItem, ...nextNodes];
210
- nodes.forEach(node => fragment.appendChild(node));
211
- return fragment;
212
- };
213
-
214
- /**
215
- * @param {{ moreButtonMenuElement: HTMLButtonElement, listItem: HTMLElement }} opts
216
- */
217
- moveItemToMoreButtonMenuFromMainMenu({ moreButtonMenuElement, listItem }) {
218
- const fragment = this.getListItemWithAdjacentNodes(listItem);
219
- moreButtonMenuElement.prepend(fragment);
220
- // eslint-disable-next-line no-param-reassign
221
- listItem.style.display = '';
222
- this.displayMoreButton();
223
- }
224
-
225
- moveAllItemsToMainMenuFromMoreButtonMenu() {
226
- const moreButtonMenu = this.getMoreButtonMenu();
227
- const moreButtonMenuWrapper = this.getMoreButtonMenuWrapper();
228
- if (moreButtonMenu.childNodes.length === 0) {
229
- return;
230
- }
231
- [...moreButtonMenu.childNodes].forEach(node => {
232
- moreButtonMenuWrapper.before(node);
233
- });
234
- }
235
-
236
- renderAllItemsInMainMenu() {
237
- this.moveAllItemsToMainMenuFromMoreButtonMenu();
238
- }
239
-
240
- hideItemsOneByOneInMainMenuUntilTheyFit() {
241
- let hiddenItemsCount = 0;
242
- const mainMenuItems = this.getListItems();
243
- for (let i = mainMenuItems.length - 1; i >= 0 && !this.doItemsFit(); i -= 1) {
244
- mainMenuItems[i].style.display = 'none';
245
- hiddenItemsCount += 1;
246
- }
247
- return hiddenItemsCount;
248
- }
249
-
250
- /**
251
- * @param {number} hiddenItemsCount
252
- */
253
- moveHiddenItemsFromMainMenuToMoreButtonMenu(hiddenItemsCount) {
254
- const moreButtonMenuElement = this.getMoreButtonMenu();
255
- const listItems = this._listNode.querySelectorAll(':scope > [role="listitem"]');
256
- for (let i = 0; i < hiddenItemsCount; i += 1) {
257
- const listItem = listItems[listItems.length - 1 - i];
258
- this.moveItemToMoreButtonMenuFromMainMenu({ moreButtonMenuElement, listItem });
259
- }
260
- }
261
-
262
- handleResize() {
263
- if (this.__resizeTimeout) {
264
- return;
265
- }
266
-
267
- this.style.visibility = 'hidden';
268
-
269
- this.__resizeTimeout = setTimeout(() => {
270
- this.__resizeTimeout = null;
271
-
272
- this.renderAllItemsInMainMenu();
273
- this.hideMoreButton();
274
-
275
- if (this.doItemsFit()) {
276
- this.style.visibility = '';
277
- return;
278
- }
279
-
280
- this.style.visibility = 'hidden';
281
- this.displayMoreButton();
282
- const hiddenItemsCount = this.hideItemsOneByOneInMainMenuUntilTheyFit();
283
- this.moveHiddenItemsFromMainMenuToMoreButtonMenu(hiddenItemsCount);
284
- this.style.visibility = '';
285
- }, 50);
286
- }
287
- };
@@ -1,274 +0,0 @@
1
- /* eslint-disable import/no-extraneous-dependencies */
2
- import { html } from 'lit';
3
- import { dedupeMixin } from '@open-wc/dedupe-mixin';
4
- // import { DisclosureMixin } from '@lion/ui/collapsible.js';
5
- import { InteractiveListMixin } from './InteractiveListMixin.js';
6
-
7
- /**
8
- * @typedef {import('./InteractiveListMixin.js').LionItem} LionItem
9
- * @typedef {import('../types/InteractiveListMixinTypes.js').InteractiveListHost} InteractiveList
10
- */
11
-
12
- /**
13
- * All logic that is needed for interactive lists that are allowed to have multiple nested, collapsible levels
14
- * Applies to [role=menu] and [role=tree]
15
- */
16
- // @ts-ignore - mixin implementation
17
- const MultiLevelListMixinImplementation = superclass =>
18
- // @ts-ignore - mixin class extension
19
- class extends InteractiveListMixin(superclass) {
20
- render() {
21
- return html`
22
- <slot name="invoker"></slot>
23
- <slot name="list"></slot>
24
- <slot id="list-items-outlet"></slot>
25
- `;
26
- }
27
-
28
- static get properties() {
29
- return {
30
- invokerNode: Object,
31
- behaveAsAccordion: { type: Boolean, attribute: 'behave-as-accordion' },
32
- level: { type: Number, reflect: true },
33
- };
34
- }
35
-
36
- /**
37
- * @configure DisclosureMixin
38
- */
39
- get _invokerNode() {
40
- // @ts-ignore - accessing static method and super property
41
- return this.constructor._getFocusableInvokerEl(this.invokerNode) || super._invokerNode;
42
- }
43
-
44
- /**
45
- * @configure DisclosureMixin
46
- * This will be compatible with DisclosureMixin and OverlayMixin. It contains the invoked
47
- * InteractiveList widget (like menu|tree).
48
- */
49
- get _contentNode() {
50
- return this._listNode;
51
- }
52
-
53
- constructor() {
54
- super();
55
-
56
- /**
57
- * When an invokerNode is supplied (usually by a parent level menu), it will take precedence
58
- * over [slot=invoker] and previousElementSibling with [data-invoker] attribute
59
- * @type {HTMLElement}
60
- */
61
- // @ts-ignore - can be undefined initially
62
- this.invokerNode = undefined;
63
- /**
64
- * @configure DisclosureMixin
65
- */
66
- this.handleFocus = true;
67
- /**
68
- * The parent list if level > 1
69
- * @type {InteractiveList}
70
- */
71
- // @ts-ignore - can be undefined initially
72
- this.parentList = undefined;
73
- /**
74
- * When true, will have a maximum of one submenu open at a time
75
- */
76
- this.behaveAsAccordion = false;
77
- /**
78
- * The level of nested menus. Will be reflected as attribute for styling purposes
79
- */
80
- this.level = 1;
81
- /**
82
- * @configure InteractiveListMixin
83
- */
84
- this.noPreselect = true;
85
- /**
86
- * @configure InteractiveListMixin
87
- */
88
- this._activeMode = 'roving-tabindex';
89
- /**
90
- * @type {Map<HTMLElement|LionItem,InteractiveList>}
91
- */
92
- this._subListMap = new Map();
93
- }
94
-
95
- // /**
96
- // * @param {import('lit-element').PropertyValues } changedProperties
97
- // */
98
- // updated(changedProperties) {
99
- // super.updated(changedProperties);
100
-
101
- // if (changedProperties.has('invokerNode')) {
102
- // // TODO: update openableCtrl invokerNode once we make this a ctrl as well
103
- // }
104
- // }
105
-
106
- /**
107
- * Gets the child InteractiveList, based on item
108
- * @param {LionItem|HTMLElement} item can be sibling of or parent of InteractiveList
109
- */
110
- static _getSubInteractiveList(item) {
111
- /**
112
- * Note that, according to W3C spec, the sub level element with [role=menu|menubar|tree]
113
- * needs to be a sibling of the invoker element with
114
- * [role=menuitem|menuitemchecbox|menuitemradio|treeitem] (and not the parent)
115
- *
116
- * In the example below <lion-menu> is considered as item
117
- * @example
118
- * <lion-menuitem>
119
- * <button slot="invoker"></button>
120
- * <lion-menu> ... </lion-menu>
121
- * </lion-menuitem>
122
- */
123
- // @ts-ignore - isInteractiveList property check
124
- const siblingOfInvoker = item.nextElementSibling?.isInteractiveList;
125
- if (siblingOfInvoker) {
126
- return item.nextElementSibling;
127
- }
128
- /**
129
- * In the example below div[role=listitem] | [data-item] is considered as item
130
- * @example
131
- * <div role="listitem" data-item>
132
- * <button slot="invoker"></button>
133
- * <lion-menu> ... </lion-menu>
134
- * </div>
135
- */
136
- const childOfInvoker =
137
- item.getAttribute?.('role') === 'listitem' || item.hasAttribute?.('data-item');
138
- if (childOfInvoker) {
139
- // @ts-ignore - isInteractiveList check
140
- return Array.from(item.children).find(child => child.isInteractiveList);
141
- }
142
- return undefined;
143
- }
144
-
145
- /**
146
- * @param {*} newItems
147
- */
148
- _initListItems(newItems) {
149
- super._initListItems(newItems);
150
-
151
- const ctor = this.constructor;
152
- // @ts-ignore - forEach parameter types
153
- newItems.forEach(item => {
154
- // @ts-ignore - static method access
155
- const subList = ctor._getSubInteractiveList(item);
156
- if (subList) {
157
- this._subListMap.set(item, subList);
158
- subList.level = this.level + 1;
159
- subList.parentList = this;
160
- subList.invokerNode = item;
161
- // @ts-ignore - invokerInteraction property
162
- subList.invokerInteraction = this.invokerInteraction;
163
- subList._activeMode = this._activeMode;
164
- }
165
- });
166
- }
167
-
168
- /**
169
- * @enhance DisclosureMixin
170
- * @param {Event} [ev]
171
- */
172
- toggle(ev) {
173
- // @ts-ignore - target property
174
- if (ev && this._listNode.contains(ev.target)) {
175
- // prevent nested menus (inside invokers) from triggering invoker
176
- return;
177
- }
178
- // @ts-ignore - super.toggle method
179
- super.toggle();
180
- }
181
-
182
- /**
183
- * @enhance InteractiveListMixin
184
- * @param {*} ev
185
- */
186
- _onListKeyDown(ev) {
187
- const targetFromsubList = Array.from(this._subListMap).find(
188
- // @ts-ignore - contains method on InteractiveListHost
189
- ([, s]) => s === ev.target || s.contains(ev.target),
190
- );
191
-
192
- if (targetFromsubList) {
193
- return;
194
- }
195
-
196
- super._onListKeyDown(ev);
197
-
198
- const subListOfActiveItem = this._subListMap.get(this.activeItem);
199
- const parentListOfActiveItem = this.parentList;
200
- const { key } = ev;
201
-
202
- if (key === 'Escape' && parentListOfActiveItem) {
203
- // We need to stop here, or else we affect parent menu (handled by OverlayController)
204
- ev.stopPropagation();
205
- }
206
-
207
- switch (key) {
208
- case 'Enter':
209
- case ' ':
210
- // make it work like a button
211
- this.activeItem?.click();
212
- break;
213
- case 'ArrowDown':
214
- if (
215
- this.orientation === 'horizontal' &&
216
- subListOfActiveItem &&
217
- this._activeMode !== 'tabbable-disclosure'
218
- ) {
219
- this.activeItem.click();
220
- }
221
- break;
222
- case 'ArrowRight':
223
- if (this.orientation === 'vertical' && subListOfActiveItem) {
224
- this.activeItem.click();
225
- }
226
- break;
227
- case 'ArrowUp':
228
- if (this.orientation === 'horizontal' && parentListOfActiveItem) {
229
- // @ts-ignore - close method
230
- this.close();
231
- // @ts-ignore - _onOverlayShow method
232
- parentListOfActiveItem._onOverlayShow();
233
- }
234
- break;
235
- case 'ArrowLeft':
236
- if (this.orientation === 'vertical' && parentListOfActiveItem) {
237
- // @ts-ignore - close method
238
- this.close();
239
- // @ts-ignore - _onOverlayShow method
240
- parentListOfActiveItem._onOverlayShow();
241
- }
242
- break;
243
- /* no default */
244
- }
245
- }
246
-
247
- // /**
248
- // * @enhance DisclosureMixin
249
- // */
250
- // _setupDisclosure() {
251
- // if (!this._invokerNode) return;
252
-
253
- // super._setupDisclosure();
254
- // }
255
-
256
- // /**
257
- // * @enhance DisclosureMixin
258
- // */
259
- // _teardownDisclosure() {
260
- // if (!this._invokerNode) return;
261
-
262
- // super._teardownDisclosure();
263
- // }
264
-
265
- // /**
266
- // * @enhance DisclosureMixin
267
- // */
268
- // async _onOpenedChanged() {
269
- // if (!this._invokerNode) return;
270
-
271
- // await super._onOpenedChanged();
272
- // }
273
- };
274
- export const MultiLevelListMixin = dedupeMixin(MultiLevelListMixinImplementation);