@lion/ui 0.22.0 → 0.23.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 (218) hide show
  1. package/README.md +35 -0
  2. package/components/combobox/src/LionCombobox.js +10 -2
  3. package/components/combobox/test/lion-combobox.test.js +31 -0
  4. package/components/form-core/src/choice-group/ChoiceGroupMixin.js +7 -0
  5. package/components/form-core/types/choice-group/ChoiceGroupMixinTypes.ts +5 -0
  6. package/components/input-amount/src/LionInputAmount.js +17 -6
  7. package/components/input-amount/src/formatters.js +5 -3
  8. package/components/input-amount/test/formatters.test.js +88 -74
  9. package/components/input-amount/test/lion-input-amount.test.js +51 -36
  10. package/components/input-tel/test/validators.test.js +9 -0
  11. package/components/listbox/src/ListboxMixin.js +19 -3
  12. package/components/listbox/types/ListboxMixinTypes.ts +7 -1
  13. package/components/menu/README.md +360 -0
  14. package/components/menu/src/InteractiveListMixin.js +867 -0
  15. package/components/menu/src/LionMenu.js +436 -0
  16. package/components/menu/src/MoreButtonMenuMixin.js +295 -0
  17. package/components/menu/src/MultiLevelListMixin.js +312 -0
  18. package/components/menu/src/utils/isInView.js +26 -0
  19. package/components/menu/src/utils/listItemInteractions.js +124 -0
  20. package/components/menu/test/InteractiveListMixin.test.js +3 -0
  21. package/components/menu/test/MoreButtonMenuMixin.test.js +4 -0
  22. package/components/menu/test/MultiLevelListMixin.test.js +3 -0
  23. package/components/menu/test/lion-menu-interactions.test.js +3 -0
  24. package/components/menu/test/lion-menu.test.js +14 -0
  25. package/components/menu/test-helpers/mimicKeyPress.js +9 -0
  26. package/components/menu/test-suites/InteractiveListMixin.suite.js +537 -0
  27. package/components/menu/test-suites/LionMenu.suite.js +114 -0
  28. package/components/menu/test-suites/LionMenuInteractions.suite.js +583 -0
  29. package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +372 -0
  30. package/components/menu/test-suites/MultiLevelListMixin.suite.js +309 -0
  31. package/components/menu/types/InteractiveListMixinTypes.ts +126 -0
  32. package/components/menu/types/MoreButtonMenuMixinTypes.ts +51 -0
  33. package/components/menu/types/MultiLevelListMixinTypes.ts +28 -0
  34. package/components/menu/types/OverlayWithListInvokerMixinTypes.ts +61 -0
  35. package/components/overlays/NEXT.md +49 -0
  36. package/components/overlays/src/OverlayController.js +304 -125
  37. package/components/overlays/src/OverlayMixin.js +81 -17
  38. package/components/overlays/src/utils/adopt-styles.js +1 -1
  39. package/components/overlays/src/utils/is-equal-config.js +15 -6
  40. package/components/overlays/test/OverlayController.test.js +223 -25
  41. package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
  42. package/components/overlays/types/ArrowMixinTypes.ts +1 -3
  43. package/components/overlays/types/OverlayConfig.ts +20 -5
  44. package/components/overlays/types/OverlayMixinTypes.ts +2 -0
  45. package/components/select-rich/src/LionSelectRich.js +12 -0
  46. package/components/select-rich/test/lion-select-rich-interaction.test.js +53 -0
  47. package/components/select-rich/test/lion-select-rich-upgrade.test.js +30 -0
  48. package/custom-elements.json +3120 -149
  49. package/dist-types/components/combobox/src/LionCombobox.d.ts +1 -1
  50. package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
  51. package/dist-types/components/dialog/src/LionDialog.d.ts +6 -2
  52. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  53. package/dist-types/components/form-core/src/choice-group/ChoiceGroupMixin.d.ts.map +1 -1
  54. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts +5 -0
  55. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts.map +1 -1
  56. package/dist-types/components/input-amount/src/LionInputAmount.d.ts +3 -1
  57. package/dist-types/components/input-amount/src/LionInputAmount.d.ts.map +1 -1
  58. package/dist-types/components/input-amount/src/formatters.d.ts +6 -4
  59. package/dist-types/components/input-amount/src/formatters.d.ts.map +1 -1
  60. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
  61. package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
  62. package/dist-types/components/listbox/types/ListboxMixinTypes.d.ts +7 -1
  63. package/dist-types/components/listbox/types/ListboxMixinTypes.d.ts.map +1 -1
  64. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +35 -0
  65. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -0
  66. package/dist-types/components/menu/src/LionMenu.d.ts +129 -0
  67. package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -0
  68. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +8 -0
  69. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +1 -0
  70. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +7 -0
  71. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -0
  72. package/dist-types/components/menu/src/utils/isInView.d.ts +9 -0
  73. package/dist-types/components/menu/src/utils/isInView.d.ts.map +1 -0
  74. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +48 -0
  75. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -0
  76. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts +2 -0
  77. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts.map +1 -0
  78. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts +2 -0
  79. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts.map +1 -0
  80. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts +2 -0
  81. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts.map +1 -0
  82. package/dist-types/components/menu/test/lion-menu-interactions.test.d.ts +2 -0
  83. package/dist-types/components/menu/test/lion-menu-interactions.test.d.ts.map +1 -0
  84. package/dist-types/components/menu/test/lion-menu.test.d.ts +2 -0
  85. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +1 -0
  86. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts +7 -0
  87. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts.map +1 -0
  88. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +11 -0
  89. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -0
  90. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts +9 -0
  91. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +1 -0
  92. package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts +5 -0
  93. package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts.map +1 -0
  94. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +11 -0
  95. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +1 -0
  96. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +11 -0
  97. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +1 -0
  98. package/dist-types/components/menu/types/InteractiveListMixinTypes.d.ts +72 -0
  99. package/dist-types/components/menu/types/InteractiveListMixinTypes.d.ts.map +1 -0
  100. package/dist-types/components/menu/types/MoreButtonMenuMixinTypes.d.ts +30 -0
  101. package/dist-types/components/menu/types/MoreButtonMenuMixinTypes.d.ts.map +1 -0
  102. package/dist-types/components/menu/types/MultiLevelListMixinTypes.d.ts +16 -0
  103. package/dist-types/components/menu/types/MultiLevelListMixinTypes.d.ts.map +1 -0
  104. package/dist-types/components/menu/types/OverlayWithListInvokerMixinTypes.d.ts +35 -0
  105. package/dist-types/components/menu/types/OverlayWithListInvokerMixinTypes.d.ts.map +1 -0
  106. package/dist-types/components/overlays/src/OverlayController.d.ts +22 -5
  107. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  108. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  109. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  110. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  111. package/dist-types/components/overlays/types/OverlayConfig.d.ts +12 -2
  112. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  113. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +1 -0
  114. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  115. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +13 -2
  116. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  117. package/dist-types/components/select-rich/test/lion-select-rich-interaction.test.d.ts.map +1 -1
  118. package/dist-types/components/select-rich/test/lion-select-rich-upgrade.test.d.ts +2 -0
  119. package/dist-types/components/select-rich/test/lion-select-rich-upgrade.test.d.ts.map +1 -0
  120. package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
  121. package/dist-types/exports/define/lion-item.d.ts +2 -0
  122. package/dist-types/exports/define/lion-item.d.ts.map +1 -0
  123. package/dist-types/exports/define/lion-menu.d.ts +2 -0
  124. package/dist-types/exports/define/lion-menu.d.ts.map +1 -0
  125. package/dist-types/exports/define/lion-menuitem.d.ts +2 -0
  126. package/dist-types/exports/define/lion-menuitem.d.ts.map +1 -0
  127. package/dist-types/exports/menu-test-suites.d.ts +4 -0
  128. package/dist-types/exports/menu-test-suites.d.ts.map +1 -0
  129. package/dist-types/exports/menu.d.ts +3 -0
  130. package/dist-types/exports/menu.d.ts.map +1 -0
  131. package/dist-types/exports/overlays.d.ts +6 -0
  132. package/dist-types/exports/overlays.d.ts.map +1 -1
  133. package/dist-types/tsconfig.tsbuildinfo +1 -1
  134. package/docs/components/checkbox-group/overview.md +2 -2
  135. package/docs/components/collapsible/overview.md +1 -1
  136. package/docs/components/combobox/api-table.md +53 -39
  137. package/docs/components/combobox/overview.md +1 -1
  138. package/docs/components/combobox/use-cases.md +1 -1
  139. package/docs/components/dialog/api-table.md +32 -6
  140. package/docs/components/dialog/overview.md +1 -1
  141. package/docs/components/fieldset/overview.md +5 -5
  142. package/docs/components/form/overview.md +3 -3
  143. package/docs/components/form/use-cases.md +2 -2
  144. package/docs/components/icon/use-cases.md +1 -1
  145. package/docs/components/input/overview.md +1 -1
  146. package/docs/components/input-amount/api-table.md +9 -7
  147. package/docs/components/input-amount/overview.md +3 -3
  148. package/docs/components/input-amount/use-cases.md +15 -4
  149. package/docs/components/input-amount-dropdown/api-table.md +2 -0
  150. package/docs/components/input-date/overview.md +3 -3
  151. package/docs/components/input-datepicker/api-table.md +63 -45
  152. package/docs/components/input-datepicker/overview.md +5 -5
  153. package/docs/components/input-email/overview.md +2 -2
  154. package/docs/components/input-file/overview.md +1 -1
  155. package/docs/components/input-iban/overview.md +2 -2
  156. package/docs/components/input-range/overview.md +2 -2
  157. package/docs/components/input-stepper/overview.md +1 -1
  158. package/docs/components/input-tel/overview.md +1 -1
  159. package/docs/components/input-tel/use-cases.md +6 -6
  160. package/docs/components/input-tel-dropdown/overview.md +1 -1
  161. package/docs/components/listbox/use-cases.md +1 -1
  162. package/docs/components/menu/api-table.md +44 -0
  163. package/docs/components/menu/applyMenuDemoStyles.js +173 -0
  164. package/docs/components/menu/extensions.md +262 -0
  165. package/docs/components/menu/index.md +13 -0
  166. package/docs/components/menu/migration.md +129 -0
  167. package/docs/components/menu/overview.md +448 -0
  168. package/docs/components/menu/src/DemoNavigationBar.js +441 -0
  169. package/docs/components/menu/src/DemoSpinButton.js +215 -0
  170. package/docs/components/menu/src/DemoToolbar.js +101 -0
  171. package/docs/components/menu/src/DemoTree.js +55 -0
  172. package/docs/components/menu/src/navigation-bar-types.js +41 -0
  173. package/docs/components/menu/use-cases.md +74 -0
  174. package/docs/components/radio-group/overview.md +3 -3
  175. package/docs/components/select/use-cases.md +1 -1
  176. package/docs/components/select-rich/api-table.md +51 -33
  177. package/docs/components/select-rich/use-cases.md +2 -2
  178. package/docs/components/tabs/examples.md +1 -1
  179. package/docs/components/tooltip/api-table.md +33 -7
  180. package/docs/fundamentals/index.md +4 -4
  181. package/docs/fundamentals/node-tools/providence-analytics/overview.md +1 -1
  182. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  183. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  184. package/docs/fundamentals/rationales/accessibility.md +1 -1
  185. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  186. package/docs/fundamentals/systems/core/overview.md +1 -1
  187. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  188. package/docs/fundamentals/systems/form/model-value.md +1 -1
  189. package/docs/fundamentals/systems/form/overview.md +28 -28
  190. package/docs/fundamentals/systems/form/validate.md +2 -2
  191. package/docs/fundamentals/systems/localize/overview.md +4 -4
  192. package/docs/fundamentals/systems/overlays/api-table.md +46 -43
  193. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  194. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  195. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  196. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  197. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  198. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  199. package/docs/guides/how-to/create-a-form.md +4 -4
  200. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  201. package/docs/guides/how-to/index.md +1 -1
  202. package/docs/guides/index.md +8 -8
  203. package/docs/guides/principles/index.md +5 -5
  204. package/docs/guides/principles/styling.md +1 -1
  205. package/exports/define/lion-item.js +3 -0
  206. package/exports/define/lion-menu.js +3 -0
  207. package/exports/define/lion-menuitem.js +3 -0
  208. package/exports/menu-test-suites.js +4 -0
  209. package/exports/menu.js +3 -0
  210. package/exports/overlays.js +6 -0
  211. package/menu-test-suites.js +4 -0
  212. package/menu.js +3 -0
  213. package/overlays.js +6 -0
  214. package/package.json +11 -4
  215. package/vendor/README.md +61 -0
  216. package/vendor/awesome-phonenumber-7.9.0-tlouisse.libphonenumber-9.0.41.tgz +0 -0
  217. package/vscode.html-custom-data.json +76 -8
  218. package/web-types.json +202 -17
