@lion/ui 0.16.1 → 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 (247) 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 +98 -0
  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/types/OverlayConfig.ts +19 -4
  74. package/components/select-rich/test/lion-select-rich.test.js +3 -0
  75. package/custom-elements.json +15785 -5337
  76. package/dist-types/components/button/src/LionButton.d.ts +1 -0
  77. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  78. package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
  79. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  80. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +3 -0
  81. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +1 -0
  82. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +24 -0
  83. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +1 -0
  84. package/dist-types/components/combobox/src/utils/makeMatchingTextBold.d.ts.map +1 -1
  85. package/dist-types/components/dialog/src/LionDialog.d.ts +2 -1
  86. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  87. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  88. package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
  89. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  90. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  91. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
  92. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
  93. package/dist-types/components/input-stepper/src/LionInputStepper.d.ts +4 -2
  94. package/dist-types/components/input-stepper/src/LionInputStepper.d.ts.map +1 -1
  95. package/dist-types/components/input-stepper/test-suites/lion-input-stepper.suite.d.ts.map +1 -1
  96. package/dist-types/components/menu/index.d.ts +3 -0
  97. package/dist-types/components/menu/index.d.ts.map +1 -0
  98. package/dist-types/components/menu/lion-menu-overlay.d.ts +2 -0
  99. package/dist-types/components/menu/lion-menu-overlay.d.ts.map +1 -0
  100. package/dist-types/components/menu/lion-menu.d.ts +2 -0
  101. package/dist-types/components/menu/lion-menu.d.ts.map +1 -0
  102. package/dist-types/components/menu/lion-spinbutton.d.ts +2 -0
  103. package/dist-types/components/menu/lion-spinbutton.d.ts.map +1 -0
  104. package/dist-types/components/menu/lion-toolbar.d.ts +2 -0
  105. package/dist-types/components/menu/lion-toolbar.d.ts.map +1 -0
  106. package/dist-types/components/menu/lion-tree.d.ts +2 -0
  107. package/dist-types/components/menu/lion-tree.d.ts.map +1 -0
  108. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +611 -0
  109. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -0
  110. package/dist-types/components/menu/src/LionMenu.d.ts +563 -0
  111. package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -0
  112. package/dist-types/components/menu/src/LionMenuHybrid.d.ts +19 -0
  113. package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +1 -0
  114. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +1006 -0
  115. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +1 -0
  116. package/dist-types/components/menu/src/LionSpinbutton.d.ts +58 -0
  117. package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +1 -0
  118. package/dist-types/components/menu/src/LionToolbar.d.ts +8 -0
  119. package/dist-types/components/menu/src/LionToolbar.d.ts.map +1 -0
  120. package/dist-types/components/menu/src/LionTree.d.ts +445 -0
  121. package/dist-types/components/menu/src/LionTree.d.ts.map +1 -0
  122. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +493 -0
  123. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -0
  124. package/dist-types/components/menu/src/utils/isInView.d.ts +9 -0
  125. package/dist-types/components/menu/src/utils/isInView.d.ts.map +1 -0
  126. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +42 -0
  127. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -0
  128. package/dist-types/components/menu/src/utils/uuid.d.ts +2 -0
  129. package/dist-types/components/menu/src/utils/uuid.d.ts.map +1 -0
  130. package/dist-types/components/menu/test/lion-menu.test.d.ts +2 -0
  131. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +1 -0
  132. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +13 -0
  133. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -0
  134. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +226 -0
  135. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +1 -0
  136. package/dist-types/components/navigation-bar/src/types.d.ts +85 -0
  137. package/dist-types/components/navigation-bar/src/types.d.ts.map +1 -0
  138. package/dist-types/components/overlays/src/OverlayController.d.ts +7 -13
  139. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  140. package/dist-types/components/overlays/src/OverlayMixin.d.ts +3 -0
  141. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  142. package/dist-types/components/overlays/src/OverlaysManager.d.ts +31 -0
  143. package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
  144. package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
  145. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  146. package/dist-types/components/overlays/types/OverlayConfig.d.ts +6 -2
  147. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  148. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +11 -2
  149. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  150. package/dist-types/exports/define/lion-item.d.ts +2 -0
  151. package/dist-types/exports/define/lion-item.d.ts.map +1 -0
  152. package/dist-types/exports/define/lion-menu-overlay.d.ts +2 -0
  153. package/dist-types/exports/define/lion-menu-overlay.d.ts.map +1 -0
  154. package/dist-types/exports/define/lion-menu.d.ts +2 -0
  155. package/dist-types/exports/define/lion-menu.d.ts.map +1 -0
  156. package/dist-types/exports/define/lion-navigation-bar.d.ts +2 -0
  157. package/dist-types/exports/define/lion-navigation-bar.d.ts.map +1 -0
  158. package/dist-types/exports/define/lion-toolbar.d.ts +2 -0
  159. package/dist-types/exports/define/lion-toolbar.d.ts.map +1 -0
  160. package/dist-types/exports/define/lion-tree.d.ts +2 -0
  161. package/dist-types/exports/define/lion-tree.d.ts.map +1 -0
  162. package/dist-types/exports/menu.d.ts +7 -0
  163. package/dist-types/exports/menu.d.ts.map +1 -0
  164. package/dist-types/exports/navigation-bar.d.ts +2 -0
  165. package/dist-types/exports/navigation-bar.d.ts.map +1 -0
  166. package/dist-types/exports/overlays.d.ts +2 -0
  167. package/dist-types/exports/types/overlays.d.ts +1 -0
  168. package/dist-types/exports/types/overlays.d.ts.map +1 -1
  169. package/dist-types/tsconfig.tsbuildinfo +1 -1
  170. package/docs/components/checkbox-group/overview.md +2 -2
  171. package/docs/components/collapsible/overview.md +1 -1
  172. package/docs/components/combobox/overview.md +1 -1
  173. package/docs/components/combobox/use-cases.md +1 -1
  174. package/docs/components/dialog/overview.md +1 -1
  175. package/docs/components/fieldset/overview.md +5 -5
  176. package/docs/components/form/overview.md +3 -3
  177. package/docs/components/form/use-cases.md +2 -2
  178. package/docs/components/icon/use-cases.md +1 -1
  179. package/docs/components/index.md +1 -1
  180. package/docs/components/input/overview.md +1 -1
  181. package/docs/components/input-amount/overview.md +3 -3
  182. package/docs/components/input-date/overview.md +3 -3
  183. package/docs/components/input-datepicker/overview.md +5 -5
  184. package/docs/components/input-datepicker/use-cases.md +16 -1
  185. package/docs/components/input-email/overview.md +2 -2
  186. package/docs/components/input-file/overview.md +1 -1
  187. package/docs/components/input-iban/overview.md +2 -2
  188. package/docs/components/input-range/api-table.md +1 -1
  189. package/docs/components/input-range/overview.md +2 -2
  190. package/docs/components/input-stepper/api-table.md +2 -2
  191. package/docs/components/input-stepper/overview.md +1 -1
  192. package/docs/components/input-stepper/use-cases.md +26 -0
  193. package/docs/components/input-tel/overview.md +1 -1
  194. package/docs/components/input-tel/use-cases.md +6 -6
  195. package/docs/components/input-tel-dropdown/overview.md +1 -1
  196. package/docs/components/listbox/use-cases.md +1 -1
  197. package/docs/components/menu/api-table.md +450 -0
  198. package/docs/components/menu/applyMenuDemoStyles.js +173 -0
  199. package/docs/components/menu/extensions.md +216 -0
  200. package/docs/components/menu/index.md +13 -0
  201. package/docs/components/menu/overview.md +422 -0
  202. package/docs/components/radio-group/overview.md +3 -3
  203. package/docs/components/select/use-cases.md +1 -1
  204. package/docs/components/select-rich/api-table.md +1 -1
  205. package/docs/components/select-rich/use-cases.md +2 -2
  206. package/docs/components/tabs/examples.md +1 -1
  207. package/docs/fundamentals/index.md +4 -4
  208. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  209. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  210. package/docs/fundamentals/rationales/accessibility.md +1 -1
  211. package/docs/fundamentals/systems/core/SlotMixin.md +18 -18
  212. package/docs/fundamentals/systems/core/overview.md +1 -1
  213. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  214. package/docs/fundamentals/systems/form/interaction-states.md +0 -1
  215. package/docs/fundamentals/systems/form/model-value.md +1 -1
  216. package/docs/fundamentals/systems/form/overview.md +28 -28
  217. package/docs/fundamentals/systems/form/validate.md +2 -2
  218. package/docs/fundamentals/systems/localize/overview.md +4 -4
  219. package/docs/fundamentals/systems/localize/text.md +1 -1
  220. package/docs/fundamentals/systems/overlays/api-table.md +92 -45
  221. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  222. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  223. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  224. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  225. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  226. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  227. package/docs/guides/how-to/create-a-form.md +4 -4
  228. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  229. package/docs/guides/how-to/index.md +14 -0
  230. package/docs/guides/index.md +8 -8
  231. package/docs/guides/principles/index.md +5 -5
  232. package/docs/guides/principles/styling.md +1 -2
  233. package/exports/collapsible.js +1 -0
  234. package/exports/define/lion-item.js +3 -0
  235. package/exports/define/lion-menu-overlay.js +3 -0
  236. package/exports/define/lion-menu.js +3 -0
  237. package/exports/define/lion-navigation-bar.js +3 -0
  238. package/exports/define/lion-toolbar.js +3 -0
  239. package/exports/define/lion-tree.js +3 -0
  240. package/exports/menu.js +6 -0
  241. package/exports/navigation-bar.js +1 -0
  242. package/exports/overlays.js +2 -0
  243. package/exports/types/overlays.ts +1 -0
  244. package/menu.js +6 -0
  245. package/navigation-bar.js +1 -0
  246. package/overlays.js +2 -0
  247. package/package.json +1 -1
