@lion/ui 0.23.0 → 0.24.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 (787) hide show
  1. package/README.md +50 -20
  2. package/components/accordion/src/LionAccordion.js +31 -42
  3. package/components/accordion/test/lion-accordion.test.js +108 -134
  4. package/components/button/src/LionButton.js +9 -12
  5. package/components/button/src/LionButtonReset.js +0 -5
  6. package/components/button/src/LionButtonSubmit.js +7 -12
  7. package/components/button/test/demos.screenshots-test.js +50 -11
  8. package/components/button/test/lion-button.test.js +0 -1
  9. package/components/button/test-suites/LionButton.suite.js +135 -145
  10. package/components/button/test-suites/LionButtonReset.suite.js +54 -72
  11. package/components/button/test-suites/LionButtonSubmit.suite.js +49 -68
  12. package/components/calendar/src/LionCalendar.js +151 -104
  13. package/components/calendar/src/calendarStyle.js +0 -1
  14. package/components/calendar/src/utils/createMonth.js +3 -4
  15. package/components/calendar/src/utils/createMultipleMonth.js +15 -7
  16. package/components/calendar/src/utils/createWeek.js +0 -2
  17. package/components/calendar/src/utils/dataTemplate.js +8 -4
  18. package/components/calendar/src/utils/dayTemplate.js +0 -6
  19. package/components/calendar/src/utils/getDayMonthYear.js +6 -2
  20. package/components/calendar/test/demos.screenshots-test.js +40 -9
  21. package/components/calendar/test/lion-calendar.test.js +171 -282
  22. package/components/calendar/test/utils/createMonth.test.js +61 -22
  23. package/components/calendar/test/utils/createMultipleMonth.test.js +14 -7
  24. package/components/calendar/test/utils/createWeek.test.js +51 -17
  25. package/components/calendar/test/utils/dataTemplate.test.js +3 -4
  26. package/components/calendar/test/utils/dayTemplate.test.js +106 -34
  27. package/components/calendar/test/utils/getFirstDayNextMonth.test.js +0 -1
  28. package/components/calendar/test/utils/getLastDayPreviousMonth.test.js +0 -1
  29. package/components/calendar/test/utils/isSameDate.test.js +0 -1
  30. package/components/calendar/test/utils/snapshots/monthTemplate_en-GB_Sunday_2018-12.js +1 -2
  31. package/components/calendar/test-helpers/CalendarObject.js +31 -62
  32. package/components/calendar/test-helpers/DayObject.js +7 -15
  33. package/components/calendar/test-suites/LionCalendar.suite.js +7 -9
  34. package/components/checkbox-group/src/LionCheckboxIndeterminate.js +17 -30
  35. package/components/checkbox-group/test/lion-checkbox-group-integrations.test.js +0 -1
  36. package/components/checkbox-group/test/lion-checkbox-group.test.js +21 -16
  37. package/components/checkbox-group/test/lion-checkbox-indeterminate-integrations.test.js +3 -3
  38. package/components/checkbox-group/test/lion-checkbox-integrations.test.js +3 -2
  39. package/components/checkbox-group/test/lion-checkbox.test.js +30 -16
  40. package/components/checkbox-group/test-suites/CheckboxIndeterminate.suite.js +147 -191
  41. package/components/collapsible/src/LionCollapsible.js +10 -15
  42. package/components/collapsible/test/lion-collapsible.test.js +4 -18
  43. package/components/combobox/src/LionCombobox.js +35 -53
  44. package/components/combobox/src/utils/makeMatchingTextBold.js +2 -5
  45. package/components/combobox/src/validators.js +0 -1
  46. package/components/combobox/test/lion-combobox-integrations.test.js +6 -6
  47. package/components/combobox/test/lion-combobox.test.js +576 -869
  48. package/components/combobox/test/validators.test.js +6 -13
  49. package/components/combobox/test-helpers/combobox-helpers.js +24 -11
  50. package/components/core/src/DisabledMixin.js +61 -66
  51. package/components/core/src/DisabledWithTabIndexMixin.js +76 -83
  52. package/components/core/src/EventTargetShim.js +1 -4
  53. package/components/core/src/ScopedElementsMixin.js +4 -15
  54. package/components/core/src/ScopedStylesController.js +1 -5
  55. package/components/core/src/SlotMixin.js +236 -239
  56. package/components/core/src/browserDetection.js +5 -12
  57. package/components/core/test/DisabledMixin.test.js +24 -39
  58. package/components/core/test/DisabledWithTabIndexMixin.test.js +21 -34
  59. package/components/core/test/EventTargetShim.test.js +0 -8
  60. package/components/core/test/ScopedElementsMixin.test.js +22 -38
  61. package/components/core/test/ScopedStylesController.test.js +11 -20
  62. package/components/core/test/SlotMixin.test.js +102 -154
  63. package/components/core/test-helpers/getCachedFixture.js +5 -11
  64. package/components/core/types/SlotMixinTypes.ts +8 -3
  65. package/components/dialog/src/LionDialog.js +4 -3
  66. package/components/dialog/test/lion-dialog.integration.test.js +10 -20
  67. package/components/dialog/test/lion-dialog.test.js +48 -62
  68. package/components/dialog/test-helpers/test-router.js +4 -6
  69. package/components/drawer/src/LionDrawer.js +18 -34
  70. package/components/drawer/src/drawerStyle.js +0 -1
  71. package/components/drawer/test/lion-drawer.test.js +1 -17
  72. package/components/fieldset/test/lion-fieldset.test.js +6 -4
  73. package/components/form/src/LionForm.js +18 -13
  74. package/components/form/test/lion-form.test.js +22 -52
  75. package/components/form-core/src/FocusMixin.js +172 -174
  76. package/components/form-core/src/FormControlMixin.js +811 -813
  77. package/components/form-core/src/FormatMixin.js +537 -537
  78. package/components/form-core/src/InteractionStateMixin.js +196 -183
  79. package/components/form-core/src/LionField.js +9 -5
  80. package/components/form-core/src/NativeTextFieldMixin.js +114 -116
  81. package/components/form-core/src/choice-group/ChoiceGroupMixin.js +322 -364
  82. package/components/form-core/src/choice-group/ChoiceInputMixin.js +306 -296
  83. package/components/form-core/src/choice-group/CustomChoiceGroupMixin.js +114 -139
  84. package/components/form-core/src/form-group/FormElementsHaveNoError.js +0 -2
  85. package/components/form-core/src/form-group/FormGroupMixin.js +551 -557
  86. package/components/form-core/src/registration/FormRegisteringMixin.js +72 -71
  87. package/components/form-core/src/registration/FormRegistrarMixin.js +201 -217
  88. package/components/form-core/src/registration/FormRegistrarPortalMixin.js +31 -37
  89. package/components/form-core/src/utils/SyncUpdatableMixin.js +106 -117
  90. package/components/form-core/src/utils/getAriaElementsInRightDomOrder.js +1 -2
  91. package/components/form-core/src/validate/LionValidationFeedback.js +12 -8
  92. package/components/form-core/src/validate/Unparseable.js +4 -2
  93. package/components/form-core/src/validate/ValidateMixin.js +829 -883
  94. package/components/form-core/src/validate/Validator.js +3 -6
  95. package/components/form-core/src/validate/resultValidators/DefaultSuccess.js +1 -2
  96. package/components/form-core/src/validate/validators/DateValidators.js +0 -5
  97. package/components/form-core/src/validate/validators/NumberValidators.js +1 -5
  98. package/components/form-core/src/validate/validators/Required.js +1 -1
  99. package/components/form-core/src/validate/validators/StringValidators.js +1 -8
  100. package/components/form-core/test/FocusMixin.test.js +96 -82
  101. package/components/form-core/test/FormControlMixin.test.js +120 -176
  102. package/components/form-core/test/FormRegistrationMixins.test.js +0 -2
  103. package/components/form-core/test/FormatMixin.test.js +0 -1
  104. package/components/form-core/test/InteractionStateMixin.test.js +0 -1
  105. package/components/form-core/test/NativeTextFieldMixin.test.js +0 -1
  106. package/components/form-core/test/choice-group/ChoiceGroupMixin.test.js +0 -1
  107. package/components/form-core/test/choice-group/ChoiceInputMixin.test.js +0 -1
  108. package/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.js +6 -8
  109. package/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.js +0 -3
  110. package/components/form-core/test/form-group/FormGroupMixin.test.js +0 -1
  111. package/components/form-core/test/lion-field.test.js +88 -98
  112. package/components/form-core/test/utils/SyncUpdatableMixin.test.js +51 -65
  113. package/components/form-core/test/utils/getAriaElementsInRightDomOrder.test.js +3 -3
  114. package/components/form-core/test/validate/DateValidators.test.js +5 -27
  115. package/components/form-core/test/validate/NumberValidators.test.js +4 -16
  116. package/components/form-core/test/validate/Required.test.js +8 -21
  117. package/components/form-core/test/validate/ResultValidator.test.js +1 -2
  118. package/components/form-core/test/validate/StringValidators.test.js +4 -35
  119. package/components/form-core/test/validate/ValidateMixin.test.js +0 -1
  120. package/components/form-core/test/validate/ValidateMixinFeedbackPart.test.js +0 -1
  121. package/components/form-core/test/validate/Validator.test.js +39 -34
  122. package/components/form-core/test/validate/lion-validation-feedback.test.js +81 -43
  123. package/components/form-core/test-helpers/ExampleValidators.js +0 -5
  124. package/components/form-core/test-helpers/getFormControlMembers.js +2 -2
  125. package/components/form-core/test-helpers/mimicUserInput.js +5 -1
  126. package/components/form-core/test-suites/FormRegistrationMixins.suite.js +65 -122
  127. package/components/form-core/test-suites/FormatMixin.suite.js +202 -227
  128. package/components/form-core/test-suites/InteractionStateMixin.suite.js +47 -60
  129. package/components/form-core/test-suites/NativeTextFieldMixin.suite.js +8 -11
  130. package/components/form-core/test-suites/ValidateMixin.suite.js +280 -359
  131. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +112 -163
  132. package/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js +185 -218
  133. package/components/form-core/test-suites/choice-group/ChoiceInputMixin.suite.js +116 -109
  134. package/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.js +36 -70
  135. package/components/form-core/test-suites/form-group/FormGroupMixin-input.suite.js +57 -65
  136. package/components/form-core/test-suites/form-group/FormGroupMixin.suite.js +664 -523
  137. package/components/form-core/translations/bg-BG.js +0 -1
  138. package/components/form-core/translations/cs-CZ.js +0 -1
  139. package/components/form-core/translations/de-DE.js +0 -1
  140. package/components/form-core/translations/en-AU.js +0 -1
  141. package/components/form-core/translations/en-GB.js +0 -1
  142. package/components/form-core/translations/en-US.js +0 -1
  143. package/components/form-core/translations/es-ES.js +0 -1
  144. package/components/form-core/translations/fr-BE.js +0 -1
  145. package/components/form-core/translations/fr-FR.js +0 -1
  146. package/components/form-core/translations/hu-HU.js +0 -1
  147. package/components/form-core/translations/it-IT.js +0 -1
  148. package/components/form-core/translations/nl-BE.js +0 -1
  149. package/components/form-core/translations/nl-NL.js +0 -1
  150. package/components/form-core/translations/pl-PL.js +0 -1
  151. package/components/form-core/translations/ro-RO.js +0 -1
  152. package/components/form-core/translations/ru-RU.js +0 -1
  153. package/components/form-core/translations/sk-SK.js +0 -1
  154. package/components/form-core/translations/tr-TR.js +0 -1
  155. package/components/form-core/translations/uk-UA.js +0 -1
  156. package/components/form-integrations/test/dialog-integrations.test.js +1 -4
  157. package/components/form-integrations/test/form-group-methods.test.js +28 -31
  158. package/components/form-integrations/test/form-integrations.test.js +27 -28
  159. package/components/form-integrations/test/form-validation-integrations.test.js +21 -29
  160. package/components/form-integrations/test/helpers/umbrella-form.js +3 -5
  161. package/components/form-integrations/test/model-value-consistency.test.js +75 -77
  162. package/components/form-integrations/test/model-value-event.test.js +10 -20
  163. package/components/helpers/src/SbActionLogger.js +13 -17
  164. package/components/helpers/src/SbLocaleSwitcher.js +5 -5
  165. package/components/helpers/src/sortEachDepth.js +0 -2
  166. package/components/helpers/test/renderLitAsNode.test.js +0 -4
  167. package/components/helpers/test/sb-action-logger.test.js +24 -55
  168. package/components/icon/src/IconManager.js +0 -2
  169. package/components/icon/src/LionIcon.js +2 -7
  170. package/components/icon/src/icons.js +0 -2
  171. package/components/icon/test/IconManager.test.js +0 -15
  172. package/components/icon/test/hammer.svg.js +3 -4
  173. package/components/icon/test/heart.svg.js +3 -4
  174. package/components/icon/test/lion-icon.test.js +14 -43
  175. package/components/input/src/LionInput.js +2 -8
  176. package/components/input/test/input-integrations.test.js +0 -5
  177. package/components/input/test/lion-input-integrations.test.js +0 -4
  178. package/components/input/test/lion-input.test.js +28 -58
  179. package/components/input/test-helpers/getInputMembers.js +2 -2
  180. package/components/input-amount/src/LionInputAmount.js +20 -20
  181. package/components/input-amount/src/formatters.js +0 -3
  182. package/components/input-amount/src/parsers.js +0 -3
  183. package/components/input-amount/test/formatters.test.js +24 -16
  184. package/components/input-amount/test/lion-input-amount-integrations.test.js +0 -4
  185. package/components/input-amount/test/lion-input-amount.test.js +123 -147
  186. package/components/input-amount/test/parsers.test.js +33 -17
  187. package/components/input-amount/test/preprocessors.test.js +0 -3
  188. package/components/input-amount-dropdown/src/LionInputAmountDropdown.js +49 -59
  189. package/components/input-amount-dropdown/src/currencyUtil.js +8 -7
  190. package/components/input-amount-dropdown/src/parsers.js +0 -1
  191. package/components/input-amount-dropdown/src/validators.js +0 -1
  192. package/components/input-amount-dropdown/test/LionInputAmountDropdown.test.js +34 -36
  193. package/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.js +18 -13
  194. package/components/input-amount-dropdown/test-helpers/mimicUserChangingDropdown.js +5 -1
  195. package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +132 -107
  196. package/components/input-date/src/LionInputDate.js +4 -3
  197. package/components/input-date/test/lion-input-date-integrations.test.js +0 -3
  198. package/components/input-date/test/lion-input-date.test.js +19 -32
  199. package/components/input-datepicker/src/LionInputDatepicker.js +17 -29
  200. package/components/input-datepicker/src/localizeNamespaceLoader.js +1 -2
  201. package/components/input-datepicker/test/lion-input-datepicker-integrations.test.js +0 -3
  202. package/components/input-datepicker/test/lion-input-datepicker.test.js +88 -153
  203. package/components/input-datepicker/test-helpers/DatepickerInputObject.js +9 -12
  204. package/components/input-datepicker/test-suites/LionInputDatepicker.suite.js +6 -4
  205. package/components/input-datepicker/translations/bg-BG.js +0 -1
  206. package/components/input-datepicker/translations/cs-CZ.js +0 -1
  207. package/components/input-datepicker/translations/de-DE.js +0 -1
  208. package/components/input-datepicker/translations/en-AU.js +0 -1
  209. package/components/input-datepicker/translations/en-GB.js +0 -1
  210. package/components/input-datepicker/translations/en-US.js +0 -1
  211. package/components/input-datepicker/translations/es-ES.js +0 -1
  212. package/components/input-datepicker/translations/fr-BE.js +0 -1
  213. package/components/input-datepicker/translations/fr-FR.js +0 -1
  214. package/components/input-datepicker/translations/hu-HU.js +0 -1
  215. package/components/input-datepicker/translations/it-IT.js +0 -1
  216. package/components/input-datepicker/translations/nl-BE.js +0 -1
  217. package/components/input-datepicker/translations/nl-NL.js +0 -1
  218. package/components/input-datepicker/translations/pl-PL.js +0 -1
  219. package/components/input-datepicker/translations/ro-RO.js +0 -1
  220. package/components/input-datepicker/translations/ru-RU.js +0 -1
  221. package/components/input-datepicker/translations/sk-SK.js +0 -1
  222. package/components/input-datepicker/translations/tr-TR.js +0 -1
  223. package/components/input-datepicker/translations/uk-UA.js +0 -1
  224. package/components/input-email/test/lion-input-email-integrations.test.js +0 -2
  225. package/components/input-email/test/lion-input-email.test.js +1 -7
  226. package/components/input-file/src/FileHandle.js +0 -3
  227. package/components/input-file/src/LionInputFile.js +85 -83
  228. package/components/input-file/src/LionSelectedFileList.js +12 -12
  229. package/components/input-file/src/validators.js +10 -9
  230. package/components/input-file/test/FileValidators.test.js +170 -80
  231. package/components/input-file/test/lion-input-file.test.js +160 -244
  232. package/components/input-file/test/lion-selected-file-list.test.js +13 -22
  233. package/components/input-file/translations/bg-BG.js +0 -1
  234. package/components/input-file/translations/cs-CZ.js +0 -1
  235. package/components/input-file/translations/de-DE.js +0 -1
  236. package/components/input-file/translations/en-AU.js +0 -1
  237. package/components/input-file/translations/en-GB.js +0 -1
  238. package/components/input-file/translations/en-PH.js +0 -1
  239. package/components/input-file/translations/en-US.js +0 -1
  240. package/components/input-file/translations/en.js +2 -1
  241. package/components/input-file/translations/es-ES.js +0 -1
  242. package/components/input-file/translations/fr-BE.js +0 -1
  243. package/components/input-file/translations/fr-FR.js +0 -1
  244. package/components/input-file/translations/hu-HU.js +0 -1
  245. package/components/input-file/translations/id-ID.js +0 -1
  246. package/components/input-file/translations/id.js +2 -1
  247. package/components/input-file/translations/it-IT.js +0 -1
  248. package/components/input-file/translations/nl-BE.js +0 -1
  249. package/components/input-file/translations/nl-NL.js +0 -1
  250. package/components/input-file/translations/pl-PL.js +0 -1
  251. package/components/input-file/translations/ro-RO.js +0 -1
  252. package/components/input-file/translations/ru-RU.js +0 -1
  253. package/components/input-file/translations/sk-SK.js +0 -1
  254. package/components/input-file/translations/uk-UA.js +0 -1
  255. package/components/input-file/translations/zh-CN.js +0 -1
  256. package/components/input-iban/src/validators.js +6 -11
  257. package/components/input-iban/test/formatters.test.js +0 -3
  258. package/components/input-iban/test/lion-input-iban-integrations.test.js +0 -2
  259. package/components/input-iban/test/lion-input-iban.test.js +1 -9
  260. package/components/input-iban/test/parsers.test.js +0 -2
  261. package/components/input-iban/test/validators.test.js +0 -12
  262. package/components/input-iban/translations/bg-BG.js +0 -1
  263. package/components/input-iban/translations/cs-CZ.js +0 -1
  264. package/components/input-iban/translations/de-DE.js +0 -1
  265. package/components/input-iban/translations/en-AU.js +0 -1
  266. package/components/input-iban/translations/en-GB.js +0 -1
  267. package/components/input-iban/translations/en-US.js +0 -1
  268. package/components/input-iban/translations/es-ES.js +0 -1
  269. package/components/input-iban/translations/fr-BE.js +0 -1
  270. package/components/input-iban/translations/fr-FR.js +0 -1
  271. package/components/input-iban/translations/hu-HU.js +0 -1
  272. package/components/input-iban/translations/it-IT.js +0 -1
  273. package/components/input-iban/translations/nl-BE.js +0 -1
  274. package/components/input-iban/translations/nl-NL.js +0 -1
  275. package/components/input-iban/translations/pl-PL.js +0 -1
  276. package/components/input-iban/translations/ro-RO.js +0 -1
  277. package/components/input-iban/translations/ru-RU.js +0 -1
  278. package/components/input-iban/translations/sk-SK.js +0 -1
  279. package/components/input-iban/translations/uk-UA.js +0 -1
  280. package/components/input-range/src/LionInputRange.js +18 -19
  281. package/components/input-range/test/lion-input-range.test.js +23 -48
  282. package/components/input-range/translations/bg-BG.js +0 -1
  283. package/components/input-range/translations/cs-CZ.js +0 -1
  284. package/components/input-range/translations/de-DE.js +0 -1
  285. package/components/input-range/translations/en-AU.js +0 -1
  286. package/components/input-range/translations/en-GB.js +0 -1
  287. package/components/input-range/translations/en-PH.js +0 -1
  288. package/components/input-range/translations/en-US.js +0 -1
  289. package/components/input-range/translations/es-ES.js +0 -1
  290. package/components/input-range/translations/fr-BE.js +0 -1
  291. package/components/input-range/translations/fr-FR.js +0 -1
  292. package/components/input-range/translations/hu-HU.js +0 -1
  293. package/components/input-range/translations/it-IT.js +0 -1
  294. package/components/input-range/translations/nl-BE.js +0 -1
  295. package/components/input-range/translations/nl-NL.js +0 -1
  296. package/components/input-range/translations/pl-PL.js +0 -1
  297. package/components/input-range/translations/ro-RO.js +0 -1
  298. package/components/input-range/translations/ru-RU.js +0 -1
  299. package/components/input-range/translations/sk-SK.js +0 -1
  300. package/components/input-range/translations/uk-UA.js +0 -1
  301. package/components/input-range/translations/zh-CN.js +0 -1
  302. package/components/input-stepper/src/LionInputStepper.js +19 -38
  303. package/components/input-stepper/test/lion-input-stepper-integrations.test.js +0 -1
  304. package/components/input-stepper/test/lion-input-stepper.test.js +0 -1
  305. package/components/input-stepper/test-suites/lion-input-stepper.integration.suite.js +0 -2
  306. package/components/input-stepper/test-suites/lion-input-stepper.suite.js +56 -105
  307. package/components/input-stepper/translations/bg-BG.js +0 -1
  308. package/components/input-stepper/translations/cs-CZ.js +0 -1
  309. package/components/input-stepper/translations/de-DE.js +0 -1
  310. package/components/input-stepper/translations/en-AU.js +0 -1
  311. package/components/input-stepper/translations/en-GB.js +0 -1
  312. package/components/input-stepper/translations/en-US.js +0 -1
  313. package/components/input-stepper/translations/es-ES.js +0 -1
  314. package/components/input-stepper/translations/fr-BE.js +0 -1
  315. package/components/input-stepper/translations/fr-FR.js +0 -1
  316. package/components/input-stepper/translations/hu-HU.js +0 -1
  317. package/components/input-stepper/translations/it-IT.js +0 -1
  318. package/components/input-stepper/translations/nl-BE.js +0 -1
  319. package/components/input-stepper/translations/nl-NL.js +0 -1
  320. package/components/input-stepper/translations/pl-PL.js +0 -1
  321. package/components/input-stepper/translations/ro-RO.js +0 -1
  322. package/components/input-stepper/translations/ru-RU.js +0 -1
  323. package/components/input-stepper/translations/sk-SK.js +0 -1
  324. package/components/input-stepper/translations/uk-UA.js +0 -1
  325. package/components/input-tel/src/LionInputTel.js +53 -37
  326. package/components/input-tel/src/PhoneUtilManager.js +6 -4
  327. package/components/input-tel/src/formatters.js +12 -10
  328. package/components/input-tel/src/parsers.js +3 -3
  329. package/components/input-tel/src/preprocessors.js +15 -7
  330. package/components/input-tel/src/validators.js +4 -6
  331. package/components/input-tel/test/LionInputTel.test.js +4 -2
  332. package/components/input-tel/test/formatters.test.js +22 -10
  333. package/components/input-tel/test/parsers.test.js +40 -11
  334. package/components/input-tel/test/preprocessors.test.js +24 -13
  335. package/components/input-tel/test/validators.test.js +7 -14
  336. package/components/input-tel/test-helpers/mockPhoneUtilManager.js +7 -6
  337. package/components/input-tel/test-suites/LionInputTel.suite.js +33 -73
  338. package/components/input-tel/translations/bg-BG.js +0 -1
  339. package/components/input-tel/translations/cs-CZ.js +0 -1
  340. package/components/input-tel/translations/de-DE.js +0 -1
  341. package/components/input-tel/translations/en-AU.js +0 -1
  342. package/components/input-tel/translations/en-GB.js +0 -1
  343. package/components/input-tel/translations/en-US.js +0 -1
  344. package/components/input-tel/translations/es-ES.js +0 -1
  345. package/components/input-tel/translations/fr-BE.js +0 -1
  346. package/components/input-tel/translations/fr-FR.js +0 -1
  347. package/components/input-tel/translations/hu-HU.js +0 -1
  348. package/components/input-tel/translations/it-IT.js +0 -1
  349. package/components/input-tel/translations/nl-BE.js +0 -1
  350. package/components/input-tel/translations/nl-NL.js +0 -1
  351. package/components/input-tel/translations/pl-PL.js +0 -1
  352. package/components/input-tel/translations/ro-RO.js +0 -1
  353. package/components/input-tel/translations/ru-RU.js +0 -1
  354. package/components/input-tel/translations/sk-SK.js +0 -1
  355. package/components/input-tel/translations/uk-UA.js +0 -1
  356. package/components/input-tel-dropdown/src/LionInputTelDropdown.js +10 -28
  357. package/components/input-tel-dropdown/src/regionCodeToLocale.js +3 -1
  358. package/components/input-tel-dropdown/test/LionInputTelDropdown.test.js +31 -38
  359. package/components/input-tel-dropdown/test/regionCodeToLocale.test.js +0 -1
  360. package/components/input-tel-dropdown/test-helpers/mimicUserChangingDropdown.js +5 -1
  361. package/components/input-tel-dropdown/test-suites/LionInputTelDropdown--parentheses.suite.js +16 -11
  362. package/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js +54 -79
  363. package/components/listbox/src/LionListbox.js +4 -1
  364. package/components/listbox/src/LionOption.js +8 -7
  365. package/components/listbox/src/LionOptions.js +0 -3
  366. package/components/listbox/src/ListboxMixin.js +786 -820
  367. package/components/listbox/test/lion-listbox.test.js +0 -1
  368. package/components/listbox/test/lion-option.test.js +53 -64
  369. package/components/listbox/test/lion-options.test.js +3 -4
  370. package/components/listbox/test-helpers/getListboxMembers.js +6 -3
  371. package/components/listbox/test-suites/ListboxMixin.suite.js +101 -261
  372. package/components/localize/src/LocalizeManager.js +40 -40
  373. package/components/localize/src/LocalizeMixin.js +130 -157
  374. package/components/localize/src/date/formatDate.js +1 -5
  375. package/components/localize/src/date/getDateFormatBasedOnLocale.js +5 -3
  376. package/components/localize/src/date/getMonthNames.js +3 -5
  377. package/components/localize/src/date/getWeekdayNames.js +1 -5
  378. package/components/localize/src/date/parseDate.js +5 -20
  379. package/components/localize/src/date/utils/normalizeIntlDate.js +0 -7
  380. package/components/localize/src/getLocalizeManager.js +0 -3
  381. package/components/localize/src/number/formatNumber.js +3 -7
  382. package/components/localize/src/number/formatNumberToParts.js +52 -18
  383. package/components/localize/src/number/getCurrencyName.js +5 -5
  384. package/components/localize/src/number/getFractionDigits.js +4 -4
  385. package/components/localize/src/number/getSeparatorsFromNumber.js +1 -3
  386. package/components/localize/src/number/parseNumber.js +0 -3
  387. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceAddGroupSeparators.js +0 -1
  388. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceSpaceBetweenCurrencyCodeAndNumber.js +4 -1
  389. package/components/localize/test/LocalizeManager.test.js +385 -278
  390. package/components/localize/test/LocalizeMixin.test.js +28 -112
  391. package/components/localize/test/date/formatDate.test.js +18 -48
  392. package/components/localize/test/date/getDateFormatBasedOnLocale.test.js +0 -3
  393. package/components/localize/test/date/getMonthNames.test.js +27 -12
  394. package/components/localize/test/date/getWeekdayNames.test.js +93 -49
  395. package/components/localize/test/date/normalizeDateTime.test.js +0 -2
  396. package/components/localize/test/date/parseDate.test.js +12 -16
  397. package/components/localize/test/getLocalizeManager.test.js +0 -3
  398. package/components/localize/test/isLocalizeESModule.test.js +32 -13
  399. package/components/localize/test/localize.test.js +0 -4
  400. package/components/localize/test/number/formatNumber.test.js +215 -106
  401. package/components/localize/test/number/formatNumberToParts.test.js +31 -38
  402. package/components/localize/test/number/getCurrencyName.test.js +20 -6
  403. package/components/localize/test/number/getDecimalSeparator.test.js +5 -4
  404. package/components/localize/test/number/getFractionDigits.test.js +0 -2
  405. package/components/localize/test/number/getGroupSeparator.test.js +0 -2
  406. package/components/localize/test/number/getSeparatorsFromNumber.test.js +5 -3
  407. package/components/localize/test/number/parseNumber.test.js +123 -56
  408. package/components/localize/test/side-effect-free-entrypoint.test.js +0 -6
  409. package/components/localize/test-helpers/fake-imports.js +11 -6
  410. package/components/localize/test-helpers/localizeTearDown.js +0 -1
  411. package/components/menu/src/InteractiveListMixin.js +637 -638
  412. package/components/menu/src/LionMenu.js +46 -59
  413. package/components/menu/src/MoreButtonMenuMixin.js +215 -238
  414. package/components/menu/src/MultiLevelListMixin.js +240 -246
  415. package/components/menu/src/utils/isInView.js +0 -1
  416. package/components/menu/src/utils/listItemInteractions.js +4 -4
  417. package/components/menu/test/InteractiveListMixin.test.js +0 -1
  418. package/components/menu/test/MoreButtonMenuMixin.test.js +3 -2
  419. package/components/menu/test/MultiLevelListMixin.test.js +0 -1
  420. package/components/menu/test/lion-menu-interactions.test.js +0 -1
  421. package/components/menu/test/lion-menu.test.js +6 -2
  422. package/components/menu/test-helpers/mimicKeyPress.js +12 -2
  423. package/components/menu/test-suites/InteractiveListMixin.suite.js +4 -43
  424. package/components/menu/test-suites/LionMenu.suite.js +1 -8
  425. package/components/menu/test-suites/LionMenuInteractions.suite.js +22 -44
  426. package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +34 -41
  427. package/components/menu/test-suites/MultiLevelListMixin.suite.js +5 -23
  428. package/components/overlays/src/ArrowMixin.js +111 -127
  429. package/components/overlays/src/OverlayController.js +166 -151
  430. package/components/overlays/src/OverlayMixin.js +61 -63
  431. package/components/overlays/src/OverlaysManager.js +30 -32
  432. package/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.js +0 -1
  433. package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +11 -11
  434. package/components/overlays/src/configurations/withBottomSheetConfig.js +12 -13
  435. package/components/overlays/src/configurations/withDropdownConfig.js +4 -2
  436. package/components/overlays/src/configurations/withModalDialogConfig.js +12 -13
  437. package/components/overlays/src/configurations/withPopoverConfig.js +27 -25
  438. package/components/overlays/src/configurations/withTooltipConfig.js +15 -13
  439. package/components/overlays/src/overlayDocumentStyle.js +1 -1
  440. package/components/overlays/src/overlayShadowDomStyle.js +0 -1
  441. package/components/overlays/src/singleton.js +0 -2
  442. package/components/overlays/src/utils/adopt-styles.js +18 -18
  443. package/components/overlays/src/utils/deep-contains.js +7 -6
  444. package/components/overlays/src/utils/get-focusable-elements.js +7 -10
  445. package/components/overlays/src/utils/inert-siblings.js +2 -4
  446. package/components/overlays/src/utils/is-equal-config.js +2 -3
  447. package/components/overlays/src/utils/is-visible.js +0 -1
  448. package/components/overlays/src/utils/simulate-tab.js +1 -4
  449. package/components/overlays/src/utils/sort-by-tabindex.js +2 -4
  450. package/components/overlays/test/ArrowMixin.test.js +18 -30
  451. package/components/overlays/test/OverlayController.test.js +375 -555
  452. package/components/overlays/test/OverlayMixin.test.js +0 -2
  453. package/components/overlays/test/OverlaysManager.test.js +30 -35
  454. package/components/overlays/test/global-positioning.test.js +6 -10
  455. package/components/overlays/test/local-positioning.test.js +101 -103
  456. package/components/overlays/test/utils-tests/active-element.test.js +12 -27
  457. package/components/overlays/test/utils-tests/adopt-styles.test.js +25 -56
  458. package/components/overlays/test/utils-tests/deep-contains.test.js +73 -74
  459. package/components/overlays/test/utils-tests/get-focusable-elements.test.js +6 -23
  460. package/components/overlays/test/utils-tests/is-equal-config.test.js +32 -13
  461. package/components/overlays/test/utils-tests/visibility.test.js +44 -79
  462. package/components/overlays/test-helpers/createShadowHost.js +5 -3
  463. package/components/overlays/test-helpers/normalizeTransformStyle.js +2 -4
  464. package/components/overlays/test-suites/OverlayMixin.suite.js +152 -181
  465. package/components/overlays/test-suites/WithHoverInteraction.suite.js +96 -79
  466. package/components/overlays/translations/bg-BG.js +0 -1
  467. package/components/overlays/translations/cs-CZ.js +0 -1
  468. package/components/overlays/translations/de-DE.js +0 -1
  469. package/components/overlays/translations/en-AU.js +0 -1
  470. package/components/overlays/translations/en-GB.js +0 -1
  471. package/components/overlays/translations/en-US.js +0 -1
  472. package/components/overlays/translations/es-ES.js +0 -1
  473. package/components/overlays/translations/fr-BE.js +0 -1
  474. package/components/overlays/translations/fr-FR.js +0 -1
  475. package/components/overlays/translations/hu-HU.js +0 -1
  476. package/components/overlays/translations/it-IT.js +0 -1
  477. package/components/overlays/translations/nl-BE.js +0 -1
  478. package/components/overlays/translations/nl-NL.js +0 -1
  479. package/components/overlays/translations/pl-PL.js +0 -1
  480. package/components/overlays/translations/ro-RO.js +0 -1
  481. package/components/overlays/translations/ru-RU.js +0 -1
  482. package/components/overlays/translations/sk-SK.js +0 -1
  483. package/components/overlays/translations/tr-TR.js +0 -1
  484. package/components/overlays/translations/uk-UA.js +0 -1
  485. package/components/pagination/src/LionPagination.js +9 -12
  486. package/components/pagination/test/lion-pagination.test.js +18 -50
  487. package/components/progress-indicator/src/LionProgressIndicator.js +10 -12
  488. package/components/progress-indicator/test/lion-progress-indicator.test.js +1 -22
  489. package/components/radio-group/src/LionRadioGroup.js +1 -2
  490. package/components/radio-group/test/lion-radio-group-integrations.test.js +0 -1
  491. package/components/radio-group/test/lion-radio-group.test.js +27 -27
  492. package/components/radio-group/test/lion-radio-integrations.test.js +3 -2
  493. package/components/radio-group/test/lion-radio.test.js +30 -16
  494. package/components/select/src/LionSelect.js +12 -13
  495. package/components/select/test/lion-select.test.js +7 -12
  496. package/components/select-rich/src/LionSelectInvoker.js +18 -11
  497. package/components/select-rich/src/LionSelectRich.js +20 -43
  498. package/components/select-rich/test/demos.screenshots-test.js +40 -9
  499. package/components/select-rich/test/lion-select-invoker.test.js +26 -43
  500. package/components/select-rich/test/lion-select-listbox-suite-integration.test.js +3 -3
  501. package/components/select-rich/test/lion-select-rich-dialog-integration.test.js +4 -9
  502. package/components/select-rich/test/lion-select-rich-interaction.test.js +116 -116
  503. package/components/select-rich/test/lion-select-rich-upgrade.test.js +3 -7
  504. package/components/select-rich/test/lion-select-rich.test.js +153 -195
  505. package/components/select-rich/test-helpers/getSelectRichMembers.js +4 -1
  506. package/components/steps/src/LionStep.js +21 -12
  507. package/components/steps/src/LionSteps.js +25 -25
  508. package/components/steps/test/lion-step.test.js +18 -25
  509. package/components/steps/test/lion-steps.test.js +45 -78
  510. package/components/switch/src/LionSwitch.js +2 -7
  511. package/components/switch/src/LionSwitchButton.js +5 -6
  512. package/components/switch/test/lion-switch-button.test.js +16 -28
  513. package/components/switch/test/lion-switch.test.js +17 -31
  514. package/components/tabs/src/LionTabs.js +25 -28
  515. package/components/tabs/test/lion-tabs.test.js +156 -154
  516. package/components/textarea/src/LionTextarea.js +4 -23
  517. package/components/textarea/test/lion-textarea-integrations.test.js +0 -5
  518. package/components/textarea/test/lion-textarea.test.js +2 -28
  519. package/components/tooltip/src/LionTooltip.js +6 -6
  520. package/components/tooltip/test/lion-tooltip.test.js +75 -102
  521. package/components/validate-messages/src/getLocalizedMessage.js +8 -7
  522. package/components/validate-messages/src/loadDefaultFeedbackMessages.js +3 -1
  523. package/components/validate-messages/src/loadDefaultFeedbackMessagesNoSideEffects.js +9 -5
  524. package/components/validate-messages/src/per-entrypoint/loadComboboxMessagesNoSideEffects.js +5 -2
  525. package/components/validate-messages/src/per-entrypoint/loadFormCoreMessagesNoSideEffects.js +99 -35
  526. package/components/validate-messages/src/per-entrypoint/loadInputTelMessagesNoSideEffects.js +4 -3
  527. package/components/validate-messages/test/loadDefaultFeedbackMessages.test.js +5 -3
  528. package/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.test.js +80 -45
  529. package/components/validate-messages/translations/bg-BG.js +0 -1
  530. package/components/validate-messages/translations/cs-CZ.js +0 -1
  531. package/components/validate-messages/translations/de-DE.js +0 -1
  532. package/components/validate-messages/translations/en-AU.js +0 -1
  533. package/components/validate-messages/translations/en-GB.js +0 -1
  534. package/components/validate-messages/translations/en-PH.js +0 -1
  535. package/components/validate-messages/translations/en-US.js +0 -1
  536. package/components/validate-messages/translations/es-ES.js +0 -1
  537. package/components/validate-messages/translations/fr-BE.js +0 -1
  538. package/components/validate-messages/translations/fr-FR.js +0 -1
  539. package/components/validate-messages/translations/hu-HU.js +0 -1
  540. package/components/validate-messages/translations/it-IT.js +0 -1
  541. package/components/validate-messages/translations/nl-BE.js +0 -1
  542. package/components/validate-messages/translations/nl-NL.js +0 -1
  543. package/components/validate-messages/translations/pl-PL.js +0 -1
  544. package/components/validate-messages/translations/ro-RO.js +0 -1
  545. package/components/validate-messages/translations/ru-RU.js +0 -1
  546. package/components/validate-messages/translations/sk-SK.js +0 -1
  547. package/components/validate-messages/translations/tr-TR.js +0 -1
  548. package/components/validate-messages/translations/uk-UA.js +0 -1
  549. package/custom-elements.json +191 -56
  550. package/dist-types/components/core/src/SlotMixin.d.ts +6 -1
  551. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  552. package/dist-types/components/core/types/SlotMixinTypes.d.ts +5 -1
  553. package/dist-types/components/core/types/SlotMixinTypes.d.ts.map +1 -1
  554. package/dist-types/components/form-core/src/LionField.d.ts +3 -1
  555. package/dist-types/components/form-core/src/LionField.d.ts.map +1 -1
  556. package/dist-types/components/input-tel/src/LionInputTel.d.ts +6 -6
  557. package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
  558. package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts +2 -2
  559. package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts.map +1 -1
  560. package/dist-types/components/input-tel/src/formatters.d.ts +2 -2
  561. package/dist-types/components/input-tel/src/formatters.d.ts.map +1 -1
  562. package/dist-types/components/input-tel/src/preprocessors.d.ts +2 -2
  563. package/dist-types/components/input-tel/src/preprocessors.d.ts.map +1 -1
  564. package/dist-types/components/input-tel/test/validators.test.d.ts +1 -1
  565. package/dist-types/components/input-tel/test/validators.test.d.ts.map +1 -1
  566. package/dist-types/components/listbox/src/LionOption.d.ts +5 -2
  567. package/dist-types/components/listbox/src/LionOption.d.ts.map +1 -1
  568. package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
  569. package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts.map +1 -1
  570. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts +3 -1
  571. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts.map +1 -1
  572. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +1 -1
  573. package/dist-types/tsconfig.tsbuildinfo +1 -1
  574. package/docs/components/accordion/overview.md +2 -2
  575. package/docs/components/accordion/reference.md +2 -2
  576. package/docs/components/accordion/use-cases.md +2 -2
  577. package/docs/components/button/examples.md +2 -2
  578. package/docs/components/button/extensions.md +2 -2
  579. package/docs/components/button/overview.md +2 -2
  580. package/docs/components/button/use-cases.md +2 -2
  581. package/docs/components/calendar/overview.md +2 -2
  582. package/docs/components/calendar/use-cases.md +2 -2
  583. package/docs/components/checkbox-group/overview.md +4 -4
  584. package/docs/components/checkbox-group/use-cases.md +2 -2
  585. package/docs/components/collapsible/examples.md +2 -2
  586. package/docs/components/collapsible/overview.md +3 -3
  587. package/docs/components/collapsible/use-cases.md +2 -2
  588. package/docs/components/combobox/extensions.md +2 -2
  589. package/docs/components/combobox/overview.md +3 -3
  590. package/docs/components/combobox/use-cases.md +3 -3
  591. package/docs/components/dialog/overview.md +3 -3
  592. package/docs/components/dialog/use-cases.md +2 -2
  593. package/docs/components/drawer/overview.md +2 -2
  594. package/docs/components/drawer/use-cases.md +2 -2
  595. package/docs/components/fieldset/overview.md +7 -7
  596. package/docs/components/fieldset/use-cases.md +2 -2
  597. package/docs/components/form/overview.md +5 -5
  598. package/docs/components/form/use-cases.md +4 -4
  599. package/docs/components/icon/overview.md +2 -2
  600. package/docs/components/icon/use-cases.md +3 -3
  601. package/docs/components/input/overview.md +3 -3
  602. package/docs/components/input/use-cases.md +2 -2
  603. package/docs/components/input-amount/overview.md +5 -5
  604. package/docs/components/input-amount/use-cases.md +2 -2
  605. package/docs/components/input-amount-dropdown/use-cases.md +2 -2
  606. package/docs/components/input-date/overview.md +5 -5
  607. package/docs/components/input-date/use-cases.md +2 -2
  608. package/docs/components/input-datepicker/overview.md +7 -7
  609. package/docs/components/input-datepicker/use-cases.md +2 -2
  610. package/docs/components/input-email/overview.md +4 -4
  611. package/docs/components/input-email/use-cases.md +2 -2
  612. package/docs/components/input-file/overview.md +3 -3
  613. package/docs/components/input-file/use-cases.md +2 -2
  614. package/docs/components/input-iban/overview.md +4 -4
  615. package/docs/components/input-iban/use-cases.md +2 -2
  616. package/docs/components/input-range/overview.md +4 -4
  617. package/docs/components/input-range/use-cases.md +2 -2
  618. package/docs/components/input-stepper/overview.md +3 -3
  619. package/docs/components/input-stepper/use-cases.md +2 -2
  620. package/docs/components/input-tel/overview.md +3 -3
  621. package/docs/components/input-tel/use-cases.md +8 -8
  622. package/docs/components/input-tel-dropdown/extensions.md +2 -2
  623. package/docs/components/input-tel-dropdown/overview.md +3 -3
  624. package/docs/components/input-tel-dropdown/use-cases.md +2 -2
  625. package/docs/components/listbox/overview.md +2 -2
  626. package/docs/components/listbox/use-cases.md +3 -3
  627. package/docs/components/menu/extensions.md +2 -2
  628. package/docs/components/menu/migration.md +2 -2
  629. package/docs/components/menu/overview.md +2 -2
  630. package/docs/components/menu/use-cases.md +1 -1
  631. package/docs/components/pagination/overview.md +2 -2
  632. package/docs/components/pagination/use-cases.md +2 -2
  633. package/docs/components/progress-indicator/examples.md +2 -2
  634. package/docs/components/progress-indicator/overview.md +2 -2
  635. package/docs/components/radio-group/overview.md +5 -5
  636. package/docs/components/radio-group/use-cases.md +2 -2
  637. package/docs/components/select/overview.md +2 -2
  638. package/docs/components/select/use-cases.md +3 -3
  639. package/docs/components/select-rich/examples.md +2 -2
  640. package/docs/components/select-rich/overview.md +2 -2
  641. package/docs/components/select-rich/use-cases.md +4 -4
  642. package/docs/components/steps/overview.md +2 -2
  643. package/docs/components/steps/use-cases.md +2 -2
  644. package/docs/components/switch/overview.md +2 -2
  645. package/docs/components/switch/reference.md +2 -2
  646. package/docs/components/switch/use-cases.md +2 -2
  647. package/docs/components/tabs/examples.md +3 -3
  648. package/docs/components/tabs/overview.md +2 -2
  649. package/docs/components/tabs/use-cases.md +2 -2
  650. package/docs/components/textarea/overview.md +2 -2
  651. package/docs/components/textarea/use-cases.md +2 -2
  652. package/docs/components/tooltip/examples.md +2 -2
  653. package/docs/components/tooltip/overview.md +2 -2
  654. package/docs/components/tooltip/use-cases.md +2 -2
  655. package/docs/fundamentals/index.md +4 -4
  656. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +2 -2
  657. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +2 -2
  658. package/docs/fundamentals/node-tools/providence-analytics/index.md +2 -2
  659. package/docs/fundamentals/node-tools/providence-analytics/overview.md +2 -2
  660. package/docs/fundamentals/node-tools/publish-docs/index.md +2 -2
  661. package/docs/fundamentals/node-tools/publish-docs/overview.md +5 -5
  662. package/docs/fundamentals/node-tools/remark-extend/index.md +2 -2
  663. package/docs/fundamentals/node-tools/remark-extend/overview.md +2 -2
  664. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +2 -2
  665. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +4 -4
  666. package/docs/fundamentals/rationales/TypeScript.md +62 -2
  667. package/docs/fundamentals/rationales/accessibility.md +5 -5
  668. package/docs/fundamentals/rationales/side-effects.md +2 -2
  669. package/docs/fundamentals/rationales/versioning.md +2 -2
  670. package/docs/fundamentals/systems/core/SlotMixin.md +3 -3
  671. package/docs/fundamentals/systems/core/index.md +2 -2
  672. package/docs/fundamentals/systems/core/overview.md +3 -3
  673. package/docs/fundamentals/systems/form/formatting-and-parsing.md +6 -6
  674. package/docs/fundamentals/systems/form/index.md +2 -2
  675. package/docs/fundamentals/systems/form/interaction-states.md +2 -2
  676. package/docs/fundamentals/systems/form/model-value.md +3 -3
  677. package/docs/fundamentals/systems/form/overview.md +30 -30
  678. package/docs/fundamentals/systems/form/styling.md +2 -2
  679. package/docs/fundamentals/systems/form/use-cases.md +2 -2
  680. package/docs/fundamentals/systems/form/validate.md +4 -4
  681. package/docs/fundamentals/systems/icon/index.md +2 -2
  682. package/docs/fundamentals/systems/icon/overview.md +2 -2
  683. package/docs/fundamentals/systems/localize/dates.md +2 -2
  684. package/docs/fundamentals/systems/localize/index.md +2 -2
  685. package/docs/fundamentals/systems/localize/numbers.md +2 -2
  686. package/docs/fundamentals/systems/localize/overview.md +6 -6
  687. package/docs/fundamentals/systems/localize/rationale.md +2 -2
  688. package/docs/fundamentals/systems/localize/text.md +2 -2
  689. package/docs/fundamentals/systems/localize/use-cases.md +2 -2
  690. package/docs/fundamentals/systems/overlays/_edge-cases.md +2 -2
  691. package/docs/fundamentals/systems/overlays/configuration.md +4 -4
  692. package/docs/fundamentals/systems/overlays/index.md +2 -2
  693. package/docs/fundamentals/systems/overlays/overview.md +7 -7
  694. package/docs/fundamentals/systems/overlays/rationale.md +2 -2
  695. package/docs/fundamentals/systems/overlays/use-cases.md +4 -4
  696. package/docs/fundamentals/tools/ajax/index.md +2 -2
  697. package/docs/fundamentals/tools/ajax/overview.md +2 -2
  698. package/docs/fundamentals/tools/ajax/use-cases.md +2 -2
  699. package/docs/fundamentals/tools/helpers/action-logger.md +2 -2
  700. package/docs/fundamentals/tools/helpers/index.md +2 -2
  701. package/docs/fundamentals/tools/helpers/overview.md +3 -3
  702. package/docs/fundamentals/tools/singleton-manager/example-complex/index.md +2 -2
  703. package/docs/fundamentals/tools/singleton-manager/example-fail/index.md +2 -2
  704. package/docs/fundamentals/tools/singleton-manager/example-success/index.md +2 -2
  705. package/docs/fundamentals/tools/singleton-manager/index.md +2 -2
  706. package/docs/fundamentals/tools/singleton-manager/overview.md +6 -6
  707. package/docs/guides/how-to/create-a-custom-field.md +7 -7
  708. package/docs/guides/how-to/create-a-form.md +6 -6
  709. package/docs/guides/how-to/extend-a-native-input.md +4 -4
  710. package/docs/guides/how-to/get-started.md +2 -2
  711. package/docs/guides/how-to/index.md +1 -1
  712. package/docs/guides/index.md +8 -8
  713. package/docs/guides/principles/definitions-and-terms.md +2 -2
  714. package/docs/guides/principles/index.md +5 -5
  715. package/docs/guides/principles/scoped-elements.md +2 -2
  716. package/docs/guides/principles/styling.md +3 -3
  717. package/docs/guides/principles/subclasser-apis.md +2 -2
  718. package/exports/define/lion-accordion.js +0 -1
  719. package/exports/define/lion-button-reset.js +0 -1
  720. package/exports/define/lion-button-submit.js +0 -1
  721. package/exports/define/lion-button.js +0 -1
  722. package/exports/define/lion-calendar.js +0 -1
  723. package/exports/define/lion-checkbox-group.js +0 -1
  724. package/exports/define/lion-checkbox-indeterminate.js +0 -1
  725. package/exports/define/lion-checkbox.js +0 -1
  726. package/exports/define/lion-collapsible.js +0 -1
  727. package/exports/define/lion-combobox.js +0 -1
  728. package/exports/define/lion-dialog.js +0 -1
  729. package/exports/define/lion-drawer.js +0 -1
  730. package/exports/define/lion-field.js +0 -1
  731. package/exports/define/lion-fieldset.js +0 -1
  732. package/exports/define/lion-form.js +0 -1
  733. package/exports/define/lion-icon.js +0 -1
  734. package/exports/define/lion-input-amount-dropdown.js +0 -1
  735. package/exports/define/lion-input-amount.js +0 -1
  736. package/exports/define/lion-input-date.js +0 -1
  737. package/exports/define/lion-input-datepicker.js +0 -1
  738. package/exports/define/lion-input-email.js +0 -1
  739. package/exports/define/lion-input-file.js +0 -1
  740. package/exports/define/lion-input-iban.js +0 -1
  741. package/exports/define/lion-input-range.js +0 -1
  742. package/exports/define/lion-input-stepper.js +0 -1
  743. package/exports/define/lion-input-tel-dropdown.js +0 -1
  744. package/exports/define/lion-input-tel.js +0 -1
  745. package/exports/define/lion-input.js +0 -1
  746. package/exports/define/lion-item.js +0 -1
  747. package/exports/define/lion-listbox.js +0 -1
  748. package/exports/define/lion-menu.js +0 -1
  749. package/exports/define/lion-menuitem.js +0 -1
  750. package/exports/define/lion-option.js +0 -1
  751. package/exports/define/lion-options.js +0 -1
  752. package/exports/define/lion-pagination.js +0 -1
  753. package/exports/define/lion-progress-indicator.js +0 -1
  754. package/exports/define/lion-radio-group.js +0 -1
  755. package/exports/define/lion-radio.js +0 -1
  756. package/exports/define/lion-select-invoker.js +0 -1
  757. package/exports/define/lion-select-rich.js +0 -1
  758. package/exports/define/lion-select.js +0 -1
  759. package/exports/define/lion-selected-file-list.js +0 -1
  760. package/exports/define/lion-step.js +0 -1
  761. package/exports/define/lion-steps.js +0 -1
  762. package/exports/define/lion-switch-button.js +0 -1
  763. package/exports/define/lion-switch.js +0 -1
  764. package/exports/define/lion-tabs.js +0 -1
  765. package/exports/define/lion-textarea.js +0 -1
  766. package/exports/define/lion-tooltip.js +0 -1
  767. package/exports/define/lion-validation-feedback.js +0 -1
  768. package/exports/define-helpers/sb-action-logger.js +0 -1
  769. package/exports/define-helpers/sb-locale-switcher.js +0 -1
  770. package/exports/form-core.js +0 -8
  771. package/exports/localize-no-side-effects.js +0 -1
  772. package/exports/localize.js +0 -2
  773. package/exports/overlays.js +0 -4
  774. package/generated/awesome-phonenumber/LICENSE +22 -0
  775. package/generated/awesome-phonenumber/LICENSE.closure-library +176 -0
  776. package/generated/awesome-phonenumber/LICENSE.libphonenumber +176 -0
  777. package/generated/awesome-phonenumber/checksums.json +6 -0
  778. package/generated/awesome-phonenumber/index-esm.mjs +817 -0
  779. package/generated/awesome-phonenumber/index.d.ts +227 -0
  780. package/generated/awesome-phonenumber/index.js +45 -0
  781. package/generated/awesome-phonenumber/lib/index.js +710 -0
  782. package/generated/awesome-phonenumber/package.json +9 -0
  783. package/generated/awesome-phonenumber/provenance.json +13 -0
  784. package/package.json +32 -10
  785. package/web-types.json +1 -1
  786. package/vendor/README.md +0 -61
  787. package/vendor/awesome-phonenumber-7.9.0-tlouisse.libphonenumber-9.0.41.tgz +0 -0
