@lion/ui 0.16.0 → 0.17.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 (248) hide show
  1. package/collapsible.js +1 -0
  2. package/components/button/src/LionButton.js +5 -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/types/DisclosureMixinTypes.ts +48 -0
  7. package/components/combobox/src/utils/makeMatchingTextBold.js +3 -1
  8. package/components/combobox/test/lion-combobox.test.js +105 -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-datepicker/src/LionInputDatepicker.js +6 -2
  16. package/components/input-datepicker/src/localizeNamespaceLoader.js +1 -0
  17. package/components/input-datepicker/test/lion-input-datepicker.test.js +17 -2
  18. package/components/input-datepicker/translations/bg.js +1 -1
  19. package/components/input-datepicker/translations/cs.js +1 -1
  20. package/components/input-datepicker/translations/de.js +1 -1
  21. package/components/input-datepicker/translations/en.js +1 -1
  22. package/components/input-datepicker/translations/es.js +1 -1
  23. package/components/input-datepicker/translations/fr.js +1 -1
  24. package/components/input-datepicker/translations/hu.js +1 -1
  25. package/components/input-datepicker/translations/it.js +1 -1
  26. package/components/input-datepicker/translations/nl.js +1 -1
  27. package/components/input-datepicker/translations/pl.js +1 -1
  28. package/components/input-datepicker/translations/ro.js +1 -1
  29. package/components/input-datepicker/translations/ru.js +1 -1
  30. package/components/input-datepicker/translations/sk.js +1 -1
  31. package/components/input-datepicker/translations/tr.js +1 -1
  32. package/components/input-datepicker/translations/uk.js +1 -1
  33. package/components/input-datepicker/translations/zh.js +1 -1
  34. package/components/input-stepper/src/LionInputStepper.js +15 -7
  35. package/components/input-stepper/test-suites/lion-input-stepper.suite.js +28 -4
  36. package/components/localize/test/date/formatDate.test.js +1 -0
  37. package/components/menu/CHANGELOG.md +37 -0
  38. package/components/menu/README.md +335 -0
  39. package/components/menu/index.js +2 -0
  40. package/components/menu/lion-menu-overlay.js +3 -0
  41. package/components/menu/lion-menu.js +3 -0
  42. package/components/menu/lion-spinbutton.js +3 -0
  43. package/components/menu/lion-toolbar.js +3 -0
  44. package/components/menu/lion-tree.js +3 -0
  45. package/components/menu/package.json +46 -0
  46. package/components/menu/requirements.temp.md +12 -0
  47. package/components/menu/src/InteractiveListMixin.js +796 -0
  48. package/components/menu/src/LionMenu.js +250 -0
  49. package/components/menu/src/LionMenuHybrid.js +46 -0
  50. package/components/menu/src/LionMenuOverlay.js +155 -0
  51. package/components/menu/src/LionSpinbutton.js +213 -0
  52. package/components/menu/src/LionToolbar.js +94 -0
  53. package/components/menu/src/LionTree.js +52 -0
  54. package/components/menu/src/MultiLevelListMixin.js +275 -0
  55. package/components/menu/src/utils/isInView.js +26 -0
  56. package/components/menu/src/utils/listItemInteractions.js +104 -0
  57. package/components/menu/src/utils/uuid.js +3 -0
  58. package/components/menu/test/lion-menu.test.js +3 -0
  59. package/components/menu/test-suites/InteractiveListMixin.suite.js +142 -0
  60. package/components/menu/types/InteractiveListMixinTypes.d.ts +82 -0
  61. package/components/navigation-bar/README.md +1 -0
  62. package/components/navigation-bar/src/LionNavigationBar.js +449 -0
  63. package/components/navigation-bar/src/types.js +41 -0
  64. package/components/overlays/NEXT.md +49 -0
  65. package/components/overlays/src/OverlayController.js +165 -115
  66. package/components/overlays/src/OverlayMixin.js +75 -12
  67. package/components/overlays/src/OverlaysManager.js +102 -4
  68. package/components/overlays/src/overlayShadowDomStyle.js +2 -2
  69. package/components/overlays/src/utils/adopt-styles.js +2 -1
  70. package/components/overlays/src/utils/get-focusable-elements.js +4 -0
  71. package/components/overlays/src/utils/is-equal-config.js +4 -1
  72. package/components/overlays/test/OverlayController.test.js +117 -6
  73. package/components/overlays/test/OverlaysManager.test.js +1 -1
  74. package/components/overlays/types/OverlayConfig.ts +19 -4
  75. package/components/select-rich/test/lion-select-rich.test.js +3 -0
  76. package/custom-elements.json +12958 -2510
  77. package/dist-types/components/button/src/LionButton.d.ts +1 -0
  78. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  79. package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
  80. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  81. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +3 -0
  82. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +1 -0
  83. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +24 -0
  84. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +1 -0
  85. package/dist-types/components/combobox/src/utils/makeMatchingTextBold.d.ts.map +1 -1
  86. package/dist-types/components/dialog/src/LionDialog.d.ts +2 -1
  87. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  88. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  89. package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
  90. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  91. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  92. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
  93. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
  94. package/dist-types/components/input-stepper/src/LionInputStepper.d.ts +4 -2
  95. package/dist-types/components/input-stepper/src/LionInputStepper.d.ts.map +1 -1
  96. package/dist-types/components/input-stepper/test-suites/lion-input-stepper.suite.d.ts.map +1 -1
  97. package/dist-types/components/menu/index.d.ts +3 -0
  98. package/dist-types/components/menu/index.d.ts.map +1 -0
  99. package/dist-types/components/menu/lion-menu-overlay.d.ts +2 -0
  100. package/dist-types/components/menu/lion-menu-overlay.d.ts.map +1 -0
  101. package/dist-types/components/menu/lion-menu.d.ts +2 -0
  102. package/dist-types/components/menu/lion-menu.d.ts.map +1 -0
  103. package/dist-types/components/menu/lion-spinbutton.d.ts +2 -0
  104. package/dist-types/components/menu/lion-spinbutton.d.ts.map +1 -0
  105. package/dist-types/components/menu/lion-toolbar.d.ts +2 -0
  106. package/dist-types/components/menu/lion-toolbar.d.ts.map +1 -0
  107. package/dist-types/components/menu/lion-tree.d.ts +2 -0
  108. package/dist-types/components/menu/lion-tree.d.ts.map +1 -0
  109. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +611 -0
  110. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -0
  111. package/dist-types/components/menu/src/LionMenu.d.ts +563 -0
  112. package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -0
  113. package/dist-types/components/menu/src/LionMenuHybrid.d.ts +19 -0
  114. package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +1 -0
  115. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +1006 -0
  116. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +1 -0
  117. package/dist-types/components/menu/src/LionSpinbutton.d.ts +58 -0
  118. package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +1 -0
  119. package/dist-types/components/menu/src/LionToolbar.d.ts +8 -0
  120. package/dist-types/components/menu/src/LionToolbar.d.ts.map +1 -0
  121. package/dist-types/components/menu/src/LionTree.d.ts +445 -0
  122. package/dist-types/components/menu/src/LionTree.d.ts.map +1 -0
  123. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +493 -0
  124. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -0
  125. package/dist-types/components/menu/src/utils/isInView.d.ts +9 -0
  126. package/dist-types/components/menu/src/utils/isInView.d.ts.map +1 -0
  127. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +42 -0
  128. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -0
  129. package/dist-types/components/menu/src/utils/uuid.d.ts +2 -0
  130. package/dist-types/components/menu/src/utils/uuid.d.ts.map +1 -0
  131. package/dist-types/components/menu/test/lion-menu.test.d.ts +2 -0
  132. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +1 -0
  133. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +13 -0
  134. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -0
  135. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +226 -0
  136. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +1 -0
  137. package/dist-types/components/navigation-bar/src/types.d.ts +85 -0
  138. package/dist-types/components/navigation-bar/src/types.d.ts.map +1 -0
  139. package/dist-types/components/overlays/src/OverlayController.d.ts +7 -13
  140. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  141. package/dist-types/components/overlays/src/OverlayMixin.d.ts +3 -0
  142. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  143. package/dist-types/components/overlays/src/OverlaysManager.d.ts +33 -2
  144. package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
  145. package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
  146. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  147. package/dist-types/components/overlays/types/OverlayConfig.d.ts +6 -2
  148. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  149. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +11 -2
  150. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  151. package/dist-types/exports/define/lion-item.d.ts +2 -0
  152. package/dist-types/exports/define/lion-item.d.ts.map +1 -0
  153. package/dist-types/exports/define/lion-menu-overlay.d.ts +2 -0
  154. package/dist-types/exports/define/lion-menu-overlay.d.ts.map +1 -0
  155. package/dist-types/exports/define/lion-menu.d.ts +2 -0
  156. package/dist-types/exports/define/lion-menu.d.ts.map +1 -0
  157. package/dist-types/exports/define/lion-navigation-bar.d.ts +2 -0
  158. package/dist-types/exports/define/lion-navigation-bar.d.ts.map +1 -0
  159. package/dist-types/exports/define/lion-toolbar.d.ts +2 -0
  160. package/dist-types/exports/define/lion-toolbar.d.ts.map +1 -0
  161. package/dist-types/exports/define/lion-tree.d.ts +2 -0
  162. package/dist-types/exports/define/lion-tree.d.ts.map +1 -0
  163. package/dist-types/exports/menu.d.ts +7 -0
  164. package/dist-types/exports/menu.d.ts.map +1 -0
  165. package/dist-types/exports/navigation-bar.d.ts +2 -0
  166. package/dist-types/exports/navigation-bar.d.ts.map +1 -0
  167. package/dist-types/exports/overlays.d.ts +2 -0
  168. package/dist-types/exports/types/overlays.d.ts +1 -0
  169. package/dist-types/exports/types/overlays.d.ts.map +1 -1
  170. package/dist-types/tsconfig.tsbuildinfo +1 -1
  171. package/docs/components/checkbox-group/overview.md +2 -2
  172. package/docs/components/collapsible/overview.md +1 -1
  173. package/docs/components/combobox/overview.md +1 -1
  174. package/docs/components/combobox/use-cases.md +1 -1
  175. package/docs/components/dialog/overview.md +1 -1
  176. package/docs/components/fieldset/overview.md +5 -5
  177. package/docs/components/form/overview.md +3 -3
  178. package/docs/components/form/use-cases.md +2 -2
  179. package/docs/components/icon/use-cases.md +1 -1
  180. package/docs/components/index.md +1 -1
  181. package/docs/components/input/overview.md +1 -1
  182. package/docs/components/input-amount/overview.md +3 -3
  183. package/docs/components/input-date/overview.md +3 -3
  184. package/docs/components/input-datepicker/overview.md +5 -5
  185. package/docs/components/input-datepicker/use-cases.md +16 -1
  186. package/docs/components/input-email/overview.md +2 -2
  187. package/docs/components/input-file/overview.md +1 -1
  188. package/docs/components/input-iban/overview.md +2 -2
  189. package/docs/components/input-range/api-table.md +1 -1
  190. package/docs/components/input-range/overview.md +2 -2
  191. package/docs/components/input-stepper/api-table.md +2 -2
  192. package/docs/components/input-stepper/overview.md +1 -1
  193. package/docs/components/input-stepper/use-cases.md +26 -0
  194. package/docs/components/input-tel/overview.md +1 -1
  195. package/docs/components/input-tel/use-cases.md +6 -6
  196. package/docs/components/input-tel-dropdown/overview.md +1 -1
  197. package/docs/components/listbox/use-cases.md +1 -1
  198. package/docs/components/menu/api-table.md +450 -0
  199. package/docs/components/menu/applyMenuDemoStyles.js +173 -0
  200. package/docs/components/menu/extensions.md +216 -0
  201. package/docs/components/menu/index.md +13 -0
  202. package/docs/components/menu/overview.md +422 -0
  203. package/docs/components/radio-group/overview.md +3 -3
  204. package/docs/components/select/use-cases.md +1 -1
  205. package/docs/components/select-rich/api-table.md +1 -1
  206. package/docs/components/select-rich/use-cases.md +2 -2
  207. package/docs/components/tabs/examples.md +1 -1
  208. package/docs/fundamentals/index.md +4 -4
  209. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  210. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  211. package/docs/fundamentals/rationales/accessibility.md +1 -1
  212. package/docs/fundamentals/systems/core/SlotMixin.md +18 -18
  213. package/docs/fundamentals/systems/core/overview.md +1 -1
  214. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  215. package/docs/fundamentals/systems/form/interaction-states.md +0 -1
  216. package/docs/fundamentals/systems/form/model-value.md +1 -1
  217. package/docs/fundamentals/systems/form/overview.md +28 -28
  218. package/docs/fundamentals/systems/form/validate.md +2 -2
  219. package/docs/fundamentals/systems/localize/overview.md +4 -4
  220. package/docs/fundamentals/systems/localize/text.md +1 -1
  221. package/docs/fundamentals/systems/overlays/api-table.md +98 -50
  222. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  223. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  224. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  225. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  226. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  227. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  228. package/docs/guides/how-to/create-a-form.md +4 -4
  229. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  230. package/docs/guides/how-to/index.md +14 -0
  231. package/docs/guides/index.md +8 -8
  232. package/docs/guides/principles/index.md +5 -5
  233. package/docs/guides/principles/styling.md +1 -2
  234. package/exports/collapsible.js +1 -0
  235. package/exports/define/lion-item.js +3 -0
  236. package/exports/define/lion-menu-overlay.js +3 -0
  237. package/exports/define/lion-menu.js +3 -0
  238. package/exports/define/lion-navigation-bar.js +3 -0
  239. package/exports/define/lion-toolbar.js +3 -0
  240. package/exports/define/lion-tree.js +3 -0
  241. package/exports/menu.js +6 -0
  242. package/exports/navigation-bar.js +1 -0
  243. package/exports/overlays.js +2 -0
  244. package/exports/types/overlays.ts +1 -0
  245. package/menu.js +6 -0
  246. package/navigation-bar.js +1 -0
  247. package/overlays.js +2 -0
  248. package/package.json +1 -1