package/collapsible.js CHANGED
@@ -1 +1,2 @@
1
1
  export { LionCollapsible } from './components/collapsible/src/LionCollapsible.js';
2
+ // export { DisclosureMixin } from '../components/collapsible/src/DisclosureMixin.js';
@@ -52,6 +52,7 @@ export class LionButton extends DisabledWithTabIndexMixin(LitElement) {
52
52
  vertical-align: middle;
53
53
  line-height: 24px;
54
54
  background-color: #eee; /* minimal styling to make it recognizable as btn */
55
+ color: black; /* if we set background, we should set color as well, like a native button */
55
56
  padding: 8px; /* padding to fix with min-height */
56
57
  outline: none; /* focus style handled below */
57
58
  cursor: default; /* we should always see the default arrow, never a caret */
@@ -219,4 +220,8 @@ export class LionButton extends DisabledWithTabIndexMixin(LitElement) {
219
220
  this.click();
220
221
  }
221
222
  }
223
+
224
+ // we want to be able to identify LionButtons w/o instanceof (for perf (loose dep) and dual version support),
225
+ // so we use a static property for that that doesn't get renamed by minifiers
226
+ static ['_$isLionButton$'] = true;
222
227
  }
@@ -279,6 +279,7 @@ export function LionButtonSuite({ klass = LionButton } = {}) {
279
279
 
280
280
  sameProperties.forEach(property => {
281
281
  it(`has same value of the property "${property}" as in native button event`, () => {
282
+ // @ts-ignore - dynamic property access
282
283
  expect(lionButtonEvent[property]).to.equal(nativeButtonEvent[property]);
283
284
  });
284
285
  });
@@ -928,6 +928,7 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
928
928
  if (type !== 'Date') {
929
929
  tmpDate.setDate(1);
930
930
  }
931
+ // @ts-ignore - dynamic method access
931
932
  tmpDate[`set${type}`](tmpDate[`get${type}`]() + modify);
932
933
  // if we've reset the day count,
933
934
  // restore day count as best we can
@@ -935,6 +936,7 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
935
936
  const maxDays = new Date(tmpDate.getFullYear(), tmpDate.getMonth() + 1, 0).getDate();
936
937
  tmpDate.setDate(Math.min(this.centralDate.getDate(), maxDays));
937
938
  }