@@ -32,7 +32,9 @@ import { Validator } from './Validator.js';
32
32
  * @param {any[]} array2
33
33
  */
34
34
  function arrayDiff(array1 = [], array2 = []) {
35
- return array1.filter(x => !array2.includes(x)).concat(array2.filter(x => !array1.includes(x)));
35
+ return array1
36
+ .filter((x) => !array2.includes(x))
37
+ .concat(array2.filter((x) => !array1.includes(x)));
36
38
  }
37
39
 
38
40
  /**
@@ -52,977 +54,921 @@ function getValueForValidators(modelValue) {
52
54
  * @param {import('@open-wc/dedupe-mixin').Constructor<import('lit').LitElement>} superclass
53
55
  */
54
56
  // prettier-ignore
55
- export const ValidateMixinImplementation = /** @type {ValidateMixin} */ (superclass =>
56
- class extends FormControlMixin(
57
- SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass)))),
58
- ) {
59
- static get scopedElements() {
60
- return {
61
- // @ts-ignore
62
- ...super.scopedElements,
63
- 'lion-validation-feedback': LionValidationFeedback,
64
- };
65
- }
66
-
67
- /** @type {any} */
68
- static get properties() {
69
- return {
70
- validators: { attribute: false },
71
- hasFeedbackFor: { attribute: false },
72
- shouldShowFeedbackFor: { attribute: false },
73
- showsFeedbackFor: {
74
- type: Array,
75
- attribute: 'shows-feedback-for',
76
- reflect: true,
77
- converter: {
78
- fromAttribute: /** @param {string | null} value */ value =>
79
- value ? value.split(',') : [],
80
- toAttribute: /** @param {[]} value */ value => value.join(','),
81
- },
82
- },
83
- validationStates: { attribute: false },
84
- isPending: {
85
- type: Boolean,
86
- attribute: 'is-pending',
87
- reflect: true,
88
- },
89
- defaultValidators: { attribute: false },
90
- _visibleMessagesAmount: { attribute: false },
91
- __childModelValueChanged: { attribute: false },
92
- };
93
- }
94
-
57
+ export const ValidateMixinImplementation = /** @type {ValidateMixin} */superclass => class extends FormControlMixin(SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass))))) {
58
+ static get scopedElements() {
59
+ return {
60
+ // @ts-ignore
61
+ ...super.scopedElements,
62
+ 'lion-validation-feedback': LionValidationFeedback
63
+ };
64
+ }
65
+
66
+ /** @type {any} */
67
+ static get properties() {
68
+ return {
69
+ validators: {
70
+ attribute: false
71
+ },
72
+ hasFeedbackFor: {
73
+ attribute: false
74
+ },
75
+ shouldShowFeedbackFor: {
76
+ attribute: false
77
+ },
78
+ showsFeedbackFor: {
79
+ type: Array,
80
+ attribute: 'shows-feedback-for',
81
+ reflect: true,
82
+ converter: {
83
+ fromAttribute: /** @param {string | null} value */value => value ? value.split(',') : [],
84
+ toAttribute: /** @param {[]} value */value => value.join(',')
85
+ }
86
+ },
87
+ validationStates: {
88
+ attribute: false
89
+ },
90
+ isPending: {
91
+ type: Boolean,
92
+ attribute: 'is-pending',
93
+ reflect: true
94
+ },
95
+ defaultValidators: {
96
+ attribute: false
97
+ },
98
+ _visibleMessagesAmount: {
99
+ attribute: false
100
+ },
101
+ __childModelValueChanged: {
102
+ attribute: false
103
+ }
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Types of validation supported by this FormControl (for instance 'error'|'warning'|'info')
109
+ * @overridable
110
+ * @type {ValidationType[]}
111
+ */
112
+ static get validationTypes() {
113
+ return ['error'];
114
+ }
115
+
116
+ /**
117
+ * Types of input interaction of the FormControl (for instance 'enter'|'select'|'upload')
118
+ * @overridable
119
+ * @type {OperationMode}
120
+ */
121
+ get operationMode() {
122
+ return 'enter';
123
+ }
124
+
125
+ /**
126
+ * Adds "._feedbackNode" as described below
127
+ * @public
128
+ */
129
+ get slots() {
95
130
  /**
96
- * Types of validation supported by this FormControl (for instance 'error'|'warning'|'info')
97
- * @overridable
98
- * @type {ValidationType[]}
131
+ * FIXME: Ugly workaround https://github.com/microsoft/TypeScript/issues/40110
132
+ * @callback getScopedTagName
133
+ * @param {string} tagName
134
+ * @returns {string}
135
+ *
136
+ * @typedef {Object} ScopedElementsObj
137
+ * @property {getScopedTagName} getScopedTagName
99
138
  */
100
- static get validationTypes() {
101
- return ['error'];
102
- }
139
+ return {
140
+ ...super.slots,
141
+ feedback: () => {
142
+ const feedbackEl = this.createScopedElement('lion-validation-feedback');
143
+ feedbackEl.setAttribute('data-tag-name', 'lion-validation-feedback');
144
+ return feedbackEl;
145
+ }
146
+ };
147
+ }
148
+
149
+ /**
150
+ * Combination of validators provided by Application Developer and the default validators
151
+ * @type {(Validator | MetaValidator)[]}
152
+ * @protected
153
+ */
154
+ get _allValidators() {
155
+ return [...this.validators, ...this.defaultValidators];
156
+ }
157
+ constructor() {
158
+ super();
103
159
 
104
160
  /**
105
- * Types of input interaction of the FormControl (for instance 'enter'|'select'|'upload')
106
- * @overridable
107
- * @type {OperationMode}
161
+ * As soon as validation happens (after modelValue/validators/validator param change), this
162
+ * array is updated with the active ValidationTypes ('error'|'warning'|'success'|'info' etc.).
163
+ * Notice the difference with `.showsFeedbackFor`, which filters `.hasFeedbackFor` based on
164
+ * `.feedbackCondition()`.
165
+ *
166
+ * For styling purposes, will be reflected to [has-feedback-for="error warning"]. This can
167
+ * be useful for subtle visual feedback on keyup, like a red/green border around an input.
168
+ *
169
+ * @example
170
+ * ```css
171
+ * :host([has-feedback-for~="error"]) .input-group__container {
172
+ * border: 1px solid red;
173
+ * }
174
+ * ```
175
+ * @type {ValidationType[]}
176
+ * @readOnly
108
177
  */
109
- get operationMode() {
110
- return 'enter';
111
- }
178
+ this.hasFeedbackFor = [];
112
179
 
113
180
  /**
114
- * Adds "._feedbackNode" as described below
115
- * @public
181
+ * Based on outcome of feedbackCondition, this array decides what ValidationTypes should be
182
+ * shown in validationFeedback, based on meta data like interaction states.
183
+ *
184
+ * For styling purposes, it reflects it `[shows-feedback-for="error warning"]`
185
+ * @type {ValidationType[]}
186
+ * @readOnly
187
+ * @example
188
+ * ```css
189
+ * :host([shows-feedback-for~="success"]) .form-field__feedback {
190
+ * transform: scaleY(1);
191
+ * }
192
+ * ```
116
193
  */
117
- get slots() {
118
- /**
119
- * FIXME: Ugly workaround https://github.com/microsoft/TypeScript/issues/40110
120
- * @callback getScopedTagName
121
- * @param {string} tagName
122
- * @returns {string}
123
- *
124
- * @typedef {Object} ScopedElementsObj
125
- * @property {getScopedTagName} getScopedTagName
126
- */
127
- return {
128
- ...super.slots,
129
- feedback: () => {
130
- const feedbackEl = this.createScopedElement('lion-validation-feedback');
131
- feedbackEl.setAttribute('data-tag-name', 'lion-validation-feedback');
132
- return feedbackEl;
133
- },
134
- };
135
- }
194
+ this.showsFeedbackFor = [];
136
195
 
196
+ // TODO: [v1] make this fully private (prefix __)?
137
197
  /**
138
- * Combination of validators provided by Application Developer and the default validators
139
- * @type {(Validator | MetaValidator)[]}
140
- * @protected
198
+ * A temporary storage to transition from hasFeedbackFor to showsFeedbackFor
199
+ * @type {ValidationType[]}
200
+ * @readOnly
201
+ * @private
141
202
  */
142
- get _allValidators() {
143
- return [...this.validators, ...this.defaultValidators];
144
- }
145
-
146
- constructor() {
147
- super();
148
-
149
- /**
150
- * As soon as validation happens (after modelValue/validators/validator param change), this
151
- * array is updated with the active ValidationTypes ('error'|'warning'|'success'|'info' etc.).
152
- * Notice the difference with `.showsFeedbackFor`, which filters `.hasFeedbackFor` based on
153
- * `.feedbackCondition()`.
154
- *
155
- * For styling purposes, will be reflected to [has-feedback-for="error warning"]. This can
156
- * be useful for subtle visual feedback on keyup, like a red/green border around an input.
157
- *
158
- * @example
159
- * ```css
160
- * :host([has-feedback-for~="error"]) .input-group__container {
161
- * border: 1px solid red;
162
- * }
163
- * ```
164
- * @type {ValidationType[]}
165
- * @readOnly
166
- */
167
- this.hasFeedbackFor = [];
168
-
169
- /**
170
- * Based on outcome of feedbackCondition, this array decides what ValidationTypes should be
171
- * shown in validationFeedback, based on meta data like interaction states.
172
- *
173
- * For styling purposes, it reflects it `[shows-feedback-for="error warning"]`
174
- * @type {ValidationType[]}
175
- * @readOnly
176
- * @example
177
- * ```css
178
- * :host([shows-feedback-for~="success"]) .form-field__feedback {
179
- * transform: scaleY(1);
180
- * }
181
- * ```
182
- */
183
- this.showsFeedbackFor = [];
184
-
185
- // TODO: [v1] make this fully private (prefix __)?
186
- /**
187
- * A temporary storage to transition from hasFeedbackFor to showsFeedbackFor
188
- * @type {ValidationType[]}
189
- * @readOnly
190
- * @private
191
- */
192
- this.shouldShowFeedbackFor = [];
193
-
194
- /**
195
- * The outcome of a validation 'round'. Keyed by ValidationType and Validator name
196
- * @readOnly
197
- * @type {ValidationStates}
198
- */
199
- this.validationStates = {};
200
-
201
- /**
202
- * Flag indicating whether async validation is pending.
203
- * Creates attribute [is-pending] as a styling hook
204
- * @type {boolean}
205
- */
206
- this.isPending = false;
207
-
208
- /**
209
- * Used by Application Developers to add Validators to a FormControl.
210
- * @example
211
- * ```html
212
- * <form-control .validators="${[new Required(), new MinLength(4, {type: 'warning'})]}">
213
- * </form-control>
214
- * ```
215
- * @type {Validator[]}
216
- */
217
- this.validators = [];
218
-
219
- /**
220
- * Used by Subclassers to add default Validators to a particular FormControl.
221
- * A date input for instance, always needs the isDate validator.
222
- * @example
223
- * ```js
224
- * this.defaultValidators.push(new IsDate());
225
- * ```
226
- * @type {Validator[]}
227
- */
228
- this.defaultValidators = [];
229
-
230
- /**
231
- * The amount of feedback messages that will visible in LionValidationFeedback
232
- * @configurable
233
- * @protected
234
- */
235
- this._visibleMessagesAmount = 1;
236
-
237
- /**
238
- * @type {ValidationResultEntry[]}
239
- * @private
240
- */
241
- this.__syncValidationResult = [];
242
-
243
- /**
244
- * @type {ValidationResultEntry[]}
245
- * @private
246
- */
247
- this.__asyncValidationResult = [];
248
-
249
- /**
250
- * Aggregated result from sync Validators, async Validators and MetaValidators
251
- * @type {ValidationResultEntry[]}
252
- * @private
253
- */
254
- this.__validationResult = [];
255
-
256
- /**
257
- * @type {ValidationResultEntry[]}
258
- * @private
259
- */
260
- this.__prevValidationResult = [];
261
-
262
- /**
263
- * The shown validation result depends on the visibility of the feedback messages
264
- * @type {ValidationResultEntry[]}
265
- * @private
266
- */
267
- this.__prevShownValidationResult = [];
268
-
269
- /**
270
- * The updated children validity affects the validity of the parent. Helper to recompute
271
- * validity of parent FormGroup
272
- * @private
273
- */
274
- this.__childModelValueChanged = false;
275
-
276
- /** @protected */
277
- this._onValidatorUpdated = this._onValidatorUpdated.bind(this);
278
- /** @protected */
279
- this._updateFeedbackComponent = this._updateFeedbackComponent.bind(this);
280
- }
281
-
282
- connectedCallback() {
283
- super.connectedCallback();
284
-
285
- const localizeManager = getLocalizeManager();
286
- localizeManager.addEventListener('localeChanged', this._updateFeedbackComponent);
287
- }
288
-
289
- disconnectedCallback() {
290
- super.disconnectedCallback();
291
-
292
- const localizeManager = getLocalizeManager();
293
- localizeManager.removeEventListener('localeChanged', this._updateFeedbackComponent);
294
- }
203
+ this.shouldShowFeedbackFor = [];
295
204
 
296
205
  /**
297
- * @param {import('lit').PropertyValues} changedProperties
206
+ * The outcome of a validation 'round'. Keyed by ValidationType and Validator name
207
+ * @readOnly
208
+ * @type {ValidationStates}
298
209
  */
299
- firstUpdated(changedProperties) {
300
- super.firstUpdated(changedProperties);
301
- this.__isValidateInitialized = true;
302
- this.validate();
303
- if (this._repropagationRole !== 'child') {
304
- this.addEventListener('model-value-changed', () => {
305
- this.__childModelValueChanged = true;
306
- });
307
- }
308
- }
210
+ this.validationStates = {};
309
211
 
310
212
  /**
311
- * @param {string} name
312
- * @param {any} oldValue
213
+ * Flag indicating whether async validation is pending.
214
+ * Creates attribute [is-pending] as a styling hook
215
+ * @type {boolean}
313
216
  */
314
- updateSync(name, oldValue) {
315
- super.updateSync(name, oldValue);
316
- if (name === 'validators') {
317
- // trigger validation (ideally only for the new or changed validator)
318
- this.__setupValidators();
319
- this.validate({ clearCurrentResult: true });
320
- } else if (name === 'modelValue') {
321
- this.validate({ clearCurrentResult: true });
322
- }
323
-
324
- if (
325
- [
326
- 'touched',
327
- 'dirty',
328
- 'prefilled',
329
- 'focused',
330
- 'submitted',
331
- 'hasFeedbackFor',
332
- 'filled',
333
- ].includes(name)
334
- ) {
335
- this._updateShouldShowFeedbackFor();
336
- }
337
-
338
- if (name === 'showsFeedbackFor') {
339
- // This can't be reflected asynchronously in Safari
340
- // Screen reader output should be in sync with visibility of error messages
341
- if (this._inputNode) {
342
- this._inputNode.setAttribute('aria-invalid', `${this._hasFeedbackVisibleFor('error')}`);
343
- // this._inputNode.setCustomValidity(this._validationMessage || '');
344
- }
345
-
346
- const diff = arrayDiff(this.showsFeedbackFor, oldValue);
347
- if (diff.length > 0) {
348
- this.dispatchEvent(new Event(`showsFeedbackForChanged`, { bubbles: true }));
349
- }
350
- diff.forEach(type => {
351
- this.dispatchEvent(
352
- new Event(`showsFeedbackFor${pascalCase(type)}Changed`, { bubbles: true }),
353
- );
354
- });
355
- }
356
-
357
- if (name === 'shouldShowFeedbackFor') {
358
- const diff = arrayDiff(this.shouldShowFeedbackFor, oldValue);
359
- if (diff.length > 0) {
360
- this.dispatchEvent(new Event(`shouldShowFeedbackForChanged`, { bubbles: true }));
361
- }
362
- }
363
- }
217
+ this.isPending = false;
364
218
 
365
219
  /**
366
- * Triggered by:
367
- * - modelValue change
368
- * - change in the 'validators' array
369
- * - change in the config of an individual Validator
370
- *
371
- * Three situations are handled:
372
- * - a1) the FormControl is empty: further execution is halted. When the Required Validator
373
- * (being mutually exclusive to the other Validators) is applied, it will end up in the
374
- * validation result (as the only Validator, since further execution was halted).
375
- * - a2) there are synchronous Validators: this is the most common flow. When modelValue hasn't
376
- * changed since last async results were generated, 'sync results' are merged with the
377
- * 'async results'.
378
- * - a3) there are asynchronous Validators: for instance when server side evaluation is needed.
379
- * Executions are scheduled and awaited and the 'async results' are merged with the
380
- * 'sync results'.
381
- *
382
- * - b) there are MetaValidators. After steps a1, a2, or a3 are finished, the holistic
383
- * MetaValidators (evaluating the total result of the 'regular' (a1, a2 and a3) validators)
384
- * will be run...
385
- *
386
- * Situations a2 and a3 are not mutually exclusive and can be triggered within one `validate()`
387
- * call. Situation b will occur after every call.
388
- *
389
- * @param {{ clearCurrentResult?: boolean }} opts
220
+ * Used by Application Developers to add Validators to a FormControl.
221
+ * @example
222
+ * ```html
223
+ * <form-control .validators="${[new Required(), new MinLength(4, {type: 'warning'})]}">
224
+ * </form-control>
225
+ * ```
226
+ * @type {Validator[]}
390
227
  */
391
- async validate({ clearCurrentResult = false } = {}) {
392
- /**
393
- * Allows Application Developer to wait for (async) validation
394
- * @example
395
- * ```js
396
- * await el.validateComplete;
397
- * ```
398
- * @type {Promise<boolean>}
399
- */
400
- this.validateComplete = new Promise(resolve => {
401
- this.__validateCompleteResolve = resolve;
402
- });
403
-
404
- if (this.disabled || this.readOnly) {
405
- this.__clearValidationResults();
406
- this.__finishValidationPass();
407
- this._updateFeedbackComponent();
408
- return;
409
- }
410
- // We don't validate before firstUpdated has run
411
- if (!this.__isValidateInitialized) {
412
- return;
413
- }
414
-
415
- this.__prevValidationResult = this.__validationResult;
416
- if (clearCurrentResult) {
417
- // Clear ('invalidate') all pending and existing validation results.
418
- // This is needed because we have async (pending) validators whose results
419
- // need to be merged with those of sync validators and vice versa.
420
- this.__clearValidationResults();
421
- }
422
- await this.__executeValidators();
423
- }
228
+ this.validators = [];
424
229
 
425
230
  /**
426
- * @param {Validator} validator
427
- * @returns {boolean}
231
+ * Used by Subclassers to add default Validators to a particular FormControl.
232
+ * A date input for instance, always needs the isDate validator.
233
+ * @example
234
+ * ```js
235
+ * this.defaultValidators.push(new IsDate());
236
+ * ```
237
+ * @type {Validator[]}
428
238
  */
429
- #isInstanceOfRequiredValidator(validator) {
430
- // walk prototype and check if validatorName is 'Required'
431
- let validatorLvlInPrototype = validator;
432
- while (validatorLvlInPrototype) {
433
- const ctor = /** @type {typeof Validator} */ (validatorLvlInPrototype.constructor);
434
- if (ctor.validatorName === 'Required') return true;
435
-
436
- validatorLvlInPrototype = Object.getPrototypeOf(validatorLvlInPrototype);
437
- }
438
- return false;
439
- }
239
+ this.defaultValidators = [];
440
240
 
441
241
  /**
442
- * @desc step a1-3 + b (as explained in `validate()`)
242
+ * The amount of feedback messages that will visible in LionValidationFeedback
243
+ * @configurable
244
+ * @protected
443
245
  */
444
- async __executeValidators() {
445
- const value = getValueForValidators(this.modelValue);
446
-
447
- /**
448
- * Handle the 'mutually exclusive' Required validator:
449
- *
450
- * About the Required Validator:
451
- * - the validity is dependent on the formControls' modelValue and therefore determined
452
- * by the formControl._isEmpty method. Basically, the Required Validator is a means
453
- * to trigger formControl._isEmpty().
454
- *
455
- * About the empty state:
456
- * - when _isEmpty returns true, the modelValue is considered empty. This means we need to stop
457
- * validation here, because all other Validators' execute functions assume the
458
- * value is not empty (there would be nothing to validate).
459
- *
460
- */
461
-
462
- const isEmpty = this.__isEmpty(value);
463
- this.__syncValidationResult = [];
464
-
465
- /**
466
- * So we can have the following scenarios:
467
- * - we're empty
468
- * - we have a single value (we are an 'endpoint') => we want to halt execution, because validation only makes sense when we have a value
469
- * - 1. we have Required => we fill .__syncValidationResult and finish validation, because we have a value to validate
470
- * - 2. we don't have Required => we stop validation
471
- * - we have a group of values (object/array) => we want to continue execution, because the constellation of the object (even though the individual endpoints are empty) might be interesting for validation.
472
- * - 3. we have Required => we fill .__syncValidationResult and continue validation (so we can add more to .__syncValidationResult)
473
- * - 4. we don't have Required => we continue validation
474
- * - we're not empty
475
- * - we have a single value or group of values
476
- * - 5. we may have Required, but if we have it will not be 'active' => we continue execution, because we have a value to validate
477
- */
478
-
479
- if (isEmpty) {
480
- const hasSingleValue = !(/** @type {* & ValidateHost} */ (this)._isFormOrFieldset);
481
- const requiredValidator = this._allValidators.find(
482
- v => /** @type {typeof Validator} */ (v.constructor)?.validatorName === 'Required',
483
- );
484
- if (requiredValidator) {
485
- this.__syncValidationResult = [{ validator: requiredValidator, outcome: true }];
486
- }
487
-
488
- if (hasSingleValue) {
489
- this.__finishValidationPass({
490
- syncValidationResult: this.__syncValidationResult,
491
- });
492
- return;
493
- }
494
- }
495
-
496
- const metaValidators = /** @type {MetaValidator[]} */ [];
497
- const syncValidators = /** @type {Validator[]} */ [];
498
- const asyncValidators = /** @type {Validator[]} */ [];
499
-
500
- for (const v of this._allValidators) {
501
- if (/** @type {MetaValidator} */ (v)?.executeOnResults) {
502
- metaValidators.push(/** @type {MetaValidator} */ (v));
503
- } else if (this.#isInstanceOfRequiredValidator(v)) {
504
- // Required validator was already handled
505
- } else if (/** @type {typeof Validator} */ (v.constructor).async) {
506
- asyncValidators.push(v);
507
- } else {
508
- syncValidators.push(v);
509
- }
510
- }
511
-
512
- const hasAsync = Boolean(asyncValidators.length);
513
-
514
- /**
515
- * 2. Synchronous validators
516
- */
517
-
518
- this.__syncValidationResult = [
519
- // This could eventually contain the Required Validator
520
- ...this.__syncValidationResult,
521
- ...this.__executeSyncValidators(syncValidators, value),
522
- ];
523
- // Finish the first (synchronous) pass
524
- this.__finishValidationPass({
525
- syncValidationResult: this.__syncValidationResult,
526
- metaValidators,
527
- });
528
-
529
- /**
530
- * 3. Asynchronous validators
531
- */
532
- if (hasAsync) {
533
- // Add a hint in the ui that we're waiting for async validation
534
- this.isPending = true;
535
- this.__asyncValidationResult = await this.__executeAsyncValidators(asyncValidators, value);
536
- this.isPending = false;
537
- // Now finish the second (asynchronous) pass (including both sync and async results)
538
- this.__finishValidationPass({
539
- syncValidationResult: this.__syncValidationResult,
540
- asyncValidationResult: this.__asyncValidationResult,
541
- metaValidators,
542
- });
543
- this.__validateCompleteResolve?.(true);
544
- } else {
545
- this.__validateCompleteResolve?.(true);
546
- }
547
- }
246
+ this._visibleMessagesAmount = 1;
548
247
 
549
248
  /**
550
- * step a2 (as explained in `validate()`): calls `__finishValidationPass`
551
- * @param {Validator[]} syncValidators
552
- * @param {unknown} value
249
+ * @type {ValidationResultEntry[]}
553
250
  * @private
554
251
  */
555
- __executeSyncValidators(syncValidators, value) {
556
- return syncValidators
557
- .map(v => ({
558
- validator: v,
559
- // TODO: fix this type - ts things this is not a FormControlHost?
560
- // @ts-ignore
561
- outcome: /** @type {boolean|string} */ (v.execute(value, v.param, { node: this })),
562
- }))
563
- .filter(v => Boolean(v.outcome));
564
- }
252
+ this.__syncValidationResult = [];
565
253
 
566
254
  /**
567
- * step a3 (as explained in `validate()`), calls __finishValidationPass
568
- * @param {Validator[]} asyncValidators all Validators except required and MetaValidators
569
- * @param {any} value
255
+ * @type {ValidationResultEntry[]}
570
256
  * @private
571
257
  */
572
- async __executeAsyncValidators(asyncValidators, value) {
573
- const outcomePromises = asyncValidators.map(v => v.execute(value, v.param, { node: this }));
574
- const asyncExecutionResults = await Promise.all(outcomePromises);
575
-
576
- return asyncExecutionResults
577
- .map((r, i) => ({
578
- validator: asyncValidators[i],
579
- outcome: /** @type {boolean|string} */ (asyncExecutionResults[i]),
580
- }))
581
- .filter(v => Boolean(v.outcome));
582
- }
258
+ this.__asyncValidationResult = [];
583
259
 
584
260
  /**
585
- * step b (as explained in `validate()`), called by __finishValidationPass
586
- * @param {{validator: Validator;outcome: boolean | string;}[]} regularValidationResult result of steps 1-3
587
- * @param {MetaValidator[]} metaValidators
261
+ * Aggregated result from sync Validators, async Validators and MetaValidators
262
+ * @type {ValidationResultEntry[]}
588
263
  * @private
589
264
  */
590
- __executeMetaValidators(regularValidationResult, metaValidators) {
591
- if (!metaValidators.length) {
592
- return [];
593
- }
594
-
595
- // If empty, do not show the ResultValidation message (e.g. Correct!)
596
- if (this._isEmpty(this.modelValue)) {
597
- this.__prevShownValidationResult = [];
598
- return [];
599
- }
600
-
601
- // Map everything to Validator[] for backwards compatibility
602
- return metaValidators
603
- .map(v => ({
604
- validator: v,
605
- outcome: /** @type {boolean|string} */ (
606
- v.executeOnResults({
607
- regularValidationResult: regularValidationResult.map(entry => entry.validator),
608
- prevValidationResult: this.__prevValidationResult.map(entry => entry.validator),
609
- prevShownValidationResult: this.__prevShownValidationResult.map(
610
- entry => entry.validator,
611
- ),
612
- })
613
- ),
614
- }))
615
- .filter(v => Boolean(v.outcome));
616
- }
265
+ this.__validationResult = [];
617
266
 
618
267
  /**
619
- * A 'pass' is a single run of the validation process, which will be triggered in these cases:
620
- * - on clear or disable
621
- * - on sync validation
622
- * - on async validation (can depend on server response)
623
- *
624
- * This method finishes a pass by adding the properties to the instance:
625
- * - validationStates
626
- * - hasFeedbackFor
627
- *
628
- * It sends a private event validate-performed, which is received by parent Formgroups.
629
- *
630
- * @param {object} options
631
- * @param {ValidationResultEntry[]} [options.syncValidationResult]
632
- * @param {ValidationResultEntry[]} [options.asyncValidationResult]
633
- * @param {MetaValidator[]} [options.metaValidators] MetaValidators to be executed
268
+ * @type {ValidationResultEntry[]}
634
269
  * @private
635
- * If not, we have nothing left to wait for.
636
270
  */
637
- __finishValidationPass({
638
- syncValidationResult = [],
639
- asyncValidationResult = [],
640
- metaValidators = [],
641
- } = {}) {
642
- const syncAndAsyncOutcome = [...syncValidationResult, ...asyncValidationResult];
643
- // if we have any MetaValidators left, now is the time to run them...
644
- const metaOutCome = /** @type {ValidationResultEntry[]} */ (
645
- this.__executeMetaValidators(syncAndAsyncOutcome, metaValidators)
646
- );
647
- this.__validationResult = [...metaOutCome, ...syncAndAsyncOutcome];
648
-
649
- const ctor = /** @type {ValidateHostConstructor} */ (this.constructor);
650
-
651
- /** @type {ValidationStates} */
652
- const validationStates = ctor.validationTypes.reduce(
653
- (acc, type) => ({ ...acc, [type]: {} }),
654
- {},
655
- );
656
- for (const { validator, outcome } of this.__validationResult) {
657
- if (!validationStates[validator.type]) {
658
- validationStates[validator.type] = {};
659
- }
660
- const vCtor = /** @type {typeof Validator} */ (validator.constructor);
661
- validationStates[validator.type][vCtor.validatorName] = outcome;
662
- }
663
- this.validationStates = validationStates;
664
-
665
- this.hasFeedbackFor = [
666
- ...new Set(this.__validationResult.map(({ validator }) => validator.type)),
667
- ];
668
- /** private event that should be listened to by LionFieldSet */
669
- this.dispatchEvent(new Event('validate-performed', { bubbles: true }));
670
- }
271
+ this.__prevValidationResult = [];
671
272
 
672
273
  /**
274
+ * The shown validation result depends on the visibility of the feedback messages
275
+ * @type {ValidationResultEntry[]}
673
276
  * @private
674
277
  */
675
- __clearValidationResults() {
676
- this.__syncValidationResult = [];
677
- this.__asyncValidationResult = [];
678
- }
679
-
680
- /**
681
- * @param {Event|CustomEvent} e
682
- * @protected
683
- */
684
- _onValidatorUpdated(e) {
685
- if (e.type === 'param-changed' || e.type === 'config-changed') {
686
- this.validate();
687
- }
688
- }
278
+ this.__prevShownValidationResult = [];
689
279
 
690
280
  /**
281
+ * The updated children validity affects the validity of the parent. Helper to recompute
282
+ * validity of parent FormGroup
691
283
  * @private
692
284
  */
693
- __setupValidators() {
694
- const events = ['param-changed', 'config-changed'];
695
-
696
- for (const validatorToCleanup of this.__prevValidators || []) {
697
- for (const eventToCleanup of events) {
698
- validatorToCleanup.removeEventListener?.(eventToCleanup, this._onValidatorUpdated);
699
- }
700
- validatorToCleanup.onFormControlDisconnect(
701
- /** @type {import('../../types/FormControlMixinTypes.js').FormControlHost} */ (
702
- /** @type {unknown} */ (this)
703
- ),
704
- );
285
+ this.__childModelValueChanged = false;
286
+
287
+ /** @protected */
288
+ this._onValidatorUpdated = this._onValidatorUpdated.bind(this);
289
+ /** @protected */
290
+ this._updateFeedbackComponent = this._updateFeedbackComponent.bind(this);
291
+ }
292
+ connectedCallback() {
293
+ super.connectedCallback();
294
+ const localizeManager = getLocalizeManager();
295
+ localizeManager.addEventListener('localeChanged', this._updateFeedbackComponent);
296
+ }
297
+ disconnectedCallback() {
298
+ super.disconnectedCallback();
299
+ const localizeManager = getLocalizeManager();
300
+ localizeManager.removeEventListener('localeChanged', this._updateFeedbackComponent);
301
+ }
302
+
303
+ /**
304
+ * @param {import('lit').PropertyValues} changedProperties
305
+ */
306
+ firstUpdated(changedProperties) {
307
+ super.firstUpdated(changedProperties);
308
+ this.__isValidateInitialized = true;
309
+ this.validate();
310
+ if (this._repropagationRole !== 'child') {
311
+ this.addEventListener('model-value-changed', () => {
312
+ this.__childModelValueChanged = true;
313
+ });
314
+ }
315
+ }
316
+
317
+ /**
318
+ * @param {string} name
319
+ * @param {any} oldValue
320
+ */
321
+ updateSync(name, oldValue) {
322
+ super.updateSync(name, oldValue);
323
+ if (name === 'validators') {
324
+ // trigger validation (ideally only for the new or changed validator)
325
+ this.__setupValidators();
326
+ this.validate({
327
+ clearCurrentResult: true
328
+ });
329
+ } else if (name === 'modelValue') {
330
+ this.validate({
331
+ clearCurrentResult: true
332
+ });
333
+ }
334
+ if (['touched', 'dirty', 'prefilled', 'focused', 'submitted', 'hasFeedbackFor', 'filled'].includes(name)) {
335
+ this._updateShouldShowFeedbackFor();
336
+ }
337
+ if (name === 'showsFeedbackFor') {
338
+ // This can't be reflected asynchronously in Safari
339
+ // Screen reader output should be in sync with visibility of error messages
340
+ if (this._inputNode) {
341
+ this._inputNode.setAttribute('aria-invalid', `${this._hasFeedbackVisibleFor('error')}`);
342
+ // this._inputNode.setCustomValidity(this._validationMessage || '');
705
343
  }
706
-
707
- for (const validatorToSetup of this._allValidators) {
708
- // disable dot notation to avoid the renaming for the prop during build/minification
709
- const validatorCtor = /** @type {typeof Validator} */ (validatorToSetup.constructor);
710
- // eslint-disable-next-line dot-notation
711
- if (validatorCtor['_$isValidator$'] === undefined) {
712
- // throws in constructor are not visible to end user so we do both
713
- const errorType = Array.isArray(validatorToSetup) ? 'array' : typeof validatorToSetup;
714
- const errorMessage = `Validators array only accepts class instances of Validator. Type "${errorType}" found. This may be caused by having multiple installations of "@lion/ui/form-core.js".`;
715
- // eslint-disable-next-line no-console
716
- console.error(errorMessage, this);
717
- throw new Error(errorMessage);
718
- }
719
- const ctor = /** @type {ValidateHostConstructor} */ (this.constructor);
720
- const vCtor = /** @type {typeof Validator} */ (validatorToSetup.constructor);
721
- if (ctor.validationTypes.indexOf(validatorToSetup.type) === -1) {
722
- // throws in constructor are not visible to end user so we do both
723
- const errorMessage = `This component does not support the validator type "${validatorToSetup.type}" used in "${vCtor.validatorName}". You may change your validators type or add it to the components "static get validationTypes() {}".`;
724
- // eslint-disable-next-line no-console
725
- console.error(errorMessage, this);
726
- throw new Error(errorMessage);
727
- }
728
-
729
- /**
730
- * Updated the code to fix issue #1607 to sync the calendar date with validators params
731
- * Here _onValidatorUpdated is responsible for responding to the event
732
- */
733
- for (const eventToSetup of events) {
734
- validatorToSetup.addEventListener?.(eventToSetup, e => {
735
- // @ts-ignore for making validator param dynamic
736
- this._onValidatorUpdated(e, { validator: validatorToSetup });
737
- });
738
- }
739
- validatorToSetup.onFormControlConnect(this);
344
+ const diff = arrayDiff(this.showsFeedbackFor, oldValue);
345
+ if (diff.length > 0) {
346
+ this.dispatchEvent(new Event(`showsFeedbackForChanged`, {
347
+ bubbles: true
348
+ }));
740
349
  }
741
- this.__prevValidators = this._allValidators;
350
+ diff.forEach(type => {
351
+ this.dispatchEvent(new Event(`showsFeedbackFor${pascalCase(type)}Changed`, {
352
+ bubbles: true
353
+ }));
354
+ });
742
355
  }
743
-
744
- /**
745
- * Helper method for the mutually exclusive Required Validator
746
- * @param {any} v
747
- * @private
748
- */
749
- __isEmpty(v) {
750
- if (typeof this._isEmpty === 'function') {
751
- return this._isEmpty(v);
356
+ if (name === 'shouldShowFeedbackFor') {
357
+ const diff = arrayDiff(this.shouldShowFeedbackFor, oldValue);
358
+ if (diff.length > 0) {
359
+ this.dispatchEvent(new Event(`shouldShowFeedbackForChanged`, {
360
+ bubbles: true
361
+ }));
752
362
  }
753
- return (
754
- this.modelValue === null || typeof this.modelValue === 'undefined' || this.modelValue === ''
755
- );
756
363
  }
757
-
758
- // ------------------------------------------------------------------------------------------
759
- // -- Feedback specifics --------------------------------------------------------------------
760
- // ------------------------------------------------------------------------------------------
761
-
762
- /**
763
- * @typedef {object} FeedbackMessage
764
- * @property {string | Node} message this
765
- * @property {string} type will be 'error' for messages from default Validators. Could be
766
- * 'warning', 'info' etc. for Validators with custom types. Needed as a directive for
767
- * feedbackNode how to render a message of a certain type
768
- * @property {number} visibilityDuration duration in ms for how long the message should be shown
769
- * @property {Validator} [validator] when the message is directly coupled to a Validator
770
- * (in most cases), this property is filled. When a message is not coupled to a Validator
771
- * (in case of success feedback which is based on a diff or current and previous validation
772
- * results), this property can be left empty.
773
- */
774
-
364
+ }
365
+
366
+ /**
367
+ * Triggered by:
368
+ * - modelValue change
369
+ * - change in the 'validators' array
370
+ * - change in the config of an individual Validator
371
+ *
372
+ * Three situations are handled:
373
+ * - a1) the FormControl is empty: further execution is halted. When the Required Validator
374
+ * (being mutually exclusive to the other Validators) is applied, it will end up in the
375
+ * validation result (as the only Validator, since further execution was halted).
376
+ * - a2) there are synchronous Validators: this is the most common flow. When modelValue hasn't
377
+ * changed since last async results were generated, 'sync results' are merged with the
378
+ * 'async results'.
379
+ * - a3) there are asynchronous Validators: for instance when server side evaluation is needed.
380
+ * Executions are scheduled and awaited and the 'async results' are merged with the
381
+ * 'sync results'.
382
+ *
383
+ * - b) there are MetaValidators. After steps a1, a2, or a3 are finished, the holistic
384
+ * MetaValidators (evaluating the total result of the 'regular' (a1, a2 and a3) validators)
385
+ * will be run...
386
+ *
387
+ * Situations a2 and a3 are not mutually exclusive and can be triggered within one `validate()`
388
+ * call. Situation b will occur after every call.
389
+ *
390
+ * @param {{ clearCurrentResult?: boolean }} opts
391
+ */
392
+ async validate({
393
+ clearCurrentResult = false
394
+ } = {}) {
775
395
  /**
776
- * @param {ValidationResultEntry[]} validationResults list of objects having a .getMessage method
777
- * @return {Promise.<FeedbackMessage[]>}
778
- * @private
396
+ * Allows Application Developer to wait for (async) validation
397
+ * @example
398
+ * ```js
399
+ * await el.validateComplete;
400
+ * ```
401
+ * @type {Promise<boolean>}
779
402
  */
780
- async __getFeedbackMessages(validationResults) {
781
- let fieldName = await this.fieldName;
782
- return Promise.all(
783
- validationResults.map(async ({ validator, outcome }) => {
784
- if (validator.config.fieldName) {
785
- fieldName = await validator.config.fieldName;
786
- }
787
- // @ts-ignore [allow-protected]
788
- const message = await validator._getMessage({
789
- modelValue: this.modelValue,
790
- formControl: this,
791
- fieldName,
792
- outcome,
793
- });
794
- return {
795
- message,
796
- type: validator.type,
797
- validator,
798
- visibilityDuration: validator.config?.visibilityDuration || 3000,
799
- };
800
- }),
801
- );
403
+ this.validateComplete = new Promise(resolve => {
404
+ this.__validateCompleteResolve = resolve;
405
+ });
406
+ if (this.disabled || this.readOnly) {
407
+ this.__clearValidationResults();
408
+ this.__finishValidationPass();
409
+ this._updateFeedbackComponent();
410
+ return;
411
+ }
412
+ // We don't validate before firstUpdated has run
413
+ if (!this.__isValidateInitialized) {
414
+ return;
415
+ }
416
+ this.__prevValidationResult = this.__validationResult;
417
+ if (clearCurrentResult) {
418
+ // Clear ('invalidate') all pending and existing validation results.
419
+ // This is needed because we have async (pending) validators whose results
420
+ // need to be merged with those of sync validators and vice versa.
421
+ this.__clearValidationResults();
802
422
  }
423
+ await this.__executeValidators();
424
+ }
425
+
426
+ /**
427
+ * @param {Validator} validator
428
+ * @returns {boolean}
429
+ */
430
+ #isInstanceOfRequiredValidator(validator) {
431
+ // walk prototype and check if validatorName is 'Required'
432
+ let validatorLvlInPrototype = validator;
433
+ while (validatorLvlInPrototype) {
434
+ const ctor = /** @type {typeof Validator} */validatorLvlInPrototype.constructor;
435
+ if (ctor.validatorName === 'Required') return true;
436
+ validatorLvlInPrototype = Object.getPrototypeOf(validatorLvlInPrototype);
437
+ }
438
+ return false;
439
+ }
440
+
441
+ /**
442
+ * @desc step a1-3 + b (as explained in `validate()`)
443
+ */
444
+ async __executeValidators() {
445
+ const value = getValueForValidators(this.modelValue);
803
446
 
804
447
  /**
805
- * Responsible for retrieving messages from Validators and
806
- * (delegation of) rendering them.
448
+ * Handle the 'mutually exclusive' Required validator:
807
449
  *
808
- * For `._feedbackNode` (extension of LionValidationFeedback):
809
- * - retrieve messages from highest prio Validators
810
- * - provide the result to custom feedback node and let the
811
- * custom node decide on their renderings
450
+ * About the Required Validator:
451
+ * - the validity is dependent on the formControls' modelValue and therefore determined
452
+ * by the formControl._isEmpty method. Basically, the Required Validator is a means
453
+ * to trigger formControl._isEmpty().
454
+ *
455
+ * About the empty state:
456
+ * - when _isEmpty returns true, the modelValue is considered empty. This means we need to stop
457
+ * validation here, because all other Validators' execute functions assume the
458
+ * value is not empty (there would be nothing to validate).
812
459
  *
813
- * In both cases:
814
- * - we compute the 'show' flag (like 'hasErrorVisible') for all types
815
- * - we set the customValidity message of the highest prio Validator
816
- * - we set aria-invalid="true" in case hasErrorVisible is true
817
- * @protected
818
460
  */
819
- _updateFeedbackComponent() {
820
- window.clearTimeout(this.removeMessage);
821
-
822
- const { _feedbackNode } = this;
823
- if (!_feedbackNode) {
824
- return;
825
- }
826
-
827
- if (!this.__feedbackQueue) {
828
- this.__feedbackQueue = new AsyncQueue();
829
- }
830
461
 
831
- if (this.showsFeedbackFor.length > 0) {
832
- this.__feedbackQueue.add(async () => {
833
- /** @type {Validator[]} */
834
- const prioritizedValidators = this._prioritizeAndFilterFeedback({
835
- validationResult: this.__validationResult.map(entry => entry.validator),
836
- });
837
-
838
- this.__prioritizedResult = prioritizedValidators
839
- .map(v => {
840
- const found = /** @type {ValidationResultEntry} */ (
841
- this.__validationResult.find(r => v === r.validator)
842
- );
843
- return found;
844
- })
845
- .filter(Boolean);
462
+ const isEmpty = this.__isEmpty(value);
463
+ this.__syncValidationResult = [];
846
464
 
847
- if (this.__prioritizedResult.length > 0) {
848
- this.__prevShownValidationResult = this.__prioritizedResult;
849
- }
850
-
851
- const messageMap = await this.__getFeedbackMessages(this.__prioritizedResult);
852
- _feedbackNode.feedbackData = messageMap || [];
465
+ /**
466
+ * So we can have the following scenarios:
467
+ * - we're empty
468
+ * - we have a single value (we are an 'endpoint') => we want to halt execution, because validation only makes sense when we have a value
469
+ * - 1. we have Required => we fill .__syncValidationResult and finish validation, because we have a value to validate
470
+ * - 2. we don't have Required => we stop validation
471
+ * - we have a group of values (object/array) => we want to continue execution, because the constellation of the object (even though the individual endpoints are empty) might be interesting for validation.
472
+ * - 3. we have Required => we fill .__syncValidationResult and continue validation (so we can add more to .__syncValidationResult)
473
+ * - 4. we don't have Required => we continue validation
474
+ * - we're not empty
475
+ * - we have a single value or group of values
476
+ * - 5. we may have Required, but if we have it will not be 'active' => we continue execution, because we have a value to validate
477
+ */
853
478
 
854
- if (
855
- messageMap?.[0] &&
856
- messageMap[0].type === 'success' &&
857
- messageMap[0].visibilityDuration !== Infinity
858
- ) {
859
- this.removeMessage = window.setTimeout(() => {
860
- _feedbackNode.removeAttribute('type');
861
- /** @type {FeedbackMessage[]} */
862
- _feedbackNode.feedbackData = [];
863
- }, messageMap[0].visibilityDuration);
864
- }
479
+ if (isEmpty) {
480
+ const hasSingleValue = !(/** @type {* & ValidateHost} */this._isFormOrFieldset);
481
+ const requiredValidator = this._allValidators.find(v => /** @type {typeof Validator} */v.constructor?.validatorName === 'Required');
482
+ if (requiredValidator) {
483
+ this.__syncValidationResult = [{
484
+ validator: requiredValidator,
485
+ outcome: true
486
+ }];
487
+ }
488
+ if (hasSingleValue) {
489
+ this.__finishValidationPass({
490
+ syncValidationResult: this.__syncValidationResult
865
491
  });
492
+ return;
493
+ }
494
+ }
495
+ const metaValidators = /** @type {MetaValidator[]} */[];
496
+ const syncValidators = /** @type {Validator[]} */[];
497
+ const asyncValidators = /** @type {Validator[]} */[];
498
+ for (const v of this._allValidators) {
499
+ if (/** @type {MetaValidator} */v?.executeOnResults) {
500
+ metaValidators.push(/** @type {MetaValidator} */v);
501
+ } else if (this.#isInstanceOfRequiredValidator(v)) {
502
+ // Required validator was already handled
503
+ } else if (/** @type {typeof Validator} */v.constructor.async) {
504
+ asyncValidators.push(v);
866
505
  } else {
867
- this.__feedbackQueue.add(async () => {
868
- _feedbackNode.feedbackData = [];
869
- });
506
+ syncValidators.push(v);
870
507
  }
871
- this.feedbackComplete = this.__feedbackQueue.complete;
872
508
  }
509
+ const hasAsync = Boolean(asyncValidators.length);
873
510
 
874
511
  /**
875
- * Default feedbackCondition condition, used by Subclassers, that will be used when
876
- * `feedbackCondition()` is not overridden by Application Developer.
877
- * Show the validity feedback when returning true, don't show when false
878
- * @param {string} type could be 'error', 'warning', 'info', 'success' or any other custom
879
- * Validator type
880
- * @param {object} meta meta info (interaction states etc)
881
- * @protected
512
+ * 2. Synchronous validators
882
513
  */
883
- // eslint-disable-next-line no-unused-vars
884
- _showFeedbackConditionFor(type, meta) {
885
- return true;
886
- }
887
514
 
888
- /**
889
- * Allows Subclassers to add meta info for feedbackCondition
890
- * @configurable
891
- */
892
- get _feedbackConditionMeta() {
893
- return { modelValue: this.modelValue, el: this };
894
- }
515
+ this.__syncValidationResult = [
516
+ // This could eventually contain the Required Validator
517
+ ...this.__syncValidationResult, ...this.__executeSyncValidators(syncValidators, value)];
518
+ // Finish the first (synchronous) pass
519
+ this.__finishValidationPass({
520
+ syncValidationResult: this.__syncValidationResult,
521
+ metaValidators
522
+ });
895
523
 
896
524
  /**
897
- * Allows the Application Developer to specify when a feedback message should be shown
898
- * @example
899
- * ```js
900
- * feedbackCondition(type, meta, defaultCondition) {
901
- * if (type === 'info') {
902
- * return true;
903
- * } else if (type === 'prefilledOnly') {
904
- * return meta.prefilled;
905
- * }
906
- * return defaultCondition(type, meta);
907
- * }
908
- * ```
909
- * @overridable
910
- * @param {string} type could be 'error', 'warning', 'info', 'success' or any other custom
911
- * Validator type
912
- * @param {object} meta meta info (interaction states etc)
913
- * @param {((type: string, meta: object) => boolean)} currentCondition this is the _showFeedbackConditionFor
914
- * that can be used if a developer wants to override for a certain type, but wants to fallback
915
- * for other types
916
- * @returns {boolean}
525
+ * 3. Asynchronous validators
917
526
  */
918
- feedbackCondition(
919
- type,
920
- meta = this._feedbackConditionMeta,
921
- currentCondition = this._showFeedbackConditionFor.bind(this),
922
- ) {
923
- return currentCondition(type, meta);
527
+ if (hasAsync) {
528
+ // Add a hint in the ui that we're waiting for async validation
529
+ this.isPending = true;
530
+ this.__asyncValidationResult = await this.__executeAsyncValidators(asyncValidators, value);
531
+ this.isPending = false;
532
+ // Now finish the second (asynchronous) pass (including both sync and async results)
533
+ this.__finishValidationPass({
534
+ syncValidationResult: this.__syncValidationResult,
535
+ asyncValidationResult: this.__asyncValidationResult,
536
+ metaValidators
537
+ });
538
+ this.__validateCompleteResolve?.(true);
539
+ } else {
540
+ this.__validateCompleteResolve?.(true);
924
541
  }
925
-
926
- /**
927
- * Used to translate `.hasFeedbackFor` and `.shouldShowFeedbackFor` to `.showsFeedbackFor`
928
- * @param {string} type
929
- * @protected
930
- */
931
- _hasFeedbackVisibleFor(type) {
932
- return this.hasFeedbackFor?.includes(type) && this.shouldShowFeedbackFor?.includes(type);
542
+ }
543
+
544
+ /**
545
+ * step a2 (as explained in `validate()`): calls `__finishValidationPass`
546
+ * @param {Validator[]} syncValidators
547
+ * @param {unknown} value
548
+ * @private
549
+ */
550
+ __executeSyncValidators(syncValidators, value) {
551
+ return syncValidators.map(v => ({
552
+ validator: v,
553
+ // TODO: fix this type - ts things this is not a FormControlHost?
554
+ // @ts-ignore
555
+ outcome: (/** @type {boolean|string} */v.execute(value, v.param, {
556
+ node: this
557
+ }))
558
+ })).filter(v => Boolean(v.outcome));
559
+ }
560
+
561
+ /**
562
+ * step a3 (as explained in `validate()`), calls __finishValidationPass
563
+ * @param {Validator[]} asyncValidators all Validators except required and MetaValidators
564
+ * @param {any} value
565
+ * @private
566
+ */
567
+ async __executeAsyncValidators(asyncValidators, value) {
568
+ const outcomePromises = asyncValidators.map(v => v.execute(value, v.param, {
569
+ node: this
570
+ }));
571
+ const asyncExecutionResults = await Promise.all(outcomePromises);
572
+ return asyncExecutionResults.map((r, i) => ({
573
+ validator: asyncValidators[i],
574
+ outcome: (/** @type {boolean|string} */asyncExecutionResults[i])
575
+ })).filter(v => Boolean(v.outcome));
576
+ }
577
+
578
+ /**
579
+ * step b (as explained in `validate()`), called by __finishValidationPass
580
+ * @param {{validator: Validator;outcome: boolean | string;}[]} regularValidationResult result of steps 1-3
581
+ * @param {MetaValidator[]} metaValidators
582
+ * @private
583
+ */
584
+ __executeMetaValidators(regularValidationResult, metaValidators) {
585
+ if (!metaValidators.length) {
586
+ return [];
933
587
  }
934
588
 
935
- /**
936
- * @param {import('lit').PropertyValues} changedProperties
937
- */
938
- updated(changedProperties) {
939
- super.updated(changedProperties);
589
+ // If empty, do not show the ResultValidation message (e.g. Correct!)
590
+ if (this._isEmpty(this.modelValue)) {
591
+ this.__prevShownValidationResult = [];
592
+ return [];
593
+ }
940
594
 
941
- if (
942
- changedProperties.has('shouldShowFeedbackFor') ||
943
- changedProperties.has('hasFeedbackFor')
944
- ) {
945
- const ctor = /** @type {ValidateHostConstructor} */ (this.constructor);
946
- // Necessary typecast because types aren't smart enough to understand that we filter out undefined
947
- this.showsFeedbackFor = /** @type {string[]} */ (
948
- ctor.validationTypes
949
- .map(type => (this._hasFeedbackVisibleFor(type) ? type : undefined))
950
- .filter(Boolean)
951
- );
952
- this._updateFeedbackComponent();
595
+ // Map everything to Validator[] for backwards compatibility
596
+ return metaValidators.map(v => ({
597
+ validator: v,
598
+ outcome: (/** @type {boolean|string} */
599
+ v.executeOnResults({
600
+ regularValidationResult: regularValidationResult.map(entry => entry.validator),
601
+ prevValidationResult: this.__prevValidationResult.map(entry => entry.validator),
602
+ prevShownValidationResult: this.__prevShownValidationResult.map(entry => entry.validator)
603
+ }))
604
+ })).filter(v => Boolean(v.outcome));
605
+ }
606
+
607
+ /**
608
+ * A 'pass' is a single run of the validation process, which will be triggered in these cases:
609
+ * - on clear or disable
610
+ * - on sync validation
611
+ * - on async validation (can depend on server response)
612
+ *
613
+ * This method finishes a pass by adding the properties to the instance:
614
+ * - validationStates
615
+ * - hasFeedbackFor
616
+ *
617
+ * It sends a private event validate-performed, which is received by parent Formgroups.
618
+ *
619
+ * @param {object} options
620
+ * @param {ValidationResultEntry[]} [options.syncValidationResult]
621
+ * @param {ValidationResultEntry[]} [options.asyncValidationResult]
622
+ * @param {MetaValidator[]} [options.metaValidators] MetaValidators to be executed
623
+ * @private
624
+ * If not, we have nothing left to wait for.
625
+ */
626
+ __finishValidationPass({
627
+ syncValidationResult = [],
628
+ asyncValidationResult = [],
629
+ metaValidators = []
630
+ } = {}) {
631
+ const syncAndAsyncOutcome = [...syncValidationResult, ...asyncValidationResult];
632
+ // if we have any MetaValidators left, now is the time to run them...
633
+ const metaOutCome = /** @type {ValidationResultEntry[]} */
634
+ this.__executeMetaValidators(syncAndAsyncOutcome, metaValidators);
635
+ this.__validationResult = [...metaOutCome, ...syncAndAsyncOutcome];
636
+ const ctor = /** @type {ValidateHostConstructor} */this.constructor;
637
+
638
+ /** @type {ValidationStates} */
639
+ const validationStates = ctor.validationTypes.reduce((acc, type) => ({
640
+ ...acc,
641
+ [type]: {}
642
+ }), {});
643
+ for (const {
644
+ validator,
645
+ outcome
646
+ } of this.__validationResult) {
647
+ if (!validationStates[validator.type]) {
648
+ validationStates[validator.type] = {};
953
649
  }
954
-
955
- if (changedProperties.has('__childModelValueChanged') && this.__childModelValueChanged) {
956
- this.validate({ clearCurrentResult: true });
957
- this.__childModelValueChanged = false;
650
+ const vCtor = /** @type {typeof Validator} */validator.constructor;
651
+ validationStates[validator.type][vCtor.validatorName] = outcome;
652
+ }
653
+ this.validationStates = validationStates;
654
+ this.hasFeedbackFor = [...new Set(this.__validationResult.map(({
655
+ validator
656
+ }) => validator.type))];
657
+ /** private event that should be listened to by LionFieldSet */
658
+ this.dispatchEvent(new Event('validate-performed', {
659
+ bubbles: true
660
+ }));
661
+ }
662
+
663
+ /**
664
+ * @private
665
+ */
666
+ __clearValidationResults() {
667
+ this.__syncValidationResult = [];
668
+ this.__asyncValidationResult = [];
669
+ }
670
+
671
+ /**
672
+ * @param {Event|CustomEvent} e
673
+ * @protected
674
+ */
675
+ _onValidatorUpdated(e) {
676
+ if (e.type === 'param-changed' || e.type === 'config-changed') {
677
+ this.validate();
678
+ }
679
+ }
680
+
681
+ /**
682
+ * @private
683
+ */
684
+ __setupValidators() {
685
+ const events = ['param-changed', 'config-changed'];
686
+ for (const validatorToCleanup of this.__prevValidators || []) {
687
+ for (const eventToCleanup of events) {
688
+ validatorToCleanup.removeEventListener?.(eventToCleanup, this._onValidatorUpdated);
689
+ }
690
+ validatorToCleanup.onFormControlDisconnect(/** @type {import('../../types/FormControlMixinTypes.js').FormControlHost} */
691
+ /** @type {unknown} */this);
692
+ }
693
+ for (const validatorToSetup of this._allValidators) {
694
+ // disable dot notation to avoid the renaming for the prop during build/minification
695
+ const validatorCtor = /** @type {typeof Validator} */validatorToSetup.constructor;
696
+ // eslint-disable-next-line dot-notation
697
+ if (validatorCtor['_$isValidator$'] === undefined) {
698
+ // throws in constructor are not visible to end user so we do both
699
+ const errorType = Array.isArray(validatorToSetup) ? 'array' : typeof validatorToSetup;
700
+ const errorMessage = `Validators array only accepts class instances of Validator. Type "${errorType}" found. This may be caused by having multiple installations of "@lion/ui/form-core.js".`;
701
+ // eslint-disable-next-line no-console
702
+ console.error(errorMessage, this);
703
+ throw new Error(errorMessage);
704
+ }
705
+ const ctor = /** @type {ValidateHostConstructor} */this.constructor;
706
+ const vCtor = /** @type {typeof Validator} */validatorToSetup.constructor;
707
+ if (ctor.validationTypes.indexOf(validatorToSetup.type) === -1) {
708
+ // throws in constructor are not visible to end user so we do both
709
+ const errorMessage = `This component does not support the validator type "${validatorToSetup.type}" used in "${vCtor.validatorName}". You may change your validators type or add it to the components "static get validationTypes() {}".`;
710
+ // eslint-disable-next-line no-console
711
+ console.error(errorMessage, this);
712
+ throw new Error(errorMessage);
958
713
  }
959
714
 
960
- if (changedProperties.has('validationStates')) {
961
- const prevStates = /** @type {{[key: string]: object;}} */ (
962
- changedProperties.get('validationStates')
963
- );
964
- if (prevStates) {
965
- Object.entries(this.validationStates).forEach(([type, feedbackObj]) => {
966
- if (
967
- prevStates[type] &&
968
- JSON.stringify(feedbackObj) !== JSON.stringify(prevStates[type])
969
- ) {
970
- this.dispatchEvent(new CustomEvent(`${type}StateChanged`, { detail: feedbackObj }));
971
- }
715
+ /**
716
+ * Updated the code to fix issue #1607 to sync the calendar date with validators params
717
+ * Here _onValidatorUpdated is responsible for responding to the event
718
+ */
719
+ for (const eventToSetup of events) {
720
+ validatorToSetup.addEventListener?.(eventToSetup, e => {
721
+ // @ts-ignore for making validator param dynamic
722
+ this._onValidatorUpdated(e, {
723
+ validator: validatorToSetup
972
724
  });
973
- }
725
+ });
974
726
  }
727
+ validatorToSetup.onFormControlConnect(this);
975
728
  }
976
-
977
- /**
978
- * @protected
979
- */
980
- _updateShouldShowFeedbackFor() {
981
- const ctor = /** @type {ValidateHostConstructor} */ (this.constructor);
982
-
729
+ this.__prevValidators = this._allValidators;
730
+ }
731
+
732
+ /**
733
+ * Helper method for the mutually exclusive Required Validator
734
+ * @param {any} v
735
+ * @private
736
+ */
737
+ __isEmpty(v) {
738
+ if (typeof this._isEmpty === 'function') {
739
+ return this._isEmpty(v);
740
+ }
741
+ return this.modelValue === null || typeof this.modelValue === 'undefined' || this.modelValue === '';
742
+ }
743
+
744
+ // ------------------------------------------------------------------------------------------
745
+ // -- Feedback specifics --------------------------------------------------------------------
746
+ // ------------------------------------------------------------------------------------------
747
+
748
+ /**
749
+ * @typedef {object} FeedbackMessage
750
+ * @property {string | Node} message this
751
+ * @property {string} type will be 'error' for messages from default Validators. Could be
752
+ * 'warning', 'info' etc. for Validators with custom types. Needed as a directive for
753
+ * feedbackNode how to render a message of a certain type
754
+ * @property {number} visibilityDuration duration in ms for how long the message should be shown
755
+ * @property {Validator} [validator] when the message is directly coupled to a Validator
756
+ * (in most cases), this property is filled. When a message is not coupled to a Validator
757
+ * (in case of success feedback which is based on a diff or current and previous validation
758
+ * results), this property can be left empty.
759
+ */
760
+
761
+ /**
762
+ * @param {ValidationResultEntry[]} validationResults list of objects having a .getMessage method
763
+ * @return {Promise.<FeedbackMessage[]>}
764
+ * @private
765
+ */
766
+ async __getFeedbackMessages(validationResults) {
767
+ let fieldName = await this.fieldName;
768
+ return Promise.all(validationResults.map(async ({
769
+ validator,
770
+ outcome
771
+ }) => {
772
+ if (validator.config.fieldName) {
773
+ fieldName = await validator.config.fieldName;
774
+ }
775
+ // @ts-ignore [allow-protected]
776
+ const message = await validator._getMessage({
777
+ modelValue: this.modelValue,
778
+ formControl: this,
779
+ fieldName,
780
+ outcome
781
+ });
782
+ return {
783
+ message,
784
+ type: validator.type,
785
+ validator,
786
+ visibilityDuration: validator.config?.visibilityDuration || 3000
787
+ };
788
+ }));
789
+ }
790
+
791
+ /**
792
+ * Responsible for retrieving messages from Validators and
793
+ * (delegation of) rendering them.
794
+ *
795
+ * For `._feedbackNode` (extension of LionValidationFeedback):
796
+ * - retrieve messages from highest prio Validators
797
+ * - provide the result to custom feedback node and let the
798
+ * custom node decide on their renderings
799
+ *
800
+ * In both cases:
801
+ * - we compute the 'show' flag (like 'hasErrorVisible') for all types
802
+ * - we set the customValidity message of the highest prio Validator
803
+ * - we set aria-invalid="true" in case hasErrorVisible is true
804
+ * @protected
805
+ */
806
+ _updateFeedbackComponent() {
807
+ window.clearTimeout(this.removeMessage);
808
+ const {
809
+ _feedbackNode
810
+ } = this;
811
+ if (!_feedbackNode) {
812
+ return;
813
+ }
814
+ if (!this.__feedbackQueue) {
815
+ this.__feedbackQueue = new AsyncQueue();
816
+ }
817
+ if (this.showsFeedbackFor.length > 0) {
818
+ this.__feedbackQueue.add(async () => {
819
+ /** @type {Validator[]} */
820
+ const prioritizedValidators = this._prioritizeAndFilterFeedback({
821
+ validationResult: this.__validationResult.map(entry => entry.validator)
822
+ });
823
+ this.__prioritizedResult = prioritizedValidators.map(v => {
824
+ const found = /** @type {ValidationResultEntry} */
825
+ this.__validationResult.find(r => v === r.validator);
826
+ return found;
827
+ }).filter(Boolean);
828
+ if (this.__prioritizedResult.length > 0) {
829
+ this.__prevShownValidationResult = this.__prioritizedResult;
830
+ }
831
+ const messageMap = await this.__getFeedbackMessages(this.__prioritizedResult);
832
+ _feedbackNode.feedbackData = messageMap || [];
833
+ if (messageMap?.[0] && messageMap[0].type === 'success' && messageMap[0].visibilityDuration !== Infinity) {
834
+ this.removeMessage = window.setTimeout(() => {
835
+ _feedbackNode.removeAttribute('type');
836
+ /** @type {FeedbackMessage[]} */
837
+ _feedbackNode.feedbackData = [];
838
+ }, messageMap[0].visibilityDuration);
839
+ }
840
+ });
841
+ } else {
842
+ this.__feedbackQueue.add(async () => {
843
+ _feedbackNode.feedbackData = [];
844
+ });
845
+ }
846
+ this.feedbackComplete = this.__feedbackQueue.complete;
847
+ }
848
+
849
+ /**
850
+ * Default feedbackCondition condition, used by Subclassers, that will be used when
851
+ * `feedbackCondition()` is not overridden by Application Developer.
852
+ * Show the validity feedback when returning true, don't show when false
853
+ * @param {string} type could be 'error', 'warning', 'info', 'success' or any other custom
854
+ * Validator type
855
+ * @param {object} meta meta info (interaction states etc)
856
+ * @protected
857
+ */
858
+ // eslint-disable-next-line no-unused-vars
859
+ _showFeedbackConditionFor(type, meta) {
860
+ return true;
861
+ }
862
+
863
+ /**
864
+ * Allows Subclassers to add meta info for feedbackCondition
865
+ * @configurable
866
+ */
867
+ get _feedbackConditionMeta() {
868
+ return {
869
+ modelValue: this.modelValue,
870
+ el: this
871
+ };
872
+ }
873
+
874
+ /**
875
+ * Allows the Application Developer to specify when a feedback message should be shown
876
+ * @example
877
+ * ```js
878
+ * feedbackCondition(type, meta, defaultCondition) {
879
+ * if (type === 'info') {
880
+ * return true;
881
+ * } else if (type === 'prefilledOnly') {
882
+ * return meta.prefilled;
883
+ * }
884
+ * return defaultCondition(type, meta);
885
+ * }
886
+ * ```
887
+ * @overridable
888
+ * @param {string} type could be 'error', 'warning', 'info', 'success' or any other custom
889
+ * Validator type
890
+ * @param {object} meta meta info (interaction states etc)
891
+ * @param {((type: string, meta: object) => boolean)} currentCondition this is the _showFeedbackConditionFor
892
+ * that can be used if a developer wants to override for a certain type, but wants to fallback
893
+ * for other types
894
+ * @returns {boolean}
895
+ */
896
+ feedbackCondition(type, meta = this._feedbackConditionMeta, currentCondition = this._showFeedbackConditionFor.bind(this)) {
897
+ return currentCondition(type, meta);
898
+ }
899
+
900
+ /**
901
+ * Used to translate `.hasFeedbackFor` and `.shouldShowFeedbackFor` to `.showsFeedbackFor`
902
+ * @param {string} type
903
+ * @protected
904
+ */
905
+ _hasFeedbackVisibleFor(type) {
906
+ return this.hasFeedbackFor?.includes(type) && this.shouldShowFeedbackFor?.includes(type);
907
+ }
908
+
909
+ /**
910
+ * @param {import('lit').PropertyValues} changedProperties
911
+ */
912
+ updated(changedProperties) {
913
+ super.updated(changedProperties);
914
+ if (changedProperties.has('shouldShowFeedbackFor') || changedProperties.has('hasFeedbackFor')) {
915
+ const ctor = /** @type {ValidateHostConstructor} */this.constructor;
983
916
  // Necessary typecast because types aren't smart enough to understand that we filter out undefined
984
- const newShouldShowFeedbackFor = /** @type {string[]} */ (
985
- ctor.validationTypes
986
- .map(type =>
987
- this.feedbackCondition(
988
- type,
989
- this._feedbackConditionMeta,
990
- this._showFeedbackConditionFor.bind(this),
991
- )
992
- ? type
993
- : undefined,
994
- )
995
- .filter(Boolean)
996
- );
997
-
998
- if (JSON.stringify(this.shouldShowFeedbackFor) !== JSON.stringify(newShouldShowFeedbackFor)) {
999
- this.shouldShowFeedbackFor = newShouldShowFeedbackFor;
917
+ this.showsFeedbackFor = /** @type {string[]} */
918
+ ctor.validationTypes.map(type => this._hasFeedbackVisibleFor(type) ? type : undefined).filter(Boolean);
919
+ this._updateFeedbackComponent();
920
+ }
921
+ if (changedProperties.has('__childModelValueChanged') && this.__childModelValueChanged) {
922
+ this.validate({
923
+ clearCurrentResult: true
924
+ });
925
+ this.__childModelValueChanged = false;
926
+ }
927
+ if (changedProperties.has('validationStates')) {
928
+ const prevStates = /** @type {{[key: string]: object;}} */
929
+ changedProperties.get('validationStates');
930
+ if (prevStates) {
931
+ Object.entries(this.validationStates).forEach(([type, feedbackObj]) => {
932
+ if (prevStates[type] && JSON.stringify(feedbackObj) !== JSON.stringify(prevStates[type])) {
933
+ this.dispatchEvent(new CustomEvent(`${type}StateChanged`, {
934
+ detail: feedbackObj
935
+ }));
936
+ }
937
+ });
1000
938
  }
1001
939
  }
1002
-
1003
- /**
1004
- * Orders all active validators in this.__validationResult.
1005
- * Can also filter out occurrences (based on interaction states)
1006
- * @overridable
1007
- * @param {{ validationResult: Validator[] }} opts
1008
- * @return {Validator[]} ordered list of Validators with feedback messages visible to the end user
1009
- * @protected
1010
- */
1011
- _prioritizeAndFilterFeedback({ validationResult }) {
1012
- const ctor = /** @type {ValidateHostConstructor} */ (this.constructor);
1013
- const types = ctor.validationTypes;
1014
- // Sort all validators based on the type provided.
1015
- const res = validationResult
1016
- .filter(v =>
1017
- this.feedbackCondition(
1018
- v.type,
1019
- this._feedbackConditionMeta,
1020
- this._showFeedbackConditionFor.bind(this),
1021
- ),
1022
- )
1023
- .sort((a, b) => types.indexOf(a.type) - types.indexOf(b.type));
1024
- return res.slice(0, this._visibleMessagesAmount);
940
+ }
941
+
942
+ /**
943
+ * @protected
944
+ */
945
+ _updateShouldShowFeedbackFor() {
946
+ const ctor = /** @type {ValidateHostConstructor} */this.constructor;
947
+
948
+ // Necessary typecast because types aren't smart enough to understand that we filter out undefined
949
+ const newShouldShowFeedbackFor = /** @type {string[]} */
950
+ ctor.validationTypes.map(type => this.feedbackCondition(type, this._feedbackConditionMeta, this._showFeedbackConditionFor.bind(this)) ? type : undefined).filter(Boolean);
951
+ if (JSON.stringify(this.shouldShowFeedbackFor) !== JSON.stringify(newShouldShowFeedbackFor)) {
952
+ this.shouldShowFeedbackFor = newShouldShowFeedbackFor;
1025
953
  }
1026
- });
1027
-
954
+ }
955
+
956
+ /**
957
+ * Orders all active validators in this.__validationResult.
958
+ * Can also filter out occurrences (based on interaction states)
959
+ * @overridable
960
+ * @param {{ validationResult: Validator[] }} opts
961
+ * @return {Validator[]} ordered list of Validators with feedback messages visible to the end user
962
+ * @protected
963
+ */
964
+ _prioritizeAndFilterFeedback({
965
+ validationResult
966
+ }) {
967
+ const ctor = /** @type {ValidateHostConstructor} */this.constructor;
968
+ const types = ctor.validationTypes;
969
+ // Sort all validators based on the type provided.
970
+ const res = validationResult.filter(v => this.feedbackCondition(v.type, this._feedbackConditionMeta, this._showFeedbackConditionFor.bind(this))).sort((a, b) => types.indexOf(a.type) - types.indexOf(b.type));
971
+ return res.slice(0, this._visibleMessagesAmount);
972
+ }
973
+ };
1028
974
  export const ValidateMixin = dedupeMixin(ValidateMixinImplementation);