@@ -3,6 +3,7 @@ import { browserDetection } from '@lion/ui/core.js';
3
3
  /**
4
4
  * @typedef {import('lit').CSSResult} CSSResult
5
5
  * @typedef {import('./OverlayController.js').OverlayController} OverlayController
6
+ * @typedef {import('@lion/ui/types/overlays.js').OverlayPhase} OverlayPhase
6
7
  */
7
8
 
8
9
  import { overlayDocumentStyle } from './overlayDocumentStyle.js';
@@ -46,13 +47,38 @@ export class OverlaysManager {
46
47
  * @private
47
48
  */
48
49
  this.__shownList = [];
49
- /** @private */
50
- this.__siblingsInert = false;
50
+ /** @protected */
51
+ this._siblingsInert = false;
51
52
  /**
52
53
  * @type {WeakMap<OverlayController, OverlayController[]>}
53
54
  * @private
54
55
  */
55
56
  this.__blockingMap = new WeakMap();
57
+ /**
58
+ * @private
59
+ * @type {{
60
+ * preventScrollCount: number;
61
+ * clientWidth: number | undefined;
62
+ * clientHeight: number | undefined;
63
+ * marginRightInline: string | undefined;
64
+ * marginBottomInline: string | undefined;
65
+ * marginRight: number | undefined;
66
+ * marginBottom: number | undefined;
67
+ * }}
68
+ */
69
+ this.__bodySizeVars = {
70
+ preventScrollCount: 0,
71
+ clientWidth: undefined,
72
+ clientHeight: undefined,
73
+ marginRightInline: undefined,
74
+ marginBottomInline: undefined,
75
+ marginRight: undefined,
76
+ marginBottom: undefined,
77
+ };
78
+
79
+ this.__forTesting = {
80
+ bodySizeVars: this.__bodySizeVars,
81
+ };
56
82
 
57
83
  if (!OverlaysManager.__globalStyleNode) {
58
84
  OverlaysManager.__globalStyleNode = OverlaysManager.__createGlobalStyleNode();
@@ -118,7 +144,14 @@ export class OverlaysManager {
118
144
 
119
145
  this.__list = [];
120
146
  this.__shownList = [];
121
- this.__siblingsInert = false;
147
+ this._siblingsInert = false;
148
+ this.__bodySizeVars.preventScrollCount = 0;
149
+ this.__bodySizeVars.clientWidth = undefined;
150
+ this.__bodySizeVars.clientHeight = undefined;
151
+ this.__bodySizeVars.marginRightInline = undefined;
152
+ this.__bodySizeVars.marginBottomInline = undefined;
153
+ this.__bodySizeVars.marginRight = undefined;
154
+ this.__bodySizeVars.marginBottom = undefined;
122
155
 
123
156
  if (OverlaysManager.__globalStyleNode) {
124
157
  document.head.removeChild(
@@ -131,11 +164,76 @@ export class OverlaysManager {
131
164
  /** Features right now only for Global Overlay Manager */
132
165
 
133
166
  get siblingsInert() {
134
- return this.__siblingsInert;
167
+ return this._siblingsInert;
135
168
  }
136
169
 
137
170
  /** PreventsScroll */
138
171
 
172
+ /**
173
+ * @param {{ phase: OverlayPhase }} config
174
+ */
175
+ requestToKeepBodySize({ phase }) {
176
+ switch (phase) {
177
+ case 'before-show':
178
+ // Tracks the amount of active preventsScroll overlays.
179
+ // Only the first overlay captures body metrics and only the last one restores them.
180
+ if (this.__bodySizeVars.preventScrollCount === 0) {
181
+ this.__bodySizeVars.clientWidth = document.body.clientWidth;
182
+ this.__bodySizeVars.clientHeight = document.body.clientHeight;
183
+ this.__bodySizeVars.marginRightInline = document.body.style.marginRight;
184
+ this.__bodySizeVars.marginBottomInline = document.body.style.marginBottom;
185
+ }
186
+ this.__bodySizeVars.preventScrollCount += 1;
187
+ break;
188
+ case 'show': {
189
+ if (this.__bodySizeVars.preventScrollCount === 1) {
190
+ if (window.getComputedStyle) {
191
+ const bodyStyle = window.getComputedStyle(document.body);
192
+ this.__bodySizeVars.marginRight = parseInt(
193
+ bodyStyle.getPropertyValue('margin-right'),
194
+ 10,
195
+ );
196
+ this.__bodySizeVars.marginBottom = parseInt(
197
+ bodyStyle.getPropertyValue('margin-bottom'),
198
+ 10,
199
+ );
200
+ } else {
201
+ this.__bodySizeVars.marginRight = 0;
202
+ this.__bodySizeVars.marginBottom = 0;
203
+ }
204
+ const scrollbarWidth =
205
+ document.body.clientWidth - /** @type {number} */ (this.__bodySizeVars.clientWidth);
206
+ const scrollbarHeight =
207
+ document.body.clientHeight - /** @type {number} */ (this.__bodySizeVars.clientHeight);
208
+ const newMarginRight = this.__bodySizeVars.marginRight + scrollbarWidth;
209
+ const newMarginBottom = this.__bodySizeVars.marginBottom + scrollbarHeight;
210
+ // @ts-expect-error [external]: CSS not yet typed
211
+ if (window.CSS?.number && document.body.attributeStyleMap?.set) {
212
+ // @ts-ignore - CSS Typed OM not fully typed
213
+ document.body.attributeStyleMap.set('margin-right', CSS.px(newMarginRight));
214
+ // @ts-ignore - CSS Typed OM not fully typed
215
+ document.body.attributeStyleMap.set('margin-bottom', CSS.px(newMarginBottom));
216
+ } else {
217
+ document.body.style.marginRight = `${newMarginRight}px`;
218
+ document.body.style.marginBottom = `${newMarginBottom}px`;
219
+ }
220
+ }
221
+ break;
222
+ }
223
+ case 'hide':
224
+ case 'teardown':
225
+ if (this.__bodySizeVars.preventScrollCount > 0) {
226
+ this.__bodySizeVars.preventScrollCount -= 1;
227
+ if (this.__bodySizeVars.preventScrollCount === 0) {
228
+ document.body.style.marginRight = this.__bodySizeVars.marginRightInline || '';
229
+ document.body.style.marginBottom = this.__bodySizeVars.marginBottomInline || '';
230
+ }
231
+ }
232
+ break;
233
+ /* no default */
234
+ }
235
+ }
236
+
139
237
  // eslint-disable-next-line class-methods-use-this
140
238
  requestToPreventScroll() {
141
239
  const { isIOS, isMacSafari } = browserDetection;
@@ -113,11 +113,11 @@ export const overlayShadowDomStyle = css`
113
113
  }
114
114
 
115
115
  @media screen and (prefers-reduced-motion: reduce) {
116
- .overlays .overlays__backdrop--animation-in {
116
+ .overlays__backdrop--animation-in {
117
117
  animation: overlays-backdrop-fade-in 1ms;
118
118
  }
119
119
 
120
- .overlays .overlays__backdrop--animation-out {
120
+ .overlays__backdrop--animation-out {
121
121
  animation: overlays-backdrop-fade-out 1ms;
122
122
  }
123
123
  }
@@ -56,7 +56,8 @@ function adoptStyleWhenAdoptedStylesheetsNotSupported(
56
56
  const styleEl = document.createElement('style');
57
57
  // keep notation, so it's not renamed in minification/build
58
58
  // eslint-disable-next-line dot-notation
59
- const nonce = window['litNonce'];
59
+ // @ts-ignore - litNonce is a custom property
60
+ const nonce = window.litNonce;
60
61
  if (nonce !== undefined) {
61
62
  styleEl.setAttribute('nonce', nonce);
62
63
  }
@@ -8,6 +8,7 @@ import { isVisible } from './is-visible.js';
8
8
  import { sortByTabIndex } from './sort-by-tabindex.js';
9
9
 
10
10
  // IE11 supports matches as 'msMatchesSelector'
11
+ /** @type {'matches' | 'msMatchesSelector'} */
11
12
  const matchesFunc = 'matches' in Element.prototype ? 'matches' : 'msMatchesSelector';
12
13
 
13
14
  /**
@@ -16,11 +17,14 @@ const matchesFunc = 'matches' in Element.prototype ? 'matches' : 'msMatchesSelec
16
17
  */
17
18
  function isFocusable(element) {
18
19
  // Elements that cannot be focused if they have [disabled] attribute.
20
+ // @ts-ignore - msMatchesSelector is legacy
19
21
  if (element[matchesFunc]('input, select, textarea, button, object')) {
22
+ // @ts-ignore
20
23
  return element[matchesFunc](':not([disabled])');
21
24
  }
22
25
 
23
26
  // Elements that can be focused even if they have [disabled] attribute.
27
+ // @ts-ignore
24
28
  return element[matchesFunc]('a[href], area[href], iframe, [tabindex], [contentEditable]');
25
29
  }
26
30
 
@@ -19,6 +19,9 @@ export function isEqualConfig(a, b) {
19
19
  if (aProps.length !== bProps.length) {
20
20
  return false;
21
21
  }
22
- const isEqual = /** @param {string} prop */ prop => isEqualConfig(a[prop], b[prop]);
22
+ const isEqual =
23
+ /** @param {string} prop */
24
+ // @ts-ignore - dynamic property access
25
+ prop => isEqualConfig(a[prop], b[prop]);
23
26
  return aProps.every(isEqual);
24
27
  }
@@ -403,7 +403,7 @@ describe('OverlayController', () => {
403
403
  { ignoreAttributes: ['closedby'] },
404
404
  );
405
405
 
406
- expect(el).lightDom.to.equal(`<div slot="content">projected</div>`);
406
+ expect(el).lightDom.to.equal(`<div data-content="" slot="content">projected</div>`);
407
407
  });
408
408
  });
409
409
 
@@ -425,7 +425,7 @@ describe('OverlayController', () => {
425
425
  `
426
426
  <dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
427
427
  <div data-id="content-wrapper">
428
- <div id="content">non projected</div>
428
+ <div data-content="" id="content">non projected</div>
429
429
  </div>
430
430
  </dialog>
431
431
  `,
@@ -1384,6 +1384,109 @@ describe('OverlayController', () => {
1384
1384
  await ctrl1.hide();
1385
1385
  expect(Array.from(document.body.classList)).to.contain('overlays-scroll-lock');
1386
1386
  });
1387
+
1388
+ it('does not accumulate body margins when nested overlays have preventsScroll', async () => {
1389
+ const ctrl0 = new OverlayController({
1390
+ ...withGlobalTestConfig(),
1391
+ preventsScroll: true,
1392
+ });
1393
+ const ctrl1 = new OverlayController({
1394
+ ...withGlobalTestConfig(),
1395
+ preventsScroll: true,
1396
+ });
1397
+
1398
+ const originalMarginRight = document.body.style.marginRight;
1399
+
1400
+ await ctrl0.show();
1401
+ const marginAfterFirst = document.body.style.marginRight;
1402
+
1403
+ await ctrl1.show();
1404
+ const marginAfterSecond = document.body.style.marginRight;
1405
+
1406
+ // The margin should NOT increase further when second overlay opens
1407
+ expect(marginAfterSecond).to.equal(marginAfterFirst);
1408
+
1409
+ await ctrl1.hide();
1410
+ // After hiding second, first still prevents scroll — margin stays
1411
+ expect(document.body.style.marginRight).to.equal(marginAfterFirst);
1412
+
1413
+ await ctrl0.hide();
1414
+ // After hiding all, original margin is restored
1415
+ expect(document.body.style.marginRight).to.equal(originalMarginRight);
1416
+ });
1417
+
1418
+ it('restores body margin when overlay with preventsScroll is torn down while shown', async () => {
1419
+ const ctrl = new OverlayController({
1420
+ ...withGlobalTestConfig(),
1421
+ preventsScroll: true,
1422
+ });
1423
+
1424
+ const originalMarginRight = document.body.style.marginRight;
1425
+
1426
+ await ctrl.show();
1427
+ const marginAfterShow = document.body.style.marginRight;
1428
+ // Margin should be set after show
1429
+ expect(marginAfterShow).to.not.equal(originalMarginRight);
1430
+
1431
+ ctrl.teardown();
1432
+ // Margin should be restored after teardown
1433
+ expect(document.body.style.marginRight).to.equal(originalMarginRight);
1434
+ });
1435
+
1436
+ it('does not break body margin when teardown() is called on a hidden overlay', async () => {
1437
+ const ctrl0 = new OverlayController({
1438
+ ...withGlobalTestConfig(),
1439
+ preventsScroll: true,
1440
+ });
1441
+ const ctrl1 = new OverlayController({
1442
+ ...withGlobalTestConfig(),
1443
+ preventsScroll: true,
1444
+ });
1445
+
1446
+ const originalMarginRight = document.body.style.marginRight;
1447
+
1448
+ // Show first overlay
1449
+ await ctrl0.show();
1450
+ const marginAfterFirst = document.body.style.marginRight;
1451
+ expect(marginAfterFirst).to.not.equal(originalMarginRight);
1452
+
1453
+ // Teardown second overlay that was never shown
1454
+ ctrl1.teardown();
1455
+ // Margin should still be set by first overlay
1456
+ expect(document.body.style.marginRight).to.equal(marginAfterFirst);
1457
+
1458
+ // Hide first overlay
1459
+ await ctrl0.hide();
1460
+ // Now margin should be restored
1461
+ expect(document.body.style.marginRight).to.equal(originalMarginRight);
1462
+ });
1463
+
1464
+ it('does not break body margin when updateConfig() is called on a hidden overlay', async () => {
1465
+ const ctrl = new OverlayController({
1466
+ ...withGlobalTestConfig(),
1467
+ preventsScroll: true,
1468
+ });
1469
+
1470
+ const originalMarginRight = document.body.style.marginRight;
1471
+
1472
+ // updateConfig calls teardown internally
1473
+ ctrl.updateConfig({
1474
+ ...withGlobalTestConfig(),
1475
+ preventsScroll: true,
1476
+ });
1477
+
1478
+ // Margin should not be affected
1479
+ expect(document.body.style.marginRight).to.equal(originalMarginRight);
1480
+
1481
+ // Show after updateConfig
1482
+ await ctrl.show();
1483
+ const marginAfterShow = document.body.style.marginRight;
1484
+ expect(marginAfterShow).to.not.equal(originalMarginRight);
1485
+
1486
+ // Hide should restore
1487
+ await ctrl.hide();
1488
+ expect(document.body.style.marginRight).to.equal(originalMarginRight);
1489
+ });
1387
1490
  });
1388
1491
 
1389
1492
  describe('hasBackdrop', () => {
@@ -2180,15 +2283,23 @@ describe('OverlayController', () => {
2180
2283
  it('should not run with scroll prevention', async () => {
2181
2284
  await overlayControllerNoPrevent.show();
2182
2285
 
2183
- expect(overlayControllerNoPrevent.__bodyMarginRightInline).to.equal(undefined);
2184
- expect(overlayControllerNoPrevent.__bodyMarginRight).to.equal(undefined);
2286
+ expect(
2287
+ overlayControllerNoPrevent.manager.__forTesting.bodySizeVars.marginRightInline,
2288
+ ).to.equal(undefined);
2289
+ expect(overlayControllerNoPrevent.manager.__forTesting.bodySizeVars.marginRight).to.equal(
2290
+ undefined,
2291
+ );
2185
2292
  });
2186
2293
 
2187
2294
  it('should run with scroll prevention', async () => {
2188
2295
  await overlayControllerPreventsScroll.show();
2189
2296
 
2190
- expect(overlayControllerPreventsScroll.__bodyMarginRightInline).to.not.equal(undefined);
2191
- expect(overlayControllerPreventsScroll.__bodyMarginRight).to.not.equal(undefined);
2297
+ expect(
2298
+ overlayControllerPreventsScroll.manager.__forTesting.bodySizeVars.marginRightInline,
2299
+ ).to.not.equal(undefined);
2300
+ expect(
2301
+ overlayControllerPreventsScroll.manager.__forTesting.bodySizeVars.marginRight,
2302
+ ).to.not.equal(undefined);
2192
2303
  });
2193
2304
  });
2194
2305
  });
@@ -46,7 +46,7 @@ describe('OverlaysManager', () => {
46
46
  // @ts-ignore [allow-private-in-test]
47
47
  expect(mngr.__shownList).to.be.empty;
48
48
  // @ts-ignore [allow-private-in-test]
49
- expect(mngr.__siblingsInert).to.be.false;
49
+ expect(mngr._siblingsInert).to.be.false;
50
50
  });
51
51
 
52
52
  it('can add/remove controllers', () => {
@@ -11,6 +11,15 @@ export type ViewportPlacement =
11
11
  | 'bottom-left'
12
12
  | 'left';
13
13
 
14
+ export type OverlayPhase =
15
+ | 'setup'
16
+ | 'init'
17
+ | 'teardown'
18
+ | 'before-show'
19
+ | 'show'
20
+ | 'hide'
21
+ | 'add'
22
+ | 'remove';
14
23
 
15
24
  export interface ViewportConfig {
16
25
  placement: ViewportPlacement;
@@ -87,14 +96,20 @@ export interface OverlayConfig {
87
96
  /** By default, the tooltip content is a 'description' for the invoker (uses aria-describedby) Setting this property to 'label' makes the content function as a label (via aria-labelledby) */
88
97
  invokerRelation?: 'label' | 'description';
89
98
 
90
- /** render a div instead of dialog */
91
- _noDialogEl?: Boolean;
92
-
93
99
  /**
94
100
  * Determines the conditions hiding/showing should be based on. It gets the OverlayController as input and returns an object with
95
101
  * functions with Overlay phases as keys
96
102
  */
97
103
  visibilityTriggerFunction?: Function;
98
- }
99
104
 
105
+ /**
106
+ * Whether the overlay content should receive focus when shown.
107
+ */
108
+ focusContentOnOpen?: boolean;
100
109
 
110
+ /*
111
+ * By default, we function either as overlay or disclosure. In some cases, this should be dynamically set (think of responsive changes).
112
+ * or it depends on the context (a top level menu is not openable (unless it's a context menu), its children menus are).
113
+ */
114
+ isOpenable?: boolean;
115
+ }
@@ -832,6 +832,7 @@ describe('lion-select-rich', () => {
832
832
  await waitUntil(isSelectRichRendered);
833
833
  getInvoker()?.click();
834
834
  await waitUntil(isDialogVisible);
835
+ // @ts-ignore - NodeList array access
835
836
  const optionBlue = /** @type { HTMLElement | undefined } */ (
836
837
  wrapperElementShadowRoot?.querySelectorAll('lion-option')
837
838
  )?.[1];
@@ -955,6 +956,7 @@ describe('lion-select-rich', () => {
955
956
  await waitUntil(isSelectRichRendered);
956
957
  getInvoker()?.click();
957
958
  await waitUntil(isDialogVisible);
959
+ // @ts-ignore - NodeList array access
958
960
  const optionBlue = /** @type { HTMLElement | undefined } */ (
959
961
  wrapperElementShadowRoot?.querySelectorAll('lion-option')
960
962
  )?.[1];
@@ -1082,6 +1084,7 @@ describe('lion-select-rich', () => {
1082
1084
  await waitUntil(isSelectRichRendered);
1083
1085
  getInvoker()?.click();
1084
1086
  await waitUntil(isDialogVisible);
1087
+ // @ts-ignore - NodeList array access
1085
1088
  const optionBlue = /** @type { HTMLElement | undefined } */ (
1086
1089
  wrapperElementShadowRoot?.querySelectorAll('lion-option')
1087
1090
  )?.[1];