@lion/ui 0.20.0-menu-system.0 → 0.21.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 (414) hide show
  1. package/calendar-suites.js +1 -0
  2. package/collapsible.js +0 -1
  3. package/components/button/src/LionButton.js +0 -4
  4. package/components/button/test-suites/LionButton.suite.js +0 -1
  5. package/components/calendar/src/LionCalendar.js +1 -3
  6. package/components/calendar/test/lion-calendar.test.js +67 -47
  7. package/components/calendar/test-suites/LionCalendar.suite.js +79 -0
  8. package/components/combobox/test/lion-combobox.test.js +0 -1
  9. package/components/form-core/src/FormatMixin.js +17 -7
  10. package/components/form-core/src/form-group/FormGroupMixin.js +0 -7
  11. package/components/form-core/src/registration/FormRegistrarMixin.js +0 -11
  12. package/components/form-core/test/FormControlMixin.test.js +0 -1
  13. package/components/form-core/test/FormatMixin.test.js +4 -1
  14. package/components/form-core/test/validate/Validator.test.js +0 -2
  15. package/components/form-core/test-helpers/mimicUserInput.js +1 -0
  16. package/components/form-core/test-suites/FormatMixin.suite.js +273 -79
  17. package/components/form-core/test-suites/ValidateMixin.suite.js +0 -2
  18. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +0 -1
  19. package/components/input/test/input-integrations.test.js +3 -2
  20. package/components/input/test/lion-input-integrations.test.js +2 -1
  21. package/components/input-amount/test/lion-input-amount-integrations.test.js +1 -1
  22. package/components/input-amount-dropdown/src/LionInputAmountDropdown.js +72 -11
  23. package/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.js +27 -0
  24. package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +60 -3
  25. package/components/input-date/test/lion-input-date-integrations.test.js +1 -1
  26. package/components/input-datepicker/src/LionInputDatepicker.js +4 -0
  27. package/components/input-datepicker/src/localizeNamespaceLoader.js +0 -1
  28. package/components/input-datepicker/test/lion-input-datepicker-integrations.test.js +1 -1
  29. package/components/input-datepicker/test/lion-input-datepicker.test.js +74 -9
  30. package/components/input-datepicker/test-suites/LionInputDatepicker.suite.js +35 -0
  31. package/components/input-email/src/LionInputEmail.js +2 -0
  32. package/components/input-email/test/lion-input-email-integrations.test.js +1 -1
  33. package/components/input-email/test/lion-input-email.test.js +6 -0
  34. package/components/input-file/src/validators.js +31 -1
  35. package/components/input-file/test/FileValidators.test.js +31 -0
  36. package/components/input-file/translations/bg.js +1 -0
  37. package/components/input-file/translations/cs.js +1 -0
  38. package/components/input-file/translations/de.js +2 -0
  39. package/components/input-file/translations/en.js +1 -0
  40. package/components/input-file/translations/es.js +1 -0
  41. package/components/input-file/translations/fr.js +1 -0
  42. package/components/input-file/translations/hu.js +1 -0
  43. package/components/input-file/translations/id.js +1 -0
  44. package/components/input-file/translations/it.js +1 -0
  45. package/components/input-file/translations/nl.js +1 -0
  46. package/components/input-file/translations/pl.js +1 -0
  47. package/components/input-file/translations/ro.js +1 -0
  48. package/components/input-file/translations/ru.js +1 -0
  49. package/components/input-file/translations/sk.js +1 -0
  50. package/components/input-file/translations/uk.js +1 -0
  51. package/components/input-file/translations/zh.js +1 -0
  52. package/components/input-iban/test/lion-input-iban-integrations.test.js +1 -1
  53. package/components/input-range/src/LionInputRange.js +51 -8
  54. package/components/input-range/test/lion-input-range.test.js +114 -0
  55. package/components/input-stepper/test-suites/lion-input-stepper.integration.suite.js +2 -2
  56. package/components/input-tel/src/LionInputTel.js +1 -1
  57. package/components/input-tel/test-suites/LionInputTel.suite.js +7 -0
  58. package/components/localize/test/date/formatDate.test.js +0 -1
  59. package/components/overlays/src/OverlayController.js +110 -278
  60. package/components/overlays/src/OverlayMixin.js +11 -58
  61. package/components/overlays/src/OverlaysManager.js +2 -2
  62. package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +41 -9
  63. package/components/overlays/src/utils/adopt-styles.js +2 -3
  64. package/components/overlays/src/utils/get-focusable-elements.js +0 -4
  65. package/components/overlays/src/utils/is-equal-config.js +6 -10
  66. package/components/overlays/test/OverlayController.test.js +14 -127
  67. package/components/overlays/test/utils-tests/is-equal-config.test.js +1 -1
  68. package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
  69. package/components/overlays/test-suites/WithHoverInteraction.suite.js +212 -0
  70. package/components/overlays/types/ArrowMixinTypes.ts +1 -3
  71. package/components/overlays/types/OverlayConfig.ts +5 -20
  72. package/components/overlays/types/OverlayMixinTypes.ts +0 -2
  73. package/components/select-rich/test/lion-select-rich.test.js +0 -3
  74. package/components/textarea/test/lion-textarea-integrations.test.js +2 -1
  75. package/components/tooltip/test/lion-tooltip.test.js +9 -1
  76. package/custom-elements.json +20629 -32907
  77. package/dist-types/components/button/src/LionButton.d.ts +0 -1
  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/calendar/test/lion-calendar.test.d.ts.map +1 -1
  82. package/dist-types/components/calendar/test-suites/LionCalendar.suite.d.ts +5 -0
  83. package/dist-types/components/calendar/test-suites/LionCalendar.suite.d.ts.map +1 -0
  84. package/dist-types/components/combobox/src/LionCombobox.d.ts +1 -1
  85. package/dist-types/components/dialog/src/LionDialog.d.ts +2 -6
  86. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  87. package/dist-types/components/form-core/src/FormatMixin.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-helpers/mimicUserInput.d.ts.map +1 -1
  91. package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts +58 -5
  92. package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts.map +1 -1
  93. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  94. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  95. package/dist-types/components/icon/src/LionIcon.d.ts +2 -2
  96. package/dist-types/components/input-amount-dropdown/src/LionInputAmountDropdown.d.ts +24 -6
  97. package/dist-types/components/input-amount-dropdown/src/LionInputAmountDropdown.d.ts.map +1 -1
  98. package/dist-types/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.d.ts +2 -0
  99. package/dist-types/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.d.ts.map +1 -0
  100. package/dist-types/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.d.ts.map +1 -1
  101. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +2 -1
  102. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
  103. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
  104. package/dist-types/components/input-datepicker/test/lion-input-datepicker.test.d.ts.map +1 -1
  105. package/dist-types/components/input-datepicker/test-suites/LionInputDatepicker.suite.d.ts +7 -0
  106. package/dist-types/components/input-datepicker/test-suites/LionInputDatepicker.suite.d.ts.map +1 -0
  107. package/dist-types/components/input-email/src/LionInputEmail.d.ts.map +1 -1
  108. package/dist-types/components/input-file/src/validators.d.ts +11 -0
  109. package/dist-types/components/input-file/src/validators.d.ts.map +1 -1
  110. package/dist-types/components/input-file/translations/bg-BG.d.ts +1 -0
  111. package/dist-types/components/input-file/translations/bg.d.ts +1 -0
  112. package/dist-types/components/input-file/translations/cs-CZ.d.ts +1 -0
  113. package/dist-types/components/input-file/translations/cs.d.ts +1 -0
  114. package/dist-types/components/input-file/translations/de-DE.d.ts +1 -0
  115. package/dist-types/components/input-file/translations/de.d.ts +1 -0
  116. package/dist-types/components/input-file/translations/en-AU.d.ts +1 -0
  117. package/dist-types/components/input-file/translations/en-GB.d.ts +1 -0
  118. package/dist-types/components/input-file/translations/en-PH.d.ts +1 -0
  119. package/dist-types/components/input-file/translations/en-US.d.ts +1 -0
  120. package/dist-types/components/input-file/translations/en.d.ts +1 -0
  121. package/dist-types/components/input-file/translations/es-ES.d.ts +1 -0
  122. package/dist-types/components/input-file/translations/es.d.ts +1 -0
  123. package/dist-types/components/input-file/translations/fr-BE.d.ts +1 -0
  124. package/dist-types/components/input-file/translations/fr-FR.d.ts +1 -0
  125. package/dist-types/components/input-file/translations/fr.d.ts +1 -0
  126. package/dist-types/components/input-file/translations/hu-HU.d.ts +1 -0
  127. package/dist-types/components/input-file/translations/hu.d.ts +1 -0
  128. package/dist-types/components/input-file/translations/id-ID.d.ts +1 -0
  129. package/dist-types/components/input-file/translations/id.d.ts +1 -0
  130. package/dist-types/components/input-file/translations/it-IT.d.ts +1 -0
  131. package/dist-types/components/input-file/translations/it.d.ts +1 -0
  132. package/dist-types/components/input-file/translations/nl-BE.d.ts +1 -0
  133. package/dist-types/components/input-file/translations/nl-NL.d.ts +1 -0
  134. package/dist-types/components/input-file/translations/nl.d.ts +1 -0
  135. package/dist-types/components/input-file/translations/pl-PL.d.ts +1 -0
  136. package/dist-types/components/input-file/translations/pl.d.ts +1 -0
  137. package/dist-types/components/input-file/translations/ro-RO.d.ts +1 -0
  138. package/dist-types/components/input-file/translations/ro.d.ts +1 -0
  139. package/dist-types/components/input-file/translations/ru-RU.d.ts +1 -0
  140. package/dist-types/components/input-file/translations/ru.d.ts +1 -0
  141. package/dist-types/components/input-file/translations/sk-SK.d.ts +1 -0
  142. package/dist-types/components/input-file/translations/sk.d.ts +1 -0
  143. package/dist-types/components/input-file/translations/uk-UA.d.ts +1 -0
  144. package/dist-types/components/input-file/translations/uk.d.ts +1 -0
  145. package/dist-types/components/input-file/translations/zh-CN.d.ts +1 -0
  146. package/dist-types/components/input-file/translations/zh.d.ts +1 -0
  147. package/dist-types/components/input-range/src/LionInputRange.d.ts +11 -0
  148. package/dist-types/components/input-range/src/LionInputRange.d.ts.map +1 -1
  149. package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
  150. package/dist-types/components/input-tel/test-suites/LionInputTel.suite.d.ts.map +1 -1
  151. package/dist-types/components/overlays/src/OverlayController.d.ts +12 -24
  152. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  153. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  154. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts.map +1 -1
  155. package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
  156. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  157. package/dist-types/components/overlays/test-suites/WithHoverInteraction.suite.d.ts +17 -0
  158. package/dist-types/components/overlays/test-suites/WithHoverInteraction.suite.d.ts.map +1 -0
  159. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  160. package/dist-types/components/overlays/types/OverlayConfig.d.ts +2 -12
  161. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  162. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +0 -1
  163. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  164. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +3 -11
  165. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  166. package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
  167. package/dist-types/components/tooltip/test/lion-tooltip.test.d.ts.map +1 -1
  168. package/dist-types/exports/calendar-suites.d.ts +2 -0
  169. package/dist-types/exports/calendar-suites.d.ts.map +1 -0
  170. package/dist-types/exports/input-datepicker-suites.d.ts +2 -0
  171. package/dist-types/exports/input-datepicker-suites.d.ts.map +1 -0
  172. package/dist-types/exports/input-file.d.ts +1 -1
  173. package/dist-types/exports/overlays-test-suites.d.ts +1 -0
  174. package/dist-types/exports/overlays.d.ts +0 -3
  175. package/dist-types/exports/overlays.d.ts.map +1 -1
  176. package/dist-types/tsconfig.tsbuildinfo +1 -1
  177. package/docs/components/checkbox-group/api-table.md +4 -2
  178. package/docs/components/checkbox-group/overview.md +2 -2
  179. package/docs/components/collapsible/overview.md +1 -1
  180. package/docs/components/combobox/api-table.md +8 -21
  181. package/docs/components/combobox/overview.md +1 -1
  182. package/docs/components/combobox/use-cases.md +1 -1
  183. package/docs/components/dialog/api-table.md +6 -31
  184. package/docs/components/dialog/overview.md +1 -1
  185. package/docs/components/fieldset/overview.md +5 -5
  186. package/docs/components/form/overview.md +3 -3
  187. package/docs/components/form/use-cases.md +2 -2
  188. package/docs/components/icon/use-cases.md +1 -1
  189. package/docs/components/input/api-table.md +2 -1
  190. package/docs/components/input/overview.md +1 -1
  191. package/docs/components/input-amount/api-table.md +2 -1
  192. package/docs/components/input-amount/overview.md +3 -3
  193. package/docs/components/input-amount-dropdown/api-table.md +3 -2
  194. package/docs/components/input-date/api-table.md +2 -1
  195. package/docs/components/input-date/overview.md +3 -3
  196. package/docs/components/input-datepicker/api-table.md +6 -22
  197. package/docs/components/input-datepicker/overview.md +5 -5
  198. package/docs/components/input-email/api-table.md +3 -2
  199. package/docs/components/input-email/overview.md +2 -2
  200. package/docs/components/input-file/api-table.md +2 -1
  201. package/docs/components/input-file/overview.md +1 -1
  202. package/docs/components/input-file/use-cases.md +18 -0
  203. package/docs/components/input-iban/api-table.md +2 -1
  204. package/docs/components/input-iban/overview.md +2 -2
  205. package/docs/components/input-range/api-table.md +7 -1
  206. package/docs/components/input-range/overview.md +2 -2
  207. package/docs/components/input-range/use-cases.md +14 -0
  208. package/docs/components/input-stepper/api-table.md +2 -1
  209. package/docs/components/input-stepper/overview.md +1 -1
  210. package/docs/components/input-tel/api-table.md +3 -2
  211. package/docs/components/input-tel/overview.md +1 -1
  212. package/docs/components/input-tel/use-cases.md +6 -6
  213. package/docs/components/input-tel-dropdown/api-table.md +3 -2
  214. package/docs/components/input-tel-dropdown/overview.md +1 -1
  215. package/docs/components/listbox/api-table.md +2 -1
  216. package/docs/components/listbox/use-cases.md +1 -1
  217. package/docs/components/radio-group/api-table.md +2 -1
  218. package/docs/components/radio-group/overview.md +3 -3
  219. package/docs/components/select/api-table.md +2 -1
  220. package/docs/components/select/use-cases.md +1 -1
  221. package/docs/components/select-rich/api-table.md +5 -21
  222. package/docs/components/select-rich/use-cases.md +2 -2
  223. package/docs/components/switch/api-table.md +2 -1
  224. package/docs/components/tabs/examples.md +1 -1
  225. package/docs/components/textarea/api-table.md +2 -1
  226. package/docs/components/tooltip/api-table.md +11 -36
  227. package/docs/components/tooltip/use-cases.md +34 -1
  228. package/docs/fundamentals/index.md +4 -4
  229. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  230. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  231. package/docs/fundamentals/rationales/accessibility.md +1 -1
  232. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  233. package/docs/fundamentals/systems/core/overview.md +1 -1
  234. package/docs/fundamentals/systems/form/api-table.md +2 -1
  235. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  236. package/docs/fundamentals/systems/form/model-value.md +1 -1
  237. package/docs/fundamentals/systems/form/overview.md +28 -28
  238. package/docs/fundamentals/systems/form/validate.md +2 -2
  239. package/docs/fundamentals/systems/localize/overview.md +4 -4
  240. package/docs/fundamentals/systems/overlays/api-table.md +34 -36
  241. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  242. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  243. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  244. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  245. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  246. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  247. package/docs/guides/how-to/create-a-form.md +4 -4
  248. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  249. package/docs/guides/how-to/index.md +1 -1
  250. package/docs/guides/index.md +8 -8
  251. package/docs/guides/principles/index.md +5 -5
  252. package/docs/guides/principles/styling.md +1 -1
  253. package/exports/calendar-suites.js +1 -0
  254. package/exports/collapsible.js +0 -1
  255. package/exports/input-datepicker-suites.js +1 -0
  256. package/exports/input-file.js +5 -1
  257. package/exports/overlays-test-suites.js +1 -0
  258. package/exports/overlays.js +0 -6
  259. package/input-datepicker-suites.js +1 -0
  260. package/input-file.js +5 -1
  261. package/overlays-test-suites.js +1 -0
  262. package/overlays.js +0 -6
  263. package/package.json +2 -2
  264. package/components/collapsible/src/DisclosureMixin.js +0 -313
  265. package/components/collapsible/test-suites/DisclosureMixin.suite.js +0 -30
  266. package/components/collapsible/types/DisclosureMixinTypes.ts +0 -48
  267. package/components/menu/CHANGELOG.md +0 -37
  268. package/components/menu/README.md +0 -335
  269. package/components/menu/index.js +0 -2
  270. package/components/menu/lion-menu-overlay.js +0 -3
  271. package/components/menu/lion-menu.js +0 -3
  272. package/components/menu/lion-spinbutton.js +0 -3
  273. package/components/menu/lion-toolbar.js +0 -3
  274. package/components/menu/lion-tree.js +0 -3
  275. package/components/menu/package.json +0 -46
  276. package/components/menu/requirements.temp.md +0 -12
  277. package/components/menu/src/InteractiveListMixin.js +0 -840
  278. package/components/menu/src/LionMenu.js +0 -250
  279. package/components/menu/src/LionMenuHybrid.js +0 -46
  280. package/components/menu/src/LionMenuOverlay.js +0 -155
  281. package/components/menu/src/LionSpinbutton.js +0 -213
  282. package/components/menu/src/LionToolbar.js +0 -94
  283. package/components/menu/src/LionTree.js +0 -52
  284. package/components/menu/src/MoreButtonMenuMixin.js +0 -278
  285. package/components/menu/src/MultiLevelListMixin.js +0 -311
  286. package/components/menu/src/utils/isInView.js +0 -26
  287. package/components/menu/src/utils/listItemInteractions.js +0 -124
  288. package/components/menu/test/InteractiveListMixin.test.js +0 -3
  289. package/components/menu/test/MoreButtonMenuMixin.test.js +0 -4
  290. package/components/menu/test/MultiLevelListMixin.test.js +0 -3
  291. package/components/menu/test/lion-menu-hybrid.test.js +0 -3
  292. package/components/menu/test/lion-menu.test.js +0 -11
  293. package/components/menu/test/lion-toolbar.test.js +0 -8
  294. package/components/menu/test/lion-tree.test.js +0 -7
  295. package/components/menu/test-helpers/mimicKeyPress.js +0 -9
  296. package/components/menu/test-suites/InteractiveListMixin.suite.js +0 -454
  297. package/components/menu/test-suites/LionMenu.suite.js +0 -113
  298. package/components/menu/test-suites/LionMenuHybrid.suite.js +0 -583
  299. package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +0 -372
  300. package/components/menu/test-suites/MultiLevelListMixin.suite.js +0 -303
  301. package/components/menu/types/InteractiveListMixinTypes.d.ts +0 -84
  302. package/components/navigation-bar/README.md +0 -1
  303. package/components/navigation-bar/src/LionNavigationBar.js +0 -439
  304. package/components/navigation-bar/src/types.js +0 -41
  305. package/components/overlays/NEXT.md +0 -49
  306. package/components/overlays/test/withHoverInteraction.test.js +0 -90
  307. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +0 -3
  308. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +0 -1
  309. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts +0 -2
  310. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts.map +0 -1
  311. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +0 -24
  312. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +0 -1
  313. package/dist-types/components/menu/index.d.ts +0 -3
  314. package/dist-types/components/menu/index.d.ts.map +0 -1
  315. package/dist-types/components/menu/lion-menu-overlay.d.ts +0 -2
  316. package/dist-types/components/menu/lion-menu-overlay.d.ts.map +0 -1
  317. package/dist-types/components/menu/lion-menu.d.ts +0 -2
  318. package/dist-types/components/menu/lion-menu.d.ts.map +0 -1
  319. package/dist-types/components/menu/lion-spinbutton.d.ts +0 -2
  320. package/dist-types/components/menu/lion-spinbutton.d.ts.map +0 -1
  321. package/dist-types/components/menu/lion-toolbar.d.ts +0 -2
  322. package/dist-types/components/menu/lion-toolbar.d.ts.map +0 -1
  323. package/dist-types/components/menu/lion-tree.d.ts +0 -2
  324. package/dist-types/components/menu/lion-tree.d.ts.map +0 -1
  325. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +0 -617
  326. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +0 -1
  327. package/dist-types/components/menu/src/LionMenu.d.ts +0 -635
  328. package/dist-types/components/menu/src/LionMenu.d.ts.map +0 -1
  329. package/dist-types/components/menu/src/LionMenuHybrid.d.ts +0 -19
  330. package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +0 -1
  331. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +0 -1015
  332. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +0 -1
  333. package/dist-types/components/menu/src/LionSpinbutton.d.ts +0 -58
  334. package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +0 -1
  335. package/dist-types/components/menu/src/LionToolbar.d.ts +0 -8
  336. package/dist-types/components/menu/src/LionToolbar.d.ts.map +0 -1
  337. package/dist-types/components/menu/src/LionTree.d.ts +0 -447
  338. package/dist-types/components/menu/src/LionTree.d.ts.map +0 -1
  339. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +0 -39
  340. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +0 -1
  341. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +0 -503
  342. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +0 -1
  343. package/dist-types/components/menu/src/utils/isInView.d.ts +0 -9
  344. package/dist-types/components/menu/src/utils/isInView.d.ts.map +0 -1
  345. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +0 -48
  346. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +0 -1
  347. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts +0 -2
  348. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts.map +0 -1
  349. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts +0 -2
  350. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts.map +0 -1
  351. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts +0 -2
  352. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts.map +0 -1
  353. package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts +0 -2
  354. package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts.map +0 -1
  355. package/dist-types/components/menu/test/lion-menu.test.d.ts +0 -2
  356. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +0 -1
  357. package/dist-types/components/menu/test/lion-toolbar.test.d.ts +0 -2
  358. package/dist-types/components/menu/test/lion-toolbar.test.d.ts.map +0 -1
  359. package/dist-types/components/menu/test/lion-tree.test.d.ts +0 -2
  360. package/dist-types/components/menu/test/lion-tree.test.d.ts.map +0 -1
  361. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts +0 -7
  362. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts.map +0 -1
  363. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +0 -14
  364. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +0 -1
  365. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts +0 -9
  366. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +0 -1
  367. package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts +0 -5
  368. package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts.map +0 -1
  369. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +0 -14
  370. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +0 -1
  371. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +0 -11
  372. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +0 -1
  373. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +0 -238
  374. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +0 -1
  375. package/dist-types/components/navigation-bar/src/types.d.ts +0 -85
  376. package/dist-types/components/navigation-bar/src/types.d.ts.map +0 -1
  377. package/dist-types/components/overlays/test/withHoverInteraction.test.d.ts +0 -2
  378. package/dist-types/components/overlays/test/withHoverInteraction.test.d.ts.map +0 -1
  379. package/dist-types/exports/define/lion-item.d.ts +0 -2
  380. package/dist-types/exports/define/lion-item.d.ts.map +0 -1
  381. package/dist-types/exports/define/lion-menu-overlay.d.ts +0 -2
  382. package/dist-types/exports/define/lion-menu-overlay.d.ts.map +0 -1
  383. package/dist-types/exports/define/lion-menu.d.ts +0 -2
  384. package/dist-types/exports/define/lion-menu.d.ts.map +0 -1
  385. package/dist-types/exports/define/lion-navigation-bar.d.ts +0 -2
  386. package/dist-types/exports/define/lion-navigation-bar.d.ts.map +0 -1
  387. package/dist-types/exports/define/lion-toolbar.d.ts +0 -2
  388. package/dist-types/exports/define/lion-toolbar.d.ts.map +0 -1
  389. package/dist-types/exports/define/lion-tree.d.ts +0 -2
  390. package/dist-types/exports/define/lion-tree.d.ts.map +0 -1
  391. package/dist-types/exports/menu-test-suites.d.ts +0 -4
  392. package/dist-types/exports/menu-test-suites.d.ts.map +0 -1
  393. package/dist-types/exports/menu.d.ts +0 -7
  394. package/dist-types/exports/menu.d.ts.map +0 -1
  395. package/dist-types/exports/navigation-bar.d.ts +0 -2
  396. package/dist-types/exports/navigation-bar.d.ts.map +0 -1
  397. package/docs/components/menu/api-table.md +0 -460
  398. package/docs/components/menu/applyMenuDemoStyles.js +0 -173
  399. package/docs/components/menu/extensions.md +0 -262
  400. package/docs/components/menu/index.md +0 -13
  401. package/docs/components/menu/overview.md +0 -422
  402. package/docs/components/menu/use-cases.md +0 -77
  403. package/exports/define/lion-item.js +0 -3
  404. package/exports/define/lion-menu-overlay.js +0 -3
  405. package/exports/define/lion-menu.js +0 -3
  406. package/exports/define/lion-navigation-bar.js +0 -3
  407. package/exports/define/lion-toolbar.js +0 -3
  408. package/exports/define/lion-tree.js +0 -3
  409. package/exports/menu-test-suites.js +0 -4
  410. package/exports/menu.js +0 -7
  411. package/exports/navigation-bar.js +0 -1
  412. package/menu-test-suites.js +0 -4
  413. package/menu.js +0 -7
  414. package/navigation-bar.js +0 -1