939
+ // @ts-ignore - dynamic property access
938
940
  this[dateType] = tmpDate;
939
941
  }
940
942
 
@@ -0,0 +1,313 @@
1
+ /**
2
+ * @typedef {import('../types/DisclosureMixinTypes.js').DisclosureHost} DisclosureHost
3
+ * @typedef {import('../types/DisclosureMixinTypes.js').DisclosureMixin} DisclosureMixin
4
+ */
5
+
6
+ // /**
7
+ // * @type {DisclosureMixin}
8
+ // */
9
+ // const DisclosureMixinImplementation = superclass =>
10
+ // // @ts-ignore https://github.com/microsoft/TypeScript/issues/36821#issuecomment-588375051
11
+ // class DisclosureMixin extends superclass {
12
+ // /** @type {any} */
13
+ // static get properties() {
14
+ // return {
15
+ // opened: { type: Boolean, reflect: true },
16
+ // handleFocus: { type: Boolean, attribute: 'handle-focus' },
17
+ // invokerInteraction: { type: String, attribute: 'invoker-interaction' },
18
+ // };
19
+ // }
20
+
21
+ // /**
22
+ // * @param {Element} focusableElOrWrapper
23
+ // * @returns {Element|null}
24
+ // */
25
+ // static _getFocusableInvokerEl(focusableElOrWrapper) {
26
+ // // return focusableElOrWrapper;
27
+ // return (
28
+ // focusableElOrWrapper &&
29
+ // (focusableElOrWrapper.hasAttribute('tabindex') || focusableElOrWrapper.tagName === 'BUTTON'
30
+ // ? focusableElOrWrapper
31
+ // : focusableElOrWrapper.querySelector('[role=button], button'))
32
+ // );
33
+ // }
34
+
35
+ // get _invokerNode() {
36
+ // const ctor = this.constructor;
37
+ // if (!this.__invokerNode) {
38
+ // const slottedNode = Array.from(this.children).find(child => child.slot === 'invoker');
39
+ // if (slottedNode) {
40
+ // this.__invokerNode = ctor._getFocusableInvokerEl(slottedNode);
41
+ // } else {
42
+ // this.__invokerNode =
43
+ // this.previousElementSibling?.hasAttribute('data-invoker') &&
44
+ // ctor._getFocusableInvokerEl(this.previousElementSibling);
45
+ // }
46
+ // }
47
+ // return this.__invokerNode;
48
+ // }
49
+
50
+ // get _contentNode() {
51
+ // if (!this._cachedOverlayContentNode) {
52
+ // this._cachedOverlayContentNode = Array.from(this.children).find(
53
+ // child => child.slot === 'content',
54
+ // );
55
+ // }
56
+ // return this._cachedOverlayContentNode;
57
+ // }
58
+
59
+ // constructor() {
60
+ // super();
61
+ // this.opened = false;
62
+ // /**
63
+ // * @type {'click'|'hover'}
64
+ // */
65
+ // this.invokerInteraction = 'click';
66
+ // /**
67
+ // * Puts focus on `_contentNode` on open and on `_invokerNode` on close.
68
+ // * @type {Boolean}
69
+ // */
70
+ // this.handleFocus = false;
71
+ // this.__disclosureNeedsSetup = true;
72
+
73
+ // this.toggle = this.toggle.bind(this);
74
+ // this.open = this.open.bind(this);
75
+ // this.close = this.close.bind(this);
76
+
77
+ // this.__handleAnimateComplete = this.__handleAnimateComplete.bind(this);
78
+
79
+ // this.__onInvokerMouseenter = this.__onInvokerMouseenter.bind(this);
80
+ // this.__onContentMouseenter = this.__onContentMouseenter.bind(this);
81
+ // this.__onInvokerMouseleave = this.__onInvokerMouseleave.bind(this);
82
+ // this.__onContentMouseleave = this.__onContentMouseleave.bind(this);
83
+ // }
84
+
85
+ // connectedCallback() {
86
+ // super.connectedCallback();
87
+ // // we do a setup after every connectedCallback as firstUpdated will only be called once
88
+ // this.__disclosureNeedsSetup = true;
89
+ // this.updateComplete.then(() => {
90
+ // if (this.__disclosureNeedsSetup) {
91
+ // this._setupDisclosure();
92
+ // }
93
+ // this.__disclosureNeedsSetup = false;
94
+ // });
95
+ // this.__setupAnimation();
96
+ // }
97
+
98
+ // disconnectedCallback() {
99
+ // super.disconnectedCallback();
100
+ // this._teardownDisclosure();
101
+ // this.__teardownAnimation();
102
+ // }
103
+
104
+ // /**
105
+ // * @overridable
106
+ // */
107
+ // _setupDisclosure() {
108
+ // console.log('_setupDisclosure', this.level);
109
+
110
+ // this._setupOpenCloseListeners();
111
+ // }
112
+
113
+ // /**
114
+ // * @overridable
115
+ // */
116
+ // _teardownDisclosure() {
117
+ // this._teardownOpenCloseListeners();
118
+ // }
119
+
120
+ // /**
121
+ // * @overridable
122
+ // */
123
+ // _setupOpenCloseListeners() {
124
+ // console.log('setup listeners', this.level);
125
+ // if (!this._invokerNode) {
126
+ // return;
127
+ // }
128
+
129
+ // const interactions = this.invokerInteraction.split(' ');
130
+
131
+ // if (interactions.includes('hover')) {
132
+ // this._invokerNode.addEventListener('mouseenter', this.__onInvokerMouseenter);
133
+ // this._contentNode?.addEventListener('mouseenter', this.__onContentMouseenter);
134
+ // this._invokerNode.addEventListener('mouseleave', this.__onInvokerMouseleave);
135
+ // this._contentNode?.addEventListener('mouseleave', this.__onContentMouseleave);
136
+ // }
137
+ // if (interactions.includes('click')) {
138
+ // this._invokerNode.addEventListener('click', this.toggle);
139
+ // }
140
+ // }
141
+
142
+ // __onInvokerMouseenter() {
143
+ // this.__invokerHover = true;
144
+ // this.open();
145
+ // }
146
+
147
+ // __onContentMouseenter() {
148
+ // this.__contentHover = true;
149
+ // console.log('this.__contentHover', this.__contentHover);
150
+ // this.open();
151
+ // }
152
+
153
+ // __onInvokerMouseleave() {
154
+ // setTimeout(() => {
155
+ // if (!this.__contentHover) {
156
+ // this.close();
157
+ // }
158
+ // });
159
+ // this.__invokerHover = false;
160
+ // }
161
+
162
+ // __onContentMouseleave() {
163
+ // setTimeout(() => {
164
+ // if (!this.__invokerHover) {
165
+ // this.close();
166
+ // }
167
+ // });
168
+ // this.__contentHover = false;
169
+ // }
170
+
171
+ // /**
172
+ // * @overridable
173
+ // */
174
+ // _teardownOpenCloseListeners() {
175
+ // if (!this._invokerNode) {
176
+ // return;
177
+ // }
178
+
179
+ // this._invokerNode.removeEventListener('mouseenter', this.open);
180
+ // this._invokerNode.removeEventListener('mouseleave', this.close);
181
+ // this._contentNode?.removeEventListener('mouseenter', this.open);
182
+ // this._contentNode?.removeEventListener('mouseleave', this.close);
183
+
184
+ // // console.log(this, 'removetCLick');
185
+
186
+ // this._invokerNode.removeEventListener('click', this.toggle);
187
+ // }
188
+
189
+ // // TODO: fire event on updated?
190
+ // /**
191
+ // * @override
192
+ // * @param {string} name
193
+ // * @param {any} oldValue
194
+ // */
195
+ // requestUpdate(name, oldValue) {
196
+ // super.requestUpdate(name, oldValue);
197
+ // if (name === 'opened') {
198
+ // this.dispatchEvent(new Event('opened-changed'));
199
+ // }
200
+ // }
201
+
202
+ // /**
203
+ // * @param {import('lit-element').PropertyValues } changedProperties
204
+ // */
205
+ // updated(changedProperties) {
206
+ // super.updated(changedProperties);
207
+
208
+ // if (changedProperties.has('opened')) {
209
+ // this._onOpenedChanged();
210
+ // }
211
+ // }
212
+
213
+ // /**
214
+ // * @param {import('lit-element').PropertyValues } changedProperties
215
+ // */
216
+ // firstUpdated(changedProperties) {
217
+ // super.firstUpdated(changedProperties);
218
+ // this._onOpenedChanged();
219
+
220
+ // if (this.handleFocus && !this._contentNode?.hasAttribute('tabindex')) {
221
+ // this._contentNode?.setAttribute('tabindex', '-1');
222
+ // }
223
+ // }
224
+
225
+ // /**
226
+ // * @overridable
227
+ // */
228
+ // async _onOpenedChanged() {
229
+ // this._invokerNode.setAttribute('aria-expanded', `${this.opened}`);
230
+
231
+ // if (this.opened) {
232
+ // this._contentNode.style.setProperty('display', '');
233
+ // await this._showAnimation({ contentNode: this._contentNode });
234
+ // this._onDisclosureShow();
235
+ // } else {
236
+ // this._onDisclosureHide();
237
+ // await this._hideAnimation({ contentNode: this._contentNode });
238
+ // this._contentNode.style.setProperty('display', 'none');
239
+ // }
240
+ // }
241
+
242
+ // _onDisclosureShow() {
243
+ // // if (this.checkedIndex != null) {
244
+ // // this.activeIndex = this.checkedIndex;
245
+ // // }
246
+
247
+ // if (this.handleFocus) {
248
+ // this._contentNode.focus();
249
+ // }
250
+ // }
251
+
252
+ // _onDisclosureHide() {
253
+ // if (this.handleFocus) {
254
+ // this._invokerNode.focus();
255
+ // }
256
+ // }
257
+
258
+ // /**
259
+ // * Show animation implementation in sub-classer.
260
+ // * @param {{ contentNode: HTMLElement; }} cfg
261
+ // */
262
+ // // eslint-disable-next-line class-methods-use-this, no-empty-function
263
+ // async _showAnimation(cfg) {
264
+ // this._refreshAnimateCompletePromise();
265
+ // }
266
+
267
+ // /**
268
+ // * Hide animation implementation in sub-classer.
269
+ // * @param {{ contentNode: HTMLElement; }} cfg
270
+ // */
271
+ // // eslint-disable-next-line class-methods-use-this, no-empty-function
272
+ // async _hideAnimation(cfg) {
273
+ // this._refreshAnimateCompletePromise();
274
+ // }
275
+
276
+ // _refreshAnimateCompletePromise() {
277
+ // this._animateComplete = new Promise(resolve => {
278
+ // // Note that when a lib like GSAP is used, neither 'transitionend' or 'animationend' will be called.
279
+ // // In such a case, a subclasser needs to resolve this pending promise by calling this method
280
+ // this._resolveAnimateComplete = resolve;
281
+ // });
282
+ // }
283
+
284
+ // __setupAnimation() {
285
+ // this._contentNode.addEventListener('transitionend', this.__handleAnimateComplete);
286
+ // this._contentNode.addEventListener('animationend', this.__handleAnimateComplete);
287
+ // }
288
+
289
+ // __teardownAnimation() {
290
+ // this._contentNode.removeEventListener('transitionend', this.__handleAnimateComplete);
291
+ // this._contentNode.removeEventListener('animationend', this.__handleAnimateComplete);
292
+ // }
293
+
294
+ // __handleAnimateComplete() {
295
+ // if (typeof this._resolveAnimateComplete === 'function') {
296
+ // this._resolveAnimateComplete();
297
+ // }
298
+ // }
299
+
300
+ // toggle() {
301
+ // // console.log('toggul', this);
302
+ // this.opened = !this.opened;
303
+ // }
304
+
305
+ // open() {
306
+ // this.opened = true;
307
+ // }
308
+
309
+ // close() {
310
+ // this.opened = false;
311
+ // }
312
+ // };
313
+ // export const DisclosureMixin = dedupeMixin(DisclosureMixinImplementation);
@@ -0,0 +1,48 @@
1
+ import { Constructor } from '@open-wc/dedupe-mixin';
2
+ import { LitElement } from 'lit';
3
+
4
+ export declare class DisclosureHost {
5
+ public opened: Boolean;
6
+
7
+ protected get _invokerNode(): HTMLElement;
8
+
9
+ protected get _contentNode(): HTMLElement;
10
+
11
+ public toggle(): void;
12
+
13
+ public open(): void;
14
+
15
+ public close(): void;
16
+
17
+ protected _onOpenedChanged(): Promise<void>;
18
+
19
+ protected _onDisclosureShow(): void;
20
+
21
+ protected _onDisclosureHide(): void;
22
+
23
+ protected _showAnimation(cfg: object): Promise<void>;
24
+
25
+ protected _hideAnimation(cfg: object): Promise<void>;
26
+
27
+ protected _refreshAnimateCompletePromise(): void;
28
+
29
+ protected _setupOpenCloseListeners(): void;
30
+
31
+ protected _teardownOpenCloseListeners(): void;
32
+
33
+ private __setupAnimation(): void;
34
+
35
+ private __teardownAnimation(): void;
36
+
37
+ private __handleAnimateComplete(): void;
38
+ }
39
+
40
+ export declare function DisclosureImplementation<T extends Constructor<LitElement>>(
41
+ superclass: T,
42
+ ): T &
43
+ Constructor<DisclosureHost> &
44
+ DisclosureHost &
45
+ Pick<typeof DisclosureHost, keyof typeof DisclosureHost> &
46
+ Pick<typeof LitElement, keyof typeof LitElement>;
47
+
48
+ export type DisclosureMixin = typeof DisclosureImplementation;
@@ -9,7 +9,9 @@ export function makeMatchingTextBold(root, matchingString) {
9
9
  if (childNode.nodeName === '#text') {
10
10
  // check for match based on nodeValue
11
11
 
12
- const re = new RegExp(`^(.*?)(${matchingString})(.*)$`, 'i');
12
+ // Escape special regex characters in matchingString
13
+ const escapedString = matchingString.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
14
+ const re = new RegExp(`^(.*?)(${escapedString})(.*)$`, 'i');
13
15
  // @ts-ignore
14
16
  const match = childNode.nodeValue.match(re);
15
17
 
@@ -3227,6 +3227,7 @@ describe('lion-combobox', () => {
3227
3227
  const [el, options] = await fruitFixture({ autocomplete: 'both', matchMode: 'all' });
3228
3228
  await mimicUserTyping(/** @type {LionCombobox} */ (el), 'choke');
3229
3229
  await el.updateComplete;
3230
+ // @ts-ignore - array index access
3230
3231
  const labelledElement = options[0].querySelector('span[aria-label="Artichoke"]');
3231
3232
  expect(labelledElement).to.not.be.null;
3232
3233
  expect(labelledElement.innerText).to.equal('Artichoke');
@@ -3648,4 +3649,108 @@ describe('lion-combobox', () => {
3648
3649
  expect(el.opened).to.be.true;
3649
3650
  });
3650
3651
  });
3652
+
3653
+ describe('Special Characters in Search', () => {
3654
+ it('correctly escapes all regex special characters in search queries', async () => {
3655
+ const el = /** @type {LionCombobox} */ (
3656
+ await fixture(html`
3657
+ <lion-combobox label="Search" name="foo">
3658
+ <lion-option .choiceValue="${'test.com'}">test.com</lion-option>
3659
+ <lion-option .choiceValue="${'func(arg)'}">func(arg)</lion-option>
3660
+ <lion-option .choiceValue="${'array[0]'}">array[0]</lion-option>
3661
+ <lion-option .choiceValue="${'C++'}">C++</lion-option>
3662
+ <lion-option .choiceValue="${'a * b'}">a * b</lion-option>
3663
+ <lion-option .choiceValue="${'What?'}">What?</lion-option>
3664
+ <lion-option .choiceValue="${'$100'}">$100</lion-option>
3665
+ <lion-option .choiceValue="${'x^2'}">x^2</lion-option>
3666
+ <lion-option .choiceValue="${'a | b'}">a | b</lion-option>
3667
+ <lion-option .choiceValue="${'path\\file'}">path\\file</lion-option>
3668
+ <lion-option .choiceValue="${'{name}'}">{name}</lion-option>
3669
+ <lion-option .choiceValue="${'user+tag@example.com'}">user+tag@example.com</lion-option>
3670
+ <lion-option .choiceValue="${'(a+b)*c^2$'}">>(a+b)*c^2$</lion-option>
3671
+ <lion-option .choiceValue="${'test|value?[x]'}">test|value?[x]</lion-option>
3672
+ <lion-option .choiceValue="${'file.{txt|md}\\n'}">file.{txt|md}\\n</lion-option>
3673
+ <lion-option .choiceValue="${'testXcom'}">testXcom</lion-option>
3674
+ <lion-option .choiceValue="${'funcXargX'}">funcXargX</lion-option>
3675
+ <lion-option .choiceValue="${'arrayX0X'}">arrayX0X</lion-option>
3676
+ </lion-combobox>
3677
+ `)
3678
+ );
3679
+
3680
+ // Test dot - should not act as wildcard
3681
+ await mimicUserTyping(el, 'test.com');
3682
+ await el.updateComplete;
3683
+ expect(getFilteredOptionValues(el)).to.eql(['test.com']);
3684
+
3685
+ // Test parentheses
3686
+ await mimicUserTyping(el, '(arg)');
3687
+ await el.updateComplete;
3688
+ expect(getFilteredOptionValues(el)).to.eql(['func(arg)']);
3689
+
3690
+ // Test square brackets
3691
+ await mimicUserTyping(el, '[0]');
3692
+ await el.updateComplete;
3693
+ expect(getFilteredOptionValues(el)).to.eql(['array[0]']);
3694
+
3695
+ // Test plus sign
3696
+ await mimicUserTyping(el, '+');
3697
+ await el.updateComplete;
3698
+ expect(getFilteredOptionValues(el)).to.eql(['C++', 'user+tag@example.com', '(a+b)*c^2$']);
3699
+
3700
+ // Test asterisk
3701
+ await mimicUserTyping(el, '*');
3702
+ await el.updateComplete;
3703
+ expect(getFilteredOptionValues(el)).to.eql(['a * b', '(a+b)*c^2$']);
3704
+
3705
+ // Test question mark
3706
+ await mimicUserTyping(el, '?');
3707
+ await el.updateComplete;
3708
+ expect(getFilteredOptionValues(el)).to.eql(['What?', 'test|value?[x]']);
3709
+
3710
+ // Test dollar sign
3711
+ await mimicUserTyping(el, '$');
3712
+ await el.updateComplete;
3713
+ expect(getFilteredOptionValues(el)).to.eql(['$100', '(a+b)*c^2$']);
3714
+
3715
+ // Test caret
3716
+ await mimicUserTyping(el, '^2');
3717
+ await el.updateComplete;
3718
+ expect(getFilteredOptionValues(el)).to.eql(['x^2', '(a+b)*c^2$']);
3719
+
3720
+ // Test pipe
3721
+ await mimicUserTyping(el, '|');
3722
+ await el.updateComplete;
3723
+ expect(getFilteredOptionValues(el)).to.eql(['a | b', 'test|value?[x]', 'file.{txt|md}\\n']);
3724
+
3725
+ // Test backslash
3726
+ await mimicUserTyping(el, '\\');
3727
+ await el.updateComplete;
3728
+ expect(getFilteredOptionValues(el)).to.eql(['path\\file', 'file.{txt|md}\\n']);
3729
+
3730
+ // Test curly braces
3731
+ await mimicUserTyping(el, '{name}');
3732
+ await el.updateComplete;
3733
+ expect(getFilteredOptionValues(el)).to.eql(['{name}']);
3734
+
3735
+ // Test complex combination with multiple special characters
3736
+ await mimicUserTyping(el, '(a+b)*c');
3737
+ await el.updateComplete;
3738
+ expect(getFilteredOptionValues(el)).to.eql(['(a+b)*c^2$']);
3739
+
3740
+ // Test email with plus and dot
3741
+ await mimicUserTyping(el, 'user+tag@example.com');
3742
+ await el.updateComplete;
3743
+ expect(getFilteredOptionValues(el)).to.eql(['user+tag@example.com']);
3744
+
3745
+ // Test combination with brackets, pipe and question mark
3746
+ await mimicUserTyping(el, 'value?[x]');
3747
+ await el.updateComplete;
3748
+ expect(getFilteredOptionValues(el)).to.eql(['test|value?[x]']);
3749
+
3750
+ // Test combination with dot, curly braces, pipe and backslash
3751
+ await mimicUserTyping(el, '.{txt|md}');
3752
+ await el.updateComplete;
3753
+ expect(getFilteredOptionValues(el)).to.eql(['file.{txt|md}\\n']);
3754
+ });
3755
+ });
3651
3756
  });