@@ -0,0 +1,436 @@
1
+ /* eslint-disable max-classes-per-file */
2
+ /* eslint-disable import/no-extraneous-dependencies */
3
+ import { LitElement, html } from 'lit';
4
+ import { dedupeMixin } from '@open-wc/dedupe-mixin';
5
+
6
+ /**
7
+ * @typedef {import('../types/OverlayWithListInvokerMixinTypes.js').OverlayWithListInvokerMixin} OverlayWithListInvokerMixinType
8
+ * @typedef {import('../../overlays/types/OverlayConfig.js').OverlayConfig} OverlayConfig
9
+ */
10
+
11
+ import { OverlayMixin, withDropdownConfig } from '@lion/ui/overlays.js';
12
+ import { MultiLevelListMixin } from './MultiLevelListMixin.js';
13
+ import { InteractiveListMixin } from './InteractiveListMixin.js';
14
+ import { setChecked, toggleChecked } from './utils/listItemInteractions.js';
15
+
16
+ // /**
17
+ // * @param {Element} element
18
+ // */
19
+ // function getContentHeight(element) {
20
+ // return `${element.getBoundingClientRect().height}px`;
21
+ // }
22
+
23
+ // /**
24
+ // * Calculate total content height after collapsible opens
25
+ // * @param {HTMLElement} contentNode content node
26
+ // * @private
27
+ // */
28
+ // async function calculateHeight(contentNode) {
29
+ // contentNode.style.setProperty('max-height', '');
30
+ // await new Promise(resolve => requestAnimationFrame(() => resolve(undefined)));
31
+ // return getContentHeight(contentNode); // Expected height i.e. actual size once collapsed after animation
32
+ // }
33
+
34
+ // /**
35
+ // * @type {AnimateMixin}
36
+ // */
37
+ // const AnimateMixinImplementation = superclass =>
38
+ // class AnimateMixin extends superclass {
39
+ // constructor() {
40
+ // super();
41
+ // this.__handleAnimateComplete = this.__handleAnimateComplete.bind(this);
42
+ // }
43
+
44
+ // connectedCallback() {
45
+ // super.connectedCallback();
46
+ // this._contentNode.style.setProperty('transition', 'max-height 0.35s, opacity 0.35s');
47
+ // }
48
+
49
+ // /**
50
+ // * Trigger show animation and wait for transition to be finished.
51
+ // * @param {Object} options - element node and its options
52
+ // * @override
53
+ // */
54
+ // async _showAnimation(cfg) {
55
+ // super._showAnimation(cfg);
56
+
57
+ // const { contentNode } = cfg;
58
+ // const expectedHeight = await calculateHeight(contentNode);
59
+ // contentNode.style.setProperty('overflow', 'hidden');
60
+ // contentNode.style.setProperty('opacity', '1');
61
+ // contentNode.style.setProperty('max-height', '0');
62
+ // await new Promise(resolve => requestAnimationFrame(() => resolve(undefined)));
63
+ // contentNode.style.setProperty('max-height', expectedHeight);
64
+ // await this._animateComplete;
65
+ // ['opacity', 'padding', 'max-height', 'overflow'].map(prop =>
66
+ // contentNode.style.removeProperty(prop),
67
+ // );
68
+ // }
69
+
70
+ // /**
71
+ // * Trigger hide animation and wait for transition to be finished.
72
+ // * @param {Object} options - element node and its options
73
+ // * @override
74
+ // */
75
+ // async _hideAnimation(cfg) {
76
+ // super._hideAnimation(cfg);
77
+
78
+ // const { contentNode } = cfg;
79
+ // if (getContentHeight(contentNode) === '0px') {
80
+ // return;
81
+ // }
82
+ // const expectedHeight = await calculateHeight(contentNode);
83
+
84
+ // contentNode.style.setProperty('overflow', 'hidden');
85
+ // contentNode.style.setProperty('max-height', expectedHeight);
86
+ // await new Promise(resolve => requestAnimationFrame(() => resolve()));
87
+ // ['opacity', 'padding', 'max-height'].map(prop => contentNode.style.setProperty(prop, 0));
88
+
89
+ // await this._animateComplete;
90
+ // }
91
+ // };
92
+ // export const AnimateMixin = dedupeMixin(AnimateMixinImplementation);
93
+
94
+ /**
95
+ * The interactive (multi level) list behavior of a menu.
96
+ *
97
+ * Not exported on its own: consumers use `LionMenu`, which adds the
98
+ * disclosure/overlay behavior on top of this.
99
+ *
100
+ * Api explanation:
101
+ * - No [slot="invoker"], because adding it inside the lion-menu would:
102
+ * - make api more verbose, less aligned with common html examples (examples from wai-aria etc.)
103
+ * - break Popper positioning (you would need to specify parent menuitem as reference node)
104
+ * - put click surface inside menuitem padding (you would need to correct with negative margin :( ...)
105
+ * - No [slot="content"], because for a "right click menu" it would be obsolete
106
+ *
107
+ * @example menu button (VsCode action menu right top of screen)
108
+ * <lion-menu>
109
+ * <button slot="invoker" title="More actions">...</button>
110
+ * <div role="menuitem">Show opened editors</div>
111
+ * <div role="separator"></div>
112
+ * <div role="menuitem">Close All</div>
113
+ * </lion-menu>
114
+ *
115
+ * @example as menubar (VsCode main menu)
116
+ * <lion-menu bar>
117
+ * <div>
118
+ * <div role="menuitem">File</div>
119
+ * <lion-menu>
120
+ * <div role="menuitem">New File</div>
121
+ * <div role="separator"></div>
122
+ * <div>
123
+ * <div role="menuitem">Open Recent</div>
124
+ * <lion-menu>
125
+ * More...
126
+ * </lion-menu>
127
+ * </div>
128
+ * </lion-menu>
129
+ * </div>
130
+ * <div>
131
+ * <div role="menuitem">View</div>
132
+ * <lion-menu>
133
+ * <div role="menuitemcheckbox">Show Minimap</div>
134
+ * </lion-menu>
135
+ * </div>
136
+ * </lion-menu>
137
+ *
138
+ *
139
+ * @example as context menu (VsCode right click menu)
140
+ * <lion-menu>
141
+ * <div role="menuitem">Go to Definition</div>
142
+ * <div role="menuitem">Go to Type Definition</div>
143
+ * <div>
144
+ * <div role="menuitem">Peek</div>
145
+ * <lion-menu>
146
+ * <div role="menuitem">Peek Call Hierarchy</div>
147
+ * <div role="separator"></div>
148
+ * <div role="menuitem">Peek Definition</div>
149
+ * </lion-menu>
150
+ * </div>
151
+ * <div role="separator"></div>
152
+ * <div role="menuitem">Find all References</div>
153
+ * </lion-menu>
154
+ */
155
+ // @ts-ignore - _listRole property type compatibility
156
+ class LionMenuCore extends MultiLevelListMixin(LitElement) {
157
+ /** @returns {import('lit').PropertyDeclarations} */
158
+ static get properties() {
159
+ return {
160
+ /**
161
+ * Enable bar to use [role="menubar"] and horizontal navigation
162
+ */
163
+ bar: { type: Boolean },
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Allows groups within one level. In case we deal with menuitemcheckbox,
169
+ * we treat it as multiple choice group
170
+ * @override InteractiveListMixin
171
+ * @param {number} index
172
+ */
173
+ setCheckedIndex(index) {
174
+ const item = this.listItems[index];
175
+ if (!item) return;
176
+
177
+ // @ts-ignore - InteractiveListItemRole type
178
+ const role = /** @type {InteractiveListItemRole} */ (item.getAttribute('role'));
179
+ let listItemsWithinGroup = this.listItems;
180
+ let { multiple } = this;
181
+ if (role === 'menuitemradio' || role === 'menuitemcheckbox') {
182
+ /**
183
+ * If index = 3 (menuitemradio 'Red'), closest group will be div[role=group]
184
+ * @example
185
+ * <interactive-list role="menu">
186
+ * <div role="menuitemcheckbox" aria-checked="true">Bold</div>
187
+ * <div role="menuitemcheckbox" aria-checked="true">Italic</div>
188
+ * <div role="separator"></div>
189
+ * <div role="group" aria-label="Text Color">
190
+ * <div role="menuitemradio" aria-checked="false">Blue</div>
191
+ * <div role="menuitemradio" aria-checked="true">Red</div>
192
+ * <div role="menuitemradio" aria-checked="false">Green</div>
193
+ * </div>
194
+ * </interactive-list>
195
+ */
196
+ const closestGroup = item.closest('[role="group"]');
197
+ const group = closestGroup && this.contains(closestGroup) ? closestGroup : this;
198
+ listItemsWithinGroup = this.listItems.filter(listItem => group.contains(listItem));
199
+ multiple = role === 'menuitemcheckbox';
200
+ }
201
+
202
+ if (!multiple) {
203
+ // Uncheck all within group
204
+ listItemsWithinGroup.forEach(listItem => {
205
+ setChecked(listItem, true);
206
+ });
207
+ setChecked(this.listItems[index]);
208
+ } else {
209
+ toggleChecked(this.listItems[index]);
210
+ }
211
+ }
212
+
213
+ constructor() {
214
+ super();
215
+
216
+ this.bar = false;
217
+ /** @configure MultiLevelListMixin */
218
+ this.behaveAsAccordion = true;
219
+ /** @configure InteractiveListMixin */
220
+ this._listRole = 'menu';
221
+ /** @configure InteractiveListMixin */
222
+ this._activateOnTypedChars = true;
223
+ /** @configure DisclosureMixin */
224
+ this.invokerInteraction = 'click';
225
+ }
226
+
227
+ /**
228
+ * @param {import('lit-element').PropertyValues } changedProperties
229
+ */
230
+ firstUpdated(changedProperties) {
231
+ super.firstUpdated(changedProperties);
232
+
233
+ if (this._activeMode === 'tabbable-disclosure') {
234
+ this._listRole = 'list';
235
+ }
236
+
237
+ this._listNode.setAttribute('role', this._listRole);
238
+
239
+ // Allow generic attr for functional styling
240
+ this.dataset.menu = '';
241
+ }
242
+
243
+ /**
244
+ * @param {import('lit-element').PropertyValues } changedProperties
245
+ */
246
+ updated(changedProperties) {
247
+ super.updated(changedProperties);
248
+
249
+ if (changedProperties.has('bar')) {
250
+ if (this.bar) {
251
+ this.axis = 'inline';
252
+ if (this._listRole === 'menu') {
253
+ this._listRole = 'menubar';
254
+ }
255
+ } else {
256
+ this.axis = 'block';
257
+ if (this._listRole === 'menubar') {
258
+ this._listRole = 'menu';
259
+ }
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Handles integration of InteractiveListMixin and OverlayMixin
267
+ * Will be used by:
268
+ * - LionMenu
269
+ * - LionCombobox
270
+ * - LionSelectRich
271
+ *
272
+ * @param {import('@open-wc/dedupe-mixin').Constructor<LionMenuCore>} superclass
273
+ */
274
+ /**
275
+ * @type {OverlayWithListInvokerMixinType}
276
+ * @param {import('@open-wc/dedupe-mixin').Constructor<import('lit').LitElement>} superclass
277
+ */
278
+ // prettier-ignore
279
+ const OverlayWithListInvokerMixinImplementation = /** @type {OverlayWithListInvokerMixinType} */ (superclass =>
280
+ class OverlayWithListInvokerMixin extends OverlayMixin(InteractiveListMixin(superclass)) {
281
+ _onOverlayShow = () => {
282
+ if (this.checkedIndex != null) {
283
+ // @ts-ignore - activeIndex can be number or array
284
+ this.activeIndex = this.checkedIndex;
285
+ }
286
+ };
287
+
288
+ /**
289
+ * @enhance OverlayMixin
290
+ */
291
+ _setupOverlayCtrl() {
292
+ super._setupOverlayCtrl();
293
+
294
+ if (!this._overlayCtrl) return;
295
+
296
+ this._overlayCtrl.addEventListener('show', this._onOverlayShow);
297
+ }
298
+
299
+ /**
300
+ * @enhance OverlayMixin
301
+ */
302
+ _teardownOverlayCtrl() {
303
+ super._teardownOverlayCtrl();
304
+
305
+ if (!this._overlayCtrl) return;
306
+
307
+ this._overlayCtrl.removeEventListener('show', this._onOverlayShow);
308
+ }
309
+
310
+ /**
311
+ * make sure OverlayMixin gets the contentNode defined by DisclosureMixin
312
+ */
313
+ get _overlayContentNode() {
314
+ // @ts-ignore - _contentNode property
315
+ return this._contentNode;
316
+ }
317
+
318
+ /**
319
+ * make sure OverlayMixin gets the invokerNode defined by DisclosureMixin
320
+ */
321
+ get _overlayInvokerNode() {
322
+ return /** @type {HTMLElement} */ (this._invokerNode);
323
+ }
324
+ });
325
+ export const OverlayWithListInvokerMixin = dedupeMixin(OverlayWithListInvokerMixinImplementation);
326
+
327
+ /**
328
+ * LionMenu is a list of choices. Whether it opens as an overlay or as a regular
329
+ * collapsible (disclosure) is configurable via `openable-mode`.
330
+ *
331
+ * N.B. the actual switching will be delegated to the disclosure system (see the
332
+ * visibility-toggle controller); for now `disclosure` is the default.
333
+ */
334
+ export class LionMenu extends OverlayWithListInvokerMixin(LionMenuCore) {
335
+ /** @returns {import('lit').PropertyDeclarations} */
336
+ static get properties() {
337
+ return {
338
+ openableMode: { type: String, attribute: 'openable-mode' },
339
+ };
340
+ }
341
+
342
+ constructor() {
343
+ super();
344
+
345
+ // By default, we go for disclosure behavior
346
+ // a TODO: in the future, bring disclosure behavior to a controller (and therefore directive).
347
+ // Take inspiration from VisibilityToggleCtrl of portal elements
348
+ /**
349
+ * Terminology aligned with https://open-ui.org/components/openable.explainer/
350
+ * @type {'disclosure'|'overlay'}
351
+ */
352
+ this.openableMode = 'disclosure';
353
+
354
+ this._shouldSetupOverlay = false;
355
+ }
356
+
357
+ /**
358
+ * @param {import('lit').PropertyValues} changedProperties
359
+ */
360
+ updated(changedProperties) {
361
+ super.updated(changedProperties);
362
+
363
+ if (changedProperties.has('openableMode')) {
364
+ if (this.openableMode === 'overlay') {
365
+ this._shouldSetupOverlay = true;
366
+ this._setupOverlayCtrl();
367
+ } else {
368
+ this._teardownOverlayCtrl();
369
+ }
370
+ }
371
+ }
372
+
373
+ // TODO: this was created 5 years ago, do we still need id="overlay-content-node-wrapper" after the "dialog refactor"?
374
+ render() {
375
+ return html`
376
+ <slot name="invoker"></slot>
377
+ <div id="overlay-content-node-wrapper">
378
+ <slot name="list"></slot>
379
+ </div>
380
+ <slot id="list-items-outlet"></slot>
381
+ `;
382
+ }
383
+
384
+ /**
385
+ * @override
386
+ * @returns {OverlayConfig}
387
+ */
388
+ _defineOverlayConfig() {
389
+ // @ts-ignore - parentList property
390
+ const { parentList } = this;
391
+ /** @type {import('@popperjs/core').Placement} */
392
+ let placement = 'bottom-start';
393
+ if (parentList?.axis !== 'inline') {
394
+ placement = 'right-start';
395
+ }
396
+
397
+ const dropdownCfg = withDropdownConfig();
398
+
399
+ return {
400
+ ...dropdownCfg,
401
+ hidesOnEsc: true,
402
+ popperConfig: {
403
+ ...dropdownCfg.popperConfig,
404
+ placement,
405
+ strategy: 'absolute',
406
+ modifiers: [
407
+ {
408
+ name: 'offset',
409
+ enabled: true,
410
+ options: {
411
+ offset: [0, 0],
412
+ },
413
+ },
414
+ ],
415
+ },
416
+ };
417
+ }
418
+
419
+ /**
420
+ * @enhance InteractiveListMixin
421
+ * @param {*} ev
422
+ */
423
+ _onListKeyUp(ev) {
424
+ super._onListKeyUp(ev);
425
+
426
+ const { key } = ev;
427
+
428
+ switch (key) {
429
+ case 'Escape':
430
+ // We need to stop here, or else we affect parent menu (handled by OverlayController)
431
+ ev.stopPropagation();
432
+ break;
433
+ /* no default */
434
+ }
435
+ }
436
+ }