@@ -1,9 +1,9 @@
1
- import { LitElement } from 'lit';
1
+ import { getFormControlMembers, mimicUserInput } from '@lion/ui/form-core-test-helpers.js';
2
+ import { FormatMixin, Unparseable, Validator } from '@lion/ui/form-core.js';
2
3
  import { parseDate } from '@lion/ui/localize-no-side-effects.js';
3
4
  import { aTimeout, defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
5
+ import { LitElement } from 'lit';
4
6
  import sinon from 'sinon';
5
- import { Unparseable, Validator, FormatMixin } from '@lion/ui/form-core.js';
6
- import { getFormControlMembers, mimicUserInput } from '@lion/ui/form-core-test-helpers.js';
7
7
 
8
8
  const isLionInputStepper = (/** @type {FormatClass} */ el) => 'valueTextMapping' in el;
9
9
 
@@ -36,56 +36,225 @@ class FormatClass extends FormatMixin(LitElement) {
36
36
  }
37
37
 
38
38
  /**
39
- * @param {{tagString?: string, modelValueType?: modelValueType}} [customConfig]
39
+ * @typedef {object} FormatMixinSuiteConfig
40
+ * @property {string | null} [tagString] - Optional. Element tag name; if omitted, one will be auto-generated via defineCE()
41
+ * @property {string | null} [childTagString] - Optional. Not currently used
42
+ * @property {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType - REQUIRED. The model value type for this component
43
+ * @property {(opts: { toggleValue: boolean, viewValue: boolean }) => any} [valueToggler] - Optional. Provide different test values for toggleValue=false vs toggleValue=true. If not provided, defaults will be generated based on modelValueType.
44
+ * @property {(el: FormatClass) => any} [getExpectedInitialModelValue] - Optional. Expected initial modelValue state when element is created without a value. If not provided, defaults will be generated based on modelValueType.
45
+ * @property {(el: FormatClass) => any} [getExpectedInitialFormattedValue] - Optional. Expected initial formattedValue state when element is created without a value. If not provided, defaults will be generated based on modelValueType.
46
+ * @property {(el: FormatClass) => any} [getExpectedInitialSerializedValue] - Optional. Expected initial serializedValue state when element is created without a value. If not provided, defaults will be generated based on modelValueType.
47
+ * @property {(el: FormatClass) => any} [getExpectedModelValueForEmptyInputNode] - Optional. Expected modelValue after user clears the input node value. Defaults to empty string.
48
+ * @property {(value: string, opts?: any) => any} [parser] - Optional. Parser override used by tests. When provided, it is applied before connectedCallback so fallback init sync uses it.
49
+ * @property {number} [valueChangeCounterOffset] - Optional. Offset for model-value-changed event counter. Use 0 for most types, 1 for Date types where parseDate() creates new objects. If not provided, defaults will be generated based on modelValueType.
50
+ */
51
+
52
+ /**
53
+ * Creates default valueToggler based on modelValueType for backwards compatibility
54
+ * @param {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
55
+ * @returns {(opts: { toggleValue: boolean, viewValue: boolean }) => any}
56
+ */
57
+ function createDefaultValueToggler(modelValueType) {
58
+ if (modelValueType === String) {
59
+ return ({ toggleValue }) => (!toggleValue ? 'test-value-1' : 'test-value-2');
60
+ }
61
+ if (modelValueType === 'iban') {
62
+ return ({ toggleValue }) => (!toggleValue ? 'NL20INGB0001234567' : 'NL91ABNA0417164300');
63
+ }
64
+ if (modelValueType === 'email') {
65
+ return ({ toggleValue }) => (!toggleValue ? 'test@example.com' : 'user@test.org');
66
+ }
67
+ if (modelValueType === Number) {
68
+ return ({ toggleValue, viewValue }) => {
69
+ if (viewValue) {
70
+ return !toggleValue ? '100' : '200';
71
+ }
72
+ return !toggleValue ? 100 : 200;
73
+ };
74
+ }
75
+ if (modelValueType === Date) {
76
+ return ({ toggleValue, viewValue }) => {
77
+ if (viewValue) {
78
+ return !toggleValue ? '01/01/2020' : '02/02/2021';
79
+ }
80
+ return !toggleValue ? parseDate('01/01/2020') : parseDate('02/02/2021');
81
+ };
82
+ }
83
+ if (modelValueType === Object) {
84
+ return ({ toggleValue, viewValue }) => {
85
+ if (viewValue) {
86
+ return !toggleValue ? '{"value": 1}' : '{"value": 2}';
87
+ }
88
+ return !toggleValue ? { value: 1 } : { value: 2 };
89
+ };
90
+ }
91
+ if (modelValueType === Boolean) {
92
+ return ({ toggleValue }) => !toggleValue;
93
+ }
94
+ if (modelValueType === Array) {
95
+ return ({ toggleValue, viewValue }) => {
96
+ if (viewValue) {
97
+ return !toggleValue ? '[1]' : '[2]';
98
+ }
99
+ return !toggleValue ? [1] : [2];
100
+ };
101
+ }
102
+ // Fallback for unknown types
103
+ return ({ toggleValue }) => (!toggleValue ? 'test-value-1' : 'test-value-2');
104
+ }
105
+
106
+ /**
107
+ * Creates default getExpectedInitialModelValue based on modelValueType
108
+ * @param {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
109
+ * @returns {() => any}
110
+ */
111
+ function createDefaultGetExpectedInitialModelValue(modelValueType) {
112
+ if (modelValueType === Boolean) {
113
+ return () => false;
114
+ }
115
+ if (modelValueType === Object) {
116
+ return () => ({});
117
+ }
118
+ if (modelValueType === Array) {
119
+ return () => [];
120
+ }
121
+ // String, Number, Date, 'iban', 'email' all default to empty string
122
+ return () => '';
123
+ }
124
+
125
+ /**
126
+ * Creates default getExpectedInitialFormattedValue based on modelValueType
127
+ * @param {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
128
+ * @returns {() => any}
129
+ */
130
+ function createDefaultGetExpectedInitialFormattedValue(modelValueType) {
131
+ // Same as modelValue for default case
132
+ return createDefaultGetExpectedInitialModelValue(modelValueType);
133
+ }
134
+
135
+ /**
136
+ * Creates default getExpectedInitialSerializedValue based on modelValueType
137
+ * @param {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
138
+ * @returns {() => any}
139
+ */
140
+ function createDefaultGetExpectedInitialSerializedValue(modelValueType) {
141
+ // Same as modelValue for default case
142
+ return createDefaultGetExpectedInitialModelValue(modelValueType);
143
+ }
144
+
145
+ /**
146
+ * Creates default valueChangeCounterOffset based on modelValueType
147
+ * @param {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
148
+ * @returns {number}
149
+ */
150
+ function createDefaultValueChangeCounterOffset(modelValueType) {
151
+ // Date types need offset of 1 because parseDate creates new objects
152
+ if (modelValueType === Date) {
153
+ return 1;
154
+ }
155
+ return 0;
156
+ }
157
+
158
+ /**
159
+ * @param {FormatMixinSuiteConfig} [customConfig]
40
160
  */
41
161
  export function runFormatMixinSuite(customConfig) {
42
162
  const cfg = {
43
- tagString: null,
44
- childTagString: null,
45
- modelValueType: String,
46
163
  ...customConfig,
47
164
  };
48
165
 
166
+ // Validate that modelValueType is provided (required for generating defaults)
167
+ if (!cfg.modelValueType) {
168
+ throw new Error(
169
+ 'FormatMixinSuite: modelValueType is REQUIRED in config. ' +
170
+ 'Provide the model value type for this component (e.g., String, Number, Date, Object, Boolean, Array, "iban", "email").',
171
+ );
172
+ }
173
+
174
+ // Use provided values or generate defaults based on modelValueType
175
+ const valueToggler = cfg.valueToggler || createDefaultValueToggler(cfg.modelValueType);
176
+ const getExpectedInitialModelValue =
177
+ cfg.getExpectedInitialModelValue ||
178
+ createDefaultGetExpectedInitialModelValue(cfg.modelValueType);
179
+ const getExpectedInitialFormattedValue =
180
+ cfg.getExpectedInitialFormattedValue ||
181
+ createDefaultGetExpectedInitialFormattedValue(cfg.modelValueType);
182
+ const getExpectedInitialSerializedValue =
183
+ cfg.getExpectedInitialSerializedValue ||
184
+ createDefaultGetExpectedInitialSerializedValue(cfg.modelValueType);
185
+ const getExpectedModelValueForEmptyInputNode =
186
+ cfg.getExpectedModelValueForEmptyInputNode || (() => '');
187
+ const defaultParser = (/** @type {string} */ value) => value.replace('foo: ', '');
188
+ const parser = cfg.parser || defaultParser;
189
+ const valueChangeCounterOffset =
190
+ cfg.valueChangeCounterOffset !== undefined
191
+ ? cfg.valueChangeCounterOffset
192
+ : createDefaultValueChangeCounterOffset(cfg.modelValueType);
193
+
49
194
  /**
50
- * Mocks a value for you based on the data type
51
- * Optionally toggles you a different value
52
- * for needing to mimic a value-change.
195
+ * Generates test values by delegating to the component's valueToggler function.
196
+ * The suite does not make assumptions about value types or structures.
197
+ * All value generation is the responsibility of the consuming component.
198
+ *
199
+ * @param {object} [opts={}]
200
+ * @returns {any}
53
201
  */
54
202
  function generateValueBasedOnType(opts = {}) {
55
- const options = { type: cfg.modelValueType, toggleValue: false, viewValue: false, ...opts };
56
-
57
- switch (options.type) {
58
- case Number:
59
- return !options.toggleValue ? '123' : '456';
60
- case Date:
61
- // viewValue instead of modelValue, since a Date object is unparseable.
62
- // Note: this viewValue needs to point to the same date as the
63
- // default returned modelValue.
64
- if (options.viewValue) {
65
- return !options.toggleValue ? '5-5-2005' : '10-10-2010';
66
- }
67
- return !options.toggleValue ? parseDate('5-5-2005') : parseDate('10-10-2010');
68
- case Array:
69
- return !options.toggleValue ? ['foo', 'bar'] : ['baz', 'yay'];
70
- case Object:
71
- return !options.toggleValue ? { foo: 'bar' } : { bar: 'foo' };
72
- case Boolean:
73
- return !options.toggleValue;
74
- case 'email':
75
- return !options.toggleValue ? 'some-user@ing.com' : 'another-user@ing.com';
76
- case 'iban':
77
- return !options.toggleValue ? 'SE3550000000054910000003' : 'CH9300762011623852957';
78
- default:
79
- return !options.toggleValue ? 'foo' : 'bar';
203
+ const options = {
204
+ toggleValue: false,
205
+ viewValue: false,
206
+ ...opts,
207
+ };
208
+
209
+ // Always delegate to the component's valueToggler (required in config)
210
+ return valueToggler(options);
211
+ }
212
+
213
+ /**
214
+ * @param {FormatClass} el
215
+ */
216
+ function generateExpectedInitialModelValue(el) {
217
+ return getExpectedInitialModelValue(el);
218
+ }
219
+
220
+ /**
221
+ * @param {FormatClass} el
222
+ */
223
+ function generateExpectedInitialFormattedValue(el) {
224
+ return getExpectedInitialFormattedValue(el);
225
+ }
226
+
227
+ /**
228
+ * @param {FormatClass} el
229
+ */
230
+ function generateExpectedInitialSerializedValue(el) {
231
+ return getExpectedInitialSerializedValue(el);
232
+ }
233
+
234
+ /**
235
+ * @param {FormatClass} el
236
+ */
237
+ function generateExpectedModelValueForEmptyInputNode(el) {
238
+ return getExpectedModelValueForEmptyInputNode(el);
239
+ }
240
+
241
+ /**
242
+ * @param {any} actual
243
+ * @param {any} expected
244
+ * @param {string} message
245
+ */
246
+ function expectValue(actual, expected, message) {
247
+ if (typeof expected === 'object' && expected !== null) {
248
+ expect(actual).to.deep.equal(expected, message);
249
+ return;
80
250
  }
251
+ expect(actual).to.equal(expected, message);
81
252
  }
82
253
 
83
254
  describe('FormatMixin', async () => {
84
255
  /** @type {{_$litStatic$: any}} */
85
256
  let tag;
86
257
  /** @type {FormatClass} */
87
- let nonFormat;
88
- /** @type {FormatClass} */
89
258
  let fooFormat;
90
259
 
91
260
  before(async () => {
@@ -94,21 +263,10 @@ export function runFormatMixinSuite(customConfig) {
94
263
  }
95
264
  tag = unsafeStatic(cfg.tagString);
96
265
 
97
- nonFormat = await fixture(html`
98
- <${tag}
99
- .formatter="${/** @param {?} v */ v => v}"
100
- .parser="${/** @param {string} v */ v => v}"
101
- .serializer="${/** @param {?} v */ v => v}"
102
- .deserializer="${/** @param {string} v */ v => v}"
103
- >
104
- <input slot="input">
105
- </${tag}>
106
- `);
107
-
108
266
  fooFormat = await fixture(html`
109
267
  <${tag}
110
268
  .formatter="${/** @param {string} value */ value => `foo: ${value}`}"
111
- .parser="${/** @param {string} value */ value => value.replace('foo: ', '')}"
269
+ .parser="${parser}"
112
270
  .serializer="${/** @param {string} value */ value => `[foo] ${value}`}"
113
271
  .deserializer="${/** @param {string} value */ value => value.replace('[foo] ', '')}"
114
272
  >
@@ -118,14 +276,41 @@ export function runFormatMixinSuite(customConfig) {
118
276
  });
119
277
 
120
278
  it('has modelValue, formattedValue and serializedValue which are computed synchronously', async () => {
121
- expect(nonFormat.modelValue).to.equal('', 'modelValue initially');
122
- expect(nonFormat.formattedValue).to.equal('', 'formattedValue initially');
123
- expect(nonFormat.serializedValue).to.equal('', 'serializedValue initially');
279
+ const nonFormat = /** @type {FormatClass} */ (
280
+ await fixture(html`
281
+ <${tag}
282
+ .formatter="${/** @param {?} v */ v => v}"
283
+ .parser="${/** @param {string} v */ v => v}"
284
+ .serializer="${/** @param {?} v */ v => v}"
285
+ .deserializer="${/** @param {string} v */ v => v}"
286
+ >
287
+ <input slot="input">
288
+ </${tag}>
289
+ `)
290
+ );
291
+ await nonFormat.updateComplete;
292
+
293
+ expectValue(
294
+ nonFormat.modelValue,
295
+ generateExpectedInitialModelValue(nonFormat),
296
+ 'modelValue initially',
297
+ );
298
+ expectValue(
299
+ nonFormat.formattedValue,
300
+ generateExpectedInitialFormattedValue(nonFormat),
301
+ 'formattedValue initially',
302
+ );
303
+ expectValue(
304
+ nonFormat.serializedValue,
305
+ generateExpectedInitialSerializedValue(nonFormat),
306
+ 'serializedValue initially',
307
+ );
308
+
124
309
  const generatedValue = generateValueBasedOnType();
125
310
  nonFormat.modelValue = generatedValue;
126
- expect(nonFormat.modelValue).to.equal(generatedValue, 'modelValue as provided');
127
- expect(nonFormat.formattedValue).to.equal(generatedValue, 'formattedValue synchronized');
128
- expect(nonFormat.serializedValue).to.equal(generatedValue, 'serializedValue synchronized');
311
+ expectValue(nonFormat.modelValue, generatedValue, 'modelValue as provided');
312
+ expectValue(nonFormat.formattedValue, generatedValue, 'formattedValue synchronized');
313
+ expectValue(nonFormat.serializedValue, generatedValue, 'serializedValue synchronized');
129
314
  });
130
315
 
131
316
  /**
@@ -145,15 +330,18 @@ export function runFormatMixinSuite(customConfig) {
145
330
  isTriggeredByUser = /** @type {CustomEvent} */ (event).detail.isTriggeredByUser;
146
331
  });
147
332
 
148
- el.modelValue = 'one';
333
+ const valueOne = generateValueBasedOnType();
334
+ const valueTwo = generateValueBasedOnType({ toggleValue: true });
335
+
336
+ el.modelValue = valueOne;
149
337
  expect(counter).to.equal(1);
150
338
  expect(isTriggeredByUser).to.be.false;
151
339
 
152
340
  // no change means no event
153
- el.modelValue = 'one';
341
+ el.modelValue = valueOne;
154
342
  expect(counter).to.equal(1);
155
343
 
156
- el.modelValue = 'two';
344
+ el.modelValue = valueTwo;
157
345
  expect(counter).to.equal(2);
158
346
  });
159
347
 
@@ -172,18 +360,14 @@ export function runFormatMixinSuite(customConfig) {
172
360
  },
173
361
  );
174
362
 
175
- mimicUserInput(formatEl, generateValueBasedOnType());
363
+ mimicUserInput(formatEl, generateValueBasedOnType({ viewValue: true }));
176
364
  expect(counter).to.equal(1);
177
365
  expect(isTriggeredByUser).to.be.true;
178
366
 
179
- // Counter offset +1 for Date because parseDate created a new Date object
180
- // when the user changes the value.
181
- // This will result in a model-value-changed trigger even if the user value was the same
182
- // TODO: a proper solution would be to add `hasChanged` to input-date, like isSameDate()
183
- // from calendar utils
184
- const counterOffset = cfg.modelValueType === Date ? 1 : 0;
367
+ // All value comparison logic is the responsibility of consuming components
368
+ const counterOffset = valueChangeCounterOffset;
185
369
 
186
- mimicUserInput(formatEl, generateValueBasedOnType());
370
+ mimicUserInput(formatEl, generateValueBasedOnType({ viewValue: true }));
187
371
  expect(counter).to.equal(1 + counterOffset);
188
372
 
189
373
  mimicUserInput(formatEl, generateValueBasedOnType({ toggleValue: true }));
@@ -197,7 +381,7 @@ export function runFormatMixinSuite(customConfig) {
197
381
  <${tag}
198
382
  value="string"
199
383
  .formatter=${/** @param {string} value */ value => `foo: ${value}`}
200
- .parser=${/** @param {string} value */ value => value.replace('foo: ', '')}
384
+ .parser=${parser}
201
385
  .serializer=${/** @param {string} value */ value => `[foo] ${value}`}
202
386
  .deserializer=${/** @param {string} value */ value => value.replace('[foo] ', '')}
203
387
  >
@@ -207,12 +391,14 @@ export function runFormatMixinSuite(customConfig) {
207
391
  );
208
392
  // Now check if the format/parse/serialize loop has been triggered
209
393
  await formatElem.updateComplete;
210
- expect(formatElem.formattedValue).to.equal('foo: string');
394
+ const expectedFormattedValue = `foo: ${formatElem.modelValue}`;
395
+ const expectedSerializedValue = `[foo] ${formatElem.modelValue}`;
211
396
 
212
- expect(formatElem._inputNode.value).to.equal('foo: string');
397
+ expect(formatElem.formattedValue).to.equal(expectedFormattedValue);
213
398
 
214
- expect(formatElem.serializedValue).to.equal('[foo] string');
215
- expect(formatElem.modelValue).to.equal('string');
399
+ expect(formatElem._inputNode.value).to.equal(expectedFormattedValue);
400
+
401
+ expect(formatElem.serializedValue).to.equal(expectedSerializedValue);
216
402
  });
217
403
 
218
404
  describe('Unparseable values', () => {
@@ -274,9 +460,11 @@ export function runFormatMixinSuite(customConfig) {
274
460
  );
275
461
  // This could happen when the user erases the input value
276
462
  mimicUserInput(el, '');
277
- // For backwards compatibility, we keep the modelValue an empty string here.
278
- // Undefined would be more appropriate 'conceptually', however
279
- expect(el.modelValue).to.equal('');
463
+ expectValue(
464
+ el.modelValue,
465
+ generateExpectedModelValueForEmptyInputNode(el),
466
+ 'modelValue after clearing input node value',
467
+ );
280
468
  });
281
469
  });
282
470
  });
@@ -399,6 +587,10 @@ export function runFormatMixinSuite(customConfig) {
399
587
 
400
588
  describe('Formatter', () => {
401
589
  it('only calls the formatter for valid values on `user-input-changed` ', async () => {
590
+ if (cfg.modelValueType === Object) {
591
+ return;
592
+ }
593
+
402
594
  const formatterSpy = sinon.spy(value => `foo: ${value}`);
403
595
 
404
596
  const generatedModelValue = generateValueBasedOnType();
@@ -619,13 +811,13 @@ export function runFormatMixinSuite(customConfig) {
619
811
  `)
620
812
  );
621
813
 
622
- expect(parserSpy.callCount).to.equal(1);
814
+ const initialParserCallCount = parserSpy.callCount;
623
815
  // This could happen for instance in a reset
624
816
  el.modelValue = undefined;
625
- expect(parserSpy.callCount).to.equal(1);
817
+ expect(parserSpy.callCount).to.equal(initialParserCallCount);
626
818
  // This could happen when the user erases the input value
627
819
  mimicUserInput(el, '');
628
- expect(parserSpy.callCount).to.equal(1);
820
+ expect(parserSpy.callCount).to.equal(initialParserCallCount);
629
821
  });
630
822
  });
631
823
 
@@ -649,17 +841,19 @@ export function runFormatMixinSuite(customConfig) {
649
841
 
650
842
  const { _inputNode } = getFormControlMembers(el);
651
843
 
652
- expect(preprocessorSpy.callCount).to.equal(1);
844
+ const initialPreprocessorCallCount = preprocessorSpy.callCount;
653
845
 
654
846
  const parserSpy = sinon.spy(el, 'parser');
655
847
  mimicUserInput(el, toBeCorrectedVal);
656
848
 
657
- expect(preprocessorSpy.callCount).to.equal(2);
849
+ expect(preprocessorSpy.callCount).to.equal(initialPreprocessorCallCount + 1);
658
850
  expect(parserSpy.lastCall.args[0]).to.equal(val);
659
851
  expect(_inputNode.value).to.equal(val);
660
852
  });
661
853
 
662
854
  it('does only calculate derived values as consequence of user input when preprocessed value is different from previous view value', async () => {
855
+ if (cfg.modelValueType === Object) return;
856
+
663
857
  const val = generateValueBasedOnType({ viewValue: true }) || 'init-value';
664
858
  if (typeof val !== 'string') return;
665
859
 
@@ -1554,13 +1554,11 @@ 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
1558
1557
  el[state] = false;
1559
1558
  // eslint-disable-next-line no-await-in-loop
1560
1559
  await el.updateComplete;
1561
1560
  expect(spy.callCount).to.equal(counter);
1562
1561
  counter += 1;
1563
- // @ts-ignore - test property access
1564
1562
  el[state] = true;
1565
1563
  // eslint-disable-next-line no-await-in-loop
1566
1564
  await el.updateComplete;
@@ -714,7 +714,6 @@ 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
718
717
  return results[/** @type {string} */ (outcome)];
719
718
  }
720
719
  }
@@ -1,9 +1,9 @@
1
- import { defineCE } from '@open-wc/testing';
2
1
  import {
3
- runInteractionStateMixinSuite,
4
2
  runFormatMixinSuite,
3
+ runInteractionStateMixinSuite,
5
4
  runNativeTextFieldMixinSuite,
6
5
  } from '@lion/ui/form-core-test-suites.js';
6
+ import { defineCE } from '@open-wc/testing';
7
7
 
8
8
  import { LionInput } from '@lion/ui/input.js';
9
9
 
@@ -26,6 +26,7 @@ describe('<lion-input> integrations', () => {
26
26
 
27
27
  runFormatMixinSuite({
28
28
  tagString: fieldTagString,
29
+ modelValueType: String,
29
30
  });
30
31
 
31
32
  runNativeTextFieldMixinSuite({
@@ -1,6 +1,6 @@
1
1
  import {
2
- runInteractionStateMixinSuite,
3
2
  runFormatMixinSuite,
3
+ runInteractionStateMixinSuite,
4
4
  } from '@lion/ui/form-core-test-suites.js';
5
5
 
6
6
  import '@lion/ui/define/lion-input.js';
@@ -14,5 +14,6 @@ describe('<lion-input> integrations', () => {
14
14
 
15
15
  runFormatMixinSuite({
16
16
  tagString,
17
+ modelValueType: String,
17
18
  });
18
19
  });
@@ -1,6 +1,6 @@
1
1
  import {
2
- runInteractionStateMixinSuite,
3
2
  runFormatMixinSuite,
3
+ runInteractionStateMixinSuite,
4
4
  } from '@lion/ui/form-core-test-suites.js';
5
5
 
6
6
  import '@lion/ui/define/lion-input-amount.js';
@@ -1,14 +1,31 @@
1
- import { html, css } from 'lit';
2
- import { ref, createRef } from 'lit/directives/ref.js';
1
+ import { css, html } from 'lit';
3
2
  import { ifDefined } from 'lit/directives/if-defined.js';
3
+ import { createRef, ref } from 'lit/directives/ref.js';
4
4
 
5
5
  import { LionInputAmount } from '@lion/ui/input-amount.js';
6
6
  import { currencyUtil } from './currencyUtil.js';
7
- import { parseAmount } from './parsers.js';
8
7
  import { formatAmount } from './formatters.js';
8
+ import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
9
+ import { parseAmount } from './parsers.js';
9
10
  import { deserializer, serializer } from './serializers.js';
10
11
  import { CurrencyAndAmount } from './validators.js';
11
- import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
12
+
13
+ /**
14
+ * @param {import('../types/index.js').AmountDropdownModelValue | undefined} newValue
15
+ * @param {import('../types/index.js').AmountDropdownModelValue | undefined} oldValue
16
+ * @returns {boolean}
17
+ */
18
+ const hasChangedAmountDropdownModelValue = (newValue, oldValue) => {
19
+ if (newValue === oldValue) {
20
+ return false;
21
+ }
22
+
23
+ if (!newValue || !oldValue || typeof newValue !== 'object' || typeof oldValue !== 'object') {
24
+ return newValue !== oldValue;
25
+ }
26
+
27
+ return newValue.currency !== oldValue.currency || !Object.is(newValue.amount, oldValue.amount);
28
+ };
12
29
 
13
30
  /**
14
31
  * Note: one could consider to implement LionInputAmountDropdown as a
@@ -56,11 +73,48 @@ export class LionInputAmountDropdown extends LionInputAmount {
56
73
  * @configure LitElement
57
74
  * @type {any}
58
75
  */
59
- static properties = {
60
- preferredCurrencies: { type: Array },
61
- allowedCurrencies: { type: Array },
62
- __dropdownSlot: { type: String },
63
- };
76
+ static get properties() {
77
+ return {
78
+ modelValue: {
79
+ type: Object,
80
+ attribute: false,
81
+ hasChanged: hasChangedAmountDropdownModelValue,
82
+ },
83
+ preferredCurrencies: { type: Array },
84
+ allowedCurrencies: { type: Array },
85
+ __dropdownSlot: { type: String },
86
+ };
87
+ }
88
+
89
+ /**
90
+ * The internal modelValue is a combination of the amount and the currency code. The amount is a number, the currency code is a string.
91
+ * @private
92
+ * @type {import('../types/index.js').AmountDropdownModelValue}
93
+ */
94
+ __modelValue;
95
+
96
+ /**
97
+ * For a FormControl to function properly, its modelValue, serializedValue and viewValue/formattedValue
98
+ * should always translate in two directions. This is expected by `_callParser` method. It guards for empty
99
+ * viewValues. As the viewValue (`.value`) only concerns the amount part and not the currency part in
100
+ * InputAmountDropdown, this contract is broken.
101
+ * Below, we compensate for this.
102
+ */
103
+ // @ts-expect-error - modelValue is overridden as an accessor but is defined as a property in parent class
104
+ set modelValue(value) {
105
+ if (value) {
106
+ this.__modelValue = /** @type {import('../types/index.js').AmountDropdownModelValue} */ (
107
+ value
108
+ );
109
+ // Below is needed because A1 and A2 in _callParser (FormatMixin) return values that are the wrong type.
110
+ } else {
111
+ this.__modelValue = { currency: this.currency, amount: '' };
112
+ }
113
+ }
114
+
115
+ get modelValue() {
116
+ return /** @type {import('../types/index.js').AmountDropdownModelValue} */ (this.__modelValue);
117
+ }
64
118
 
65
119
  static localizeNamespaces = [
66
120
  { 'lion-input-amount-dropdown': localizeNamespaceLoader },
@@ -274,6 +328,9 @@ export class LionInputAmountDropdown extends LionInputAmount {
274
328
 
275
329
  this.parser = parseAmount;
276
330
 
331
+ /** @type {import('../types/index.js').AmountDropdownModelValue} */
332
+ this.__modelValue = { currency: this.currency, amount: '' };
333
+
277
334
  /**
278
335
  * @param {import("../types/index.js").AmountDropdownModelValue} modelValue
279
336
  * @param {import('../../localize/types/LocalizeMixinTypes.js').FormatNumberOptions} [givenOptions] Locale Options
@@ -388,7 +445,8 @@ export class LionInputAmountDropdown extends LionInputAmount {
388
445
  * @protected
389
446
  */
390
447
  _initModelValueBasedOnDropdown() {
391
- if (!this._initialModelValue && !this.dirty) {
448
+ const { currency, amount } = this._initialModelValue || {};
449
+ if (!currency && !amount && !this.dirty) {
392
450
  this.__initializedCurrencyCode = this.currency;
393
451
  this._initialModelValue = { currency: this.currency };
394
452
  this.modelValue = this._initialModelValue;
@@ -515,7 +573,10 @@ export class LionInputAmountDropdown extends LionInputAmount {
515
573
  }
516
574
 
517
575
  // 2. Try to get the currency from user input
518
- if (this.modelValue?.currency && this.allowedCurrencies?.includes(this.modelValue?.currency)) {
576
+ if (
577
+ this.modelValue?.currency &&
578
+ this.allowedCurrencies?.includes(/** @type {CurrencyCode} */ (this.modelValue?.currency))
579
+ ) {
519
580
  this.currency = this.modelValue.currency;
520
581
  return;
521
582
  }