@@ -352,11 +352,14 @@ const FormGroupMixinImplementation = superclass =>
352
352
  this.formElements._keys().forEach(name => {
353
353
  const elem = this.formElements[name];
354
354
  if (elem instanceof FormControlsCollection) {
355
+ // @ts-ignore - dynamic property access
355
356
  result[name] = elem.filter(el => _filterFn(el, property)).map(el => el[property]);
356
357
  } else if (_filterFn(elem, property)) {
357
358
  if (typeof elem._getFromAllFormElements === 'function') {
359
+ // @ts-ignore - dynamic property access
358
360
  result[name] = elem._getFromAllFormElements(property);
359
361
  } else {
362
+ // @ts-ignore - dynamic property access
360
363
  result[name] = elem[property];
361
364
  }
362
365
  }
@@ -386,6 +389,7 @@ const FormGroupMixinImplementation = superclass =>
386
389
  if (Array.isArray(this.formElements[name])) {
387
390
  this.formElements[name].forEach(
388
391
  (/** @type {FormControl} */ el, /** @type {number} */ index) => {
392
+ // @ts-ignore - dynamic property access
389
393
  el[property] = values[name][index]; // eslint-disable-line no-param-reassign
390
394
  },
391
395
  );
@@ -393,6 +397,7 @@ const FormGroupMixinImplementation = superclass =>
393
397
  if (this.formElements[name]) {
394
398
  this.formElements[name][property] = values[name];
395
399
  } else {
400
+ // @ts-ignore - dynamic property access
396
401
  this.__pendingValues[property][name] = values[name];
397
402
  }
398
403
  });
@@ -406,6 +411,7 @@ const FormGroupMixinImplementation = superclass =>
406
411
  _anyFormElementHas(property) {
407
412
  return Object.keys(this.formElements).some(name => {
408
413
  if (Array.isArray(this.formElements[name])) {
414
+ // @ts-ignore - dynamic property access
409
415
  return this.formElements[name].some((/** @type {FormControl} */ el) => !!el[property]);
410
416
  }
411
417
  return !!this.formElements[name][property];
@@ -436,6 +442,7 @@ const FormGroupMixinImplementation = superclass =>
436
442
  _everyFormElementHas(property) {
437
443
  return Object.keys(this.formElements).every(name => {
438
444
  if (Array.isArray(this.formElements[name])) {
445
+ // @ts-ignore - dynamic property access
439
446
  return this.formElements[name].every((/** @type {FormControl} */ el) => !!el[property]);
440
447
  }
441
448
  return !!this.formElements[name][property];
@@ -162,15 +162,21 @@ const FormRegistrarMixinImplementation = superclass =>
162
162
  }
163
163
 
164
164
  if (name.substr(-2) === '[]') {
165
+ // @ts-ignore - dynamic named access to form elements
165
166
  if (!Array.isArray(this.formElements[name])) {
167
+ // @ts-ignore
166
168
  this.formElements[name] = new FormControlsCollection();
167
169
  }
168
170
  if (indexToInsertAt > 0) {
171
+ // @ts-ignore
169
172
  this.formElements[name].splice(indexToInsertAt, 0, child);
170
173
  } else {
174
+ // @ts-ignore
171
175
  this.formElements[name].push(child);
172
176
  }
177
+ // @ts-ignore
173
178
  } else if (!this.formElements[name]) {
179
+ // @ts-ignore
174
180
  this.formElements[name] = child;
175
181
  } else {
176
182
  console.info('Error Node:', child); // eslint-disable-line no-console
@@ -194,12 +200,17 @@ const FormRegistrarMixinImplementation = superclass =>
194
200
  // 2. Handle name based object keys
195
201
  if (this._isFormOrFieldset) {
196
202
  const { name } = child; // FIXME: <-- ElementWithParentFormGroup should become LionFieldWithParentFormGroup so that "name" exists
203
+ // @ts-ignore - dynamic named access to form elements
197
204
  if (name.substr(-2) === '[]' && this.formElements[name]) {
205
+ // @ts-ignore
198
206
  const idx = this.formElements[name].indexOf(child);
199
207
  if (idx > -1) {
208
+ // @ts-ignore
200
209
  this.formElements[name].splice(idx, 1);
201
210
  }
211
+ // @ts-ignore
202
212
  } else if (this.formElements[name]) {
213
+ // @ts-ignore
203
214
  delete this.formElements[name];
204
215
  }
205
216
  }
@@ -153,6 +153,7 @@ describe('FormControlMixin', () => {
153
153
  el.shadowRoot?.querySelector('.form-field__label'),
154
154
  );
155
155
  Object.entries(expectedValues).forEach(([key, val]) => {
156
+ // @ts-ignore - dynamic style property access
156
157
  expect(labelStyle[key]).to.equal(val);
157
158
  });
158
159
  });
@@ -191,7 +191,9 @@ describe('Validator', () => {
191
191
  it('adds static ["_$isValidator$"] property as a marker to identify the Validator class across different lion versions (as instanceof cannot be used)', async () => {
192
192
  const myValidator = new Validator();
193
193
 
194
+ // @ts-ignore - static property access
194
195
  expect(myValidator.constructor['_$isValidator$']).to.exist;
196
+ // @ts-ignore - static property access
195
197
  expect(myValidator.constructor['_$isValidator$']).to.be.true;
196
198
  });
197
199
 
@@ -1554,11 +1554,13 @@ export function runValidateMixinSuite(customConfig) {
1554
1554
  // eslint-disable-next-line no-restricted-syntax
1555
1555
  for (const state of ['dirty', 'touched', 'prefilled', 'submitted']) {
1556
1556
  counter += 1;
1557
+ // @ts-ignore - test property access
1557
1558
  el[state] = false;
1558
1559
  // eslint-disable-next-line no-await-in-loop
1559
1560
  await el.updateComplete;
1560
1561
  expect(spy.callCount).to.equal(counter);
1561
1562
  counter += 1;
1563
+ // @ts-ignore - test property access
1562
1564
  el[state] = true;
1563
1565
  // eslint-disable-next-line no-await-in-loop
1564
1566
  await el.updateComplete;
@@ -714,6 +714,7 @@ export function runValidateMixinFeedbackPart() {
714
714
  const results = {
715
715
  'a-string-instead-of-bool': 'Msg based on enum output',
716
716
  };
717
+ // @ts-ignore - test data structure
717
718
  return results[/** @type {string} */ (outcome)];
718
719
  }
719
720
  }