@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.
- package/README.md +50 -20
- package/components/accordion/src/LionAccordion.js +31 -42
- package/components/accordion/test/lion-accordion.test.js +108 -134
- package/components/button/src/LionButton.js +9 -12
- package/components/button/src/LionButtonReset.js +0 -5
- package/components/button/src/LionButtonSubmit.js +7 -12
- package/components/button/test/demos.screenshots-test.js +50 -11
- package/components/button/test/lion-button.test.js +0 -1
- package/components/button/test-suites/LionButton.suite.js +135 -145
- package/components/button/test-suites/LionButtonReset.suite.js +54 -72
- package/components/button/test-suites/LionButtonSubmit.suite.js +49 -68
- package/components/calendar/src/LionCalendar.js +151 -104
- package/components/calendar/src/calendarStyle.js +0 -1
- package/components/calendar/src/utils/createMonth.js +3 -4
- package/components/calendar/src/utils/createMultipleMonth.js +15 -7
- package/components/calendar/src/utils/createWeek.js +0 -2
- package/components/calendar/src/utils/dataTemplate.js +8 -4
- package/components/calendar/src/utils/dayTemplate.js +0 -6
- package/components/calendar/src/utils/getDayMonthYear.js +6 -2
- package/components/calendar/test/demos.screenshots-test.js +40 -9
- package/components/calendar/test/lion-calendar.test.js +171 -282
- package/components/calendar/test/utils/createMonth.test.js +61 -22
- package/components/calendar/test/utils/createMultipleMonth.test.js +14 -7
- package/components/calendar/test/utils/createWeek.test.js +51 -17
- package/components/calendar/test/utils/dataTemplate.test.js +3 -4
- package/components/calendar/test/utils/dayTemplate.test.js +106 -34
- package/components/calendar/test/utils/getFirstDayNextMonth.test.js +0 -1
- package/components/calendar/test/utils/getLastDayPreviousMonth.test.js +0 -1
- package/components/calendar/test/utils/isSameDate.test.js +0 -1
- package/components/calendar/test/utils/snapshots/monthTemplate_en-GB_Sunday_2018-12.js +1 -2
- package/components/calendar/test-helpers/CalendarObject.js +31 -62
- package/components/calendar/test-helpers/DayObject.js +7 -15
- package/components/calendar/test-suites/LionCalendar.suite.js +7 -9
- package/components/checkbox-group/src/LionCheckboxIndeterminate.js +17 -30
- package/components/checkbox-group/test/lion-checkbox-group-integrations.test.js +0 -1
- package/components/checkbox-group/test/lion-checkbox-group.test.js +21 -16
- package/components/checkbox-group/test/lion-checkbox-indeterminate-integrations.test.js +3 -3
- package/components/checkbox-group/test/lion-checkbox-integrations.test.js +3 -2
- package/components/checkbox-group/test/lion-checkbox.test.js +30 -16
- package/components/checkbox-group/test-suites/CheckboxIndeterminate.suite.js +147 -191
- package/components/collapsible/src/LionCollapsible.js +10 -15
- package/components/collapsible/test/lion-collapsible.test.js +4 -18
- package/components/combobox/src/LionCombobox.js +35 -53
- package/components/combobox/src/utils/makeMatchingTextBold.js +2 -5
- package/components/combobox/src/validators.js +0 -1
- package/components/combobox/test/lion-combobox-integrations.test.js +6 -6
- package/components/combobox/test/lion-combobox.test.js +576 -869
- package/components/combobox/test/validators.test.js +6 -13
- package/components/combobox/test-helpers/combobox-helpers.js +24 -11
- package/components/core/src/DisabledMixin.js +61 -66
- package/components/core/src/DisabledWithTabIndexMixin.js +76 -83
- package/components/core/src/EventTargetShim.js +1 -4
- package/components/core/src/ScopedElementsMixin.js +4 -15
- package/components/core/src/ScopedStylesController.js +1 -5
- package/components/core/src/SlotMixin.js +236 -239
- package/components/core/src/browserDetection.js +5 -12
- package/components/core/test/DisabledMixin.test.js +24 -39
- package/components/core/test/DisabledWithTabIndexMixin.test.js +21 -34
- package/components/core/test/EventTargetShim.test.js +0 -8
- package/components/core/test/ScopedElementsMixin.test.js +22 -38
- package/components/core/test/ScopedStylesController.test.js +11 -20
- package/components/core/test/SlotMixin.test.js +102 -154
- package/components/core/test-helpers/getCachedFixture.js +5 -11
- package/components/core/types/SlotMixinTypes.ts +8 -3
- package/components/dialog/src/LionDialog.js +4 -3
- package/components/dialog/test/lion-dialog.integration.test.js +10 -20
- package/components/dialog/test/lion-dialog.test.js +48 -62
- package/components/dialog/test-helpers/test-router.js +4 -6
- package/components/drawer/src/LionDrawer.js +18 -34
- package/components/drawer/src/drawerStyle.js +0 -1
- package/components/drawer/test/lion-drawer.test.js +1 -17
- package/components/fieldset/test/lion-fieldset.test.js +6 -4
- package/components/form/src/LionForm.js +18 -13
- package/components/form/test/lion-form.test.js +22 -52
- package/components/form-core/src/FocusMixin.js +172 -174
- package/components/form-core/src/FormControlMixin.js +811 -813
- package/components/form-core/src/FormatMixin.js +537 -537
- package/components/form-core/src/InteractionStateMixin.js +196 -183
- package/components/form-core/src/LionField.js +9 -5
- package/components/form-core/src/NativeTextFieldMixin.js +114 -116
- package/components/form-core/src/choice-group/ChoiceGroupMixin.js +322 -364
- package/components/form-core/src/choice-group/ChoiceInputMixin.js +306 -296
- package/components/form-core/src/choice-group/CustomChoiceGroupMixin.js +114 -139
- package/components/form-core/src/form-group/FormElementsHaveNoError.js +0 -2
- package/components/form-core/src/form-group/FormGroupMixin.js +551 -557
- package/components/form-core/src/registration/FormRegisteringMixin.js +72 -71
- package/components/form-core/src/registration/FormRegistrarMixin.js +201 -217
- package/components/form-core/src/registration/FormRegistrarPortalMixin.js +31 -37
- package/components/form-core/src/utils/SyncUpdatableMixin.js +106 -117
- package/components/form-core/src/utils/getAriaElementsInRightDomOrder.js +1 -2
- package/components/form-core/src/validate/LionValidationFeedback.js +12 -8
- package/components/form-core/src/validate/Unparseable.js +4 -2
- package/components/form-core/src/validate/ValidateMixin.js +829 -883
- package/components/form-core/src/validate/Validator.js +3 -6
- package/components/form-core/src/validate/resultValidators/DefaultSuccess.js +1 -2
- package/components/form-core/src/validate/validators/DateValidators.js +0 -5
- package/components/form-core/src/validate/validators/NumberValidators.js +1 -5
- package/components/form-core/src/validate/validators/Required.js +1 -1
- package/components/form-core/src/validate/validators/StringValidators.js +1 -8
- package/components/form-core/test/FocusMixin.test.js +96 -82
- package/components/form-core/test/FormControlMixin.test.js +120 -176
- package/components/form-core/test/FormRegistrationMixins.test.js +0 -2
- package/components/form-core/test/FormatMixin.test.js +0 -1
- package/components/form-core/test/InteractionStateMixin.test.js +0 -1
- package/components/form-core/test/NativeTextFieldMixin.test.js +0 -1
- package/components/form-core/test/choice-group/ChoiceGroupMixin.test.js +0 -1
- package/components/form-core/test/choice-group/ChoiceInputMixin.test.js +0 -1
- package/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.js +6 -8
- package/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.js +0 -3
- package/components/form-core/test/form-group/FormGroupMixin.test.js +0 -1
- package/components/form-core/test/lion-field.test.js +88 -98
- package/components/form-core/test/utils/SyncUpdatableMixin.test.js +51 -65
- package/components/form-core/test/utils/getAriaElementsInRightDomOrder.test.js +3 -3
- package/components/form-core/test/validate/DateValidators.test.js +5 -27
- package/components/form-core/test/validate/NumberValidators.test.js +4 -16
- package/components/form-core/test/validate/Required.test.js +8 -21
- package/components/form-core/test/validate/ResultValidator.test.js +1 -2
- package/components/form-core/test/validate/StringValidators.test.js +4 -35
- package/components/form-core/test/validate/ValidateMixin.test.js +0 -1
- package/components/form-core/test/validate/ValidateMixinFeedbackPart.test.js +0 -1
- package/components/form-core/test/validate/Validator.test.js +39 -34
- package/components/form-core/test/validate/lion-validation-feedback.test.js +81 -43
- package/components/form-core/test-helpers/ExampleValidators.js +0 -5
- package/components/form-core/test-helpers/getFormControlMembers.js +2 -2
- package/components/form-core/test-helpers/mimicUserInput.js +5 -1
- package/components/form-core/test-suites/FormRegistrationMixins.suite.js +65 -122
- package/components/form-core/test-suites/FormatMixin.suite.js +202 -227
- package/components/form-core/test-suites/InteractionStateMixin.suite.js +47 -60
- package/components/form-core/test-suites/NativeTextFieldMixin.suite.js +8 -11
- package/components/form-core/test-suites/ValidateMixin.suite.js +280 -359
- package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +112 -163
- package/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js +185 -218
- package/components/form-core/test-suites/choice-group/ChoiceInputMixin.suite.js +116 -109
- package/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.js +36 -70
- package/components/form-core/test-suites/form-group/FormGroupMixin-input.suite.js +57 -65
- package/components/form-core/test-suites/form-group/FormGroupMixin.suite.js +664 -523
- package/components/form-core/translations/bg-BG.js +0 -1
- package/components/form-core/translations/cs-CZ.js +0 -1
- package/components/form-core/translations/de-DE.js +0 -1
- package/components/form-core/translations/en-AU.js +0 -1
- package/components/form-core/translations/en-GB.js +0 -1
- package/components/form-core/translations/en-US.js +0 -1
- package/components/form-core/translations/es-ES.js +0 -1
- package/components/form-core/translations/fr-BE.js +0 -1
- package/components/form-core/translations/fr-FR.js +0 -1
- package/components/form-core/translations/hu-HU.js +0 -1
- package/components/form-core/translations/it-IT.js +0 -1
- package/components/form-core/translations/nl-BE.js +0 -1
- package/components/form-core/translations/nl-NL.js +0 -1
- package/components/form-core/translations/pl-PL.js +0 -1
- package/components/form-core/translations/ro-RO.js +0 -1
- package/components/form-core/translations/ru-RU.js +0 -1
- package/components/form-core/translations/sk-SK.js +0 -1
- package/components/form-core/translations/tr-TR.js +0 -1
- package/components/form-core/translations/uk-UA.js +0 -1
- package/components/form-integrations/test/dialog-integrations.test.js +1 -4
- package/components/form-integrations/test/form-group-methods.test.js +28 -31
- package/components/form-integrations/test/form-integrations.test.js +27 -28
- package/components/form-integrations/test/form-validation-integrations.test.js +21 -29
- package/components/form-integrations/test/helpers/umbrella-form.js +3 -5
- package/components/form-integrations/test/model-value-consistency.test.js +75 -77
- package/components/form-integrations/test/model-value-event.test.js +10 -20
- package/components/helpers/src/SbActionLogger.js +13 -17
- package/components/helpers/src/SbLocaleSwitcher.js +5 -5
- package/components/helpers/src/sortEachDepth.js +0 -2
- package/components/helpers/test/renderLitAsNode.test.js +0 -4
- package/components/helpers/test/sb-action-logger.test.js +24 -55
- package/components/icon/src/IconManager.js +0 -2
- package/components/icon/src/LionIcon.js +2 -7
- package/components/icon/src/icons.js +0 -2
- package/components/icon/test/IconManager.test.js +0 -15
- package/components/icon/test/hammer.svg.js +3 -4
- package/components/icon/test/heart.svg.js +3 -4
- package/components/icon/test/lion-icon.test.js +14 -43
- package/components/input/src/LionInput.js +2 -8
- package/components/input/test/input-integrations.test.js +0 -5
- package/components/input/test/lion-input-integrations.test.js +0 -4
- package/components/input/test/lion-input.test.js +28 -58
- package/components/input/test-helpers/getInputMembers.js +2 -2
- package/components/input-amount/src/LionInputAmount.js +20 -20
- package/components/input-amount/src/formatters.js +0 -3
- package/components/input-amount/src/parsers.js +0 -3
- package/components/input-amount/test/formatters.test.js +24 -16
- package/components/input-amount/test/lion-input-amount-integrations.test.js +0 -4
- package/components/input-amount/test/lion-input-amount.test.js +123 -147
- package/components/input-amount/test/parsers.test.js +33 -17
- package/components/input-amount/test/preprocessors.test.js +0 -3
- package/components/input-amount-dropdown/src/LionInputAmountDropdown.js +49 -59
- package/components/input-amount-dropdown/src/currencyUtil.js +8 -7
- package/components/input-amount-dropdown/src/parsers.js +0 -1
- package/components/input-amount-dropdown/src/validators.js +0 -1
- package/components/input-amount-dropdown/test/LionInputAmountDropdown.test.js +34 -36
- package/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.js +18 -13
- package/components/input-amount-dropdown/test-helpers/mimicUserChangingDropdown.js +5 -1
- package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +132 -107
- package/components/input-date/src/LionInputDate.js +4 -3
- package/components/input-date/test/lion-input-date-integrations.test.js +0 -3
- package/components/input-date/test/lion-input-date.test.js +19 -32
- package/components/input-datepicker/src/LionInputDatepicker.js +17 -29
- package/components/input-datepicker/src/localizeNamespaceLoader.js +1 -2
- package/components/input-datepicker/test/lion-input-datepicker-integrations.test.js +0 -3
- package/components/input-datepicker/test/lion-input-datepicker.test.js +88 -153
- package/components/input-datepicker/test-helpers/DatepickerInputObject.js +9 -12
- package/components/input-datepicker/test-suites/LionInputDatepicker.suite.js +6 -4
- package/components/input-datepicker/translations/bg-BG.js +0 -1
- package/components/input-datepicker/translations/cs-CZ.js +0 -1
- package/components/input-datepicker/translations/de-DE.js +0 -1
- package/components/input-datepicker/translations/en-AU.js +0 -1
- package/components/input-datepicker/translations/en-GB.js +0 -1
- package/components/input-datepicker/translations/en-US.js +0 -1
- package/components/input-datepicker/translations/es-ES.js +0 -1
- package/components/input-datepicker/translations/fr-BE.js +0 -1
- package/components/input-datepicker/translations/fr-FR.js +0 -1
- package/components/input-datepicker/translations/hu-HU.js +0 -1
- package/components/input-datepicker/translations/it-IT.js +0 -1
- package/components/input-datepicker/translations/nl-BE.js +0 -1
- package/components/input-datepicker/translations/nl-NL.js +0 -1
- package/components/input-datepicker/translations/pl-PL.js +0 -1
- package/components/input-datepicker/translations/ro-RO.js +0 -1
- package/components/input-datepicker/translations/ru-RU.js +0 -1
- package/components/input-datepicker/translations/sk-SK.js +0 -1
- package/components/input-datepicker/translations/tr-TR.js +0 -1
- package/components/input-datepicker/translations/uk-UA.js +0 -1
- package/components/input-email/test/lion-input-email-integrations.test.js +0 -2
- package/components/input-email/test/lion-input-email.test.js +1 -7
- package/components/input-file/src/FileHandle.js +0 -3
- package/components/input-file/src/LionInputFile.js +85 -83
- package/components/input-file/src/LionSelectedFileList.js +12 -12
- package/components/input-file/src/validators.js +10 -9
- package/components/input-file/test/FileValidators.test.js +170 -80
- package/components/input-file/test/lion-input-file.test.js +160 -244
- package/components/input-file/test/lion-selected-file-list.test.js +13 -22
- package/components/input-file/translations/bg-BG.js +0 -1
- package/components/input-file/translations/cs-CZ.js +0 -1
- package/components/input-file/translations/de-DE.js +0 -1
- package/components/input-file/translations/en-AU.js +0 -1
- package/components/input-file/translations/en-GB.js +0 -1
- package/components/input-file/translations/en-PH.js +0 -1
- package/components/input-file/translations/en-US.js +0 -1
- package/components/input-file/translations/en.js +2 -1
- package/components/input-file/translations/es-ES.js +0 -1
- package/components/input-file/translations/fr-BE.js +0 -1
- package/components/input-file/translations/fr-FR.js +0 -1
- package/components/input-file/translations/hu-HU.js +0 -1
- package/components/input-file/translations/id-ID.js +0 -1
- package/components/input-file/translations/id.js +2 -1
- package/components/input-file/translations/it-IT.js +0 -1
- package/components/input-file/translations/nl-BE.js +0 -1
- package/components/input-file/translations/nl-NL.js +0 -1
- package/components/input-file/translations/pl-PL.js +0 -1
- package/components/input-file/translations/ro-RO.js +0 -1
- package/components/input-file/translations/ru-RU.js +0 -1
- package/components/input-file/translations/sk-SK.js +0 -1
- package/components/input-file/translations/uk-UA.js +0 -1
- package/components/input-file/translations/zh-CN.js +0 -1
- package/components/input-iban/src/validators.js +6 -11
- package/components/input-iban/test/formatters.test.js +0 -3
- package/components/input-iban/test/lion-input-iban-integrations.test.js +0 -2
- package/components/input-iban/test/lion-input-iban.test.js +1 -9
- package/components/input-iban/test/parsers.test.js +0 -2
- package/components/input-iban/test/validators.test.js +0 -12
- package/components/input-iban/translations/bg-BG.js +0 -1
- package/components/input-iban/translations/cs-CZ.js +0 -1
- package/components/input-iban/translations/de-DE.js +0 -1
- package/components/input-iban/translations/en-AU.js +0 -1
- package/components/input-iban/translations/en-GB.js +0 -1
- package/components/input-iban/translations/en-US.js +0 -1
- package/components/input-iban/translations/es-ES.js +0 -1
- package/components/input-iban/translations/fr-BE.js +0 -1
- package/components/input-iban/translations/fr-FR.js +0 -1
- package/components/input-iban/translations/hu-HU.js +0 -1
- package/components/input-iban/translations/it-IT.js +0 -1
- package/components/input-iban/translations/nl-BE.js +0 -1
- package/components/input-iban/translations/nl-NL.js +0 -1
- package/components/input-iban/translations/pl-PL.js +0 -1
- package/components/input-iban/translations/ro-RO.js +0 -1
- package/components/input-iban/translations/ru-RU.js +0 -1
- package/components/input-iban/translations/sk-SK.js +0 -1
- package/components/input-iban/translations/uk-UA.js +0 -1
- package/components/input-range/src/LionInputRange.js +18 -19
- package/components/input-range/test/lion-input-range.test.js +23 -48
- package/components/input-range/translations/bg-BG.js +0 -1
- package/components/input-range/translations/cs-CZ.js +0 -1
- package/components/input-range/translations/de-DE.js +0 -1
- package/components/input-range/translations/en-AU.js +0 -1
- package/components/input-range/translations/en-GB.js +0 -1
- package/components/input-range/translations/en-PH.js +0 -1
- package/components/input-range/translations/en-US.js +0 -1
- package/components/input-range/translations/es-ES.js +0 -1
- package/components/input-range/translations/fr-BE.js +0 -1
- package/components/input-range/translations/fr-FR.js +0 -1
- package/components/input-range/translations/hu-HU.js +0 -1
- package/components/input-range/translations/it-IT.js +0 -1
- package/components/input-range/translations/nl-BE.js +0 -1
- package/components/input-range/translations/nl-NL.js +0 -1
- package/components/input-range/translations/pl-PL.js +0 -1
- package/components/input-range/translations/ro-RO.js +0 -1
- package/components/input-range/translations/ru-RU.js +0 -1
- package/components/input-range/translations/sk-SK.js +0 -1
- package/components/input-range/translations/uk-UA.js +0 -1
- package/components/input-range/translations/zh-CN.js +0 -1
- package/components/input-stepper/src/LionInputStepper.js +19 -38
- package/components/input-stepper/test/lion-input-stepper-integrations.test.js +0 -1
- package/components/input-stepper/test/lion-input-stepper.test.js +0 -1
- package/components/input-stepper/test-suites/lion-input-stepper.integration.suite.js +0 -2
- package/components/input-stepper/test-suites/lion-input-stepper.suite.js +56 -105
- package/components/input-stepper/translations/bg-BG.js +0 -1
- package/components/input-stepper/translations/cs-CZ.js +0 -1
- package/components/input-stepper/translations/de-DE.js +0 -1
- package/components/input-stepper/translations/en-AU.js +0 -1
- package/components/input-stepper/translations/en-GB.js +0 -1
- package/components/input-stepper/translations/en-US.js +0 -1
- package/components/input-stepper/translations/es-ES.js +0 -1
- package/components/input-stepper/translations/fr-BE.js +0 -1
- package/components/input-stepper/translations/fr-FR.js +0 -1
- package/components/input-stepper/translations/hu-HU.js +0 -1
- package/components/input-stepper/translations/it-IT.js +0 -1
- package/components/input-stepper/translations/nl-BE.js +0 -1
- package/components/input-stepper/translations/nl-NL.js +0 -1
- package/components/input-stepper/translations/pl-PL.js +0 -1
- package/components/input-stepper/translations/ro-RO.js +0 -1
- package/components/input-stepper/translations/ru-RU.js +0 -1
- package/components/input-stepper/translations/sk-SK.js +0 -1
- package/components/input-stepper/translations/uk-UA.js +0 -1
- package/components/input-tel/src/LionInputTel.js +53 -37
- package/components/input-tel/src/PhoneUtilManager.js +6 -4
- package/components/input-tel/src/formatters.js +12 -10
- package/components/input-tel/src/parsers.js +3 -3
- package/components/input-tel/src/preprocessors.js +15 -7
- package/components/input-tel/src/validators.js +4 -6
- package/components/input-tel/test/LionInputTel.test.js +4 -2
- package/components/input-tel/test/formatters.test.js +22 -10
- package/components/input-tel/test/parsers.test.js +40 -11
- package/components/input-tel/test/preprocessors.test.js +24 -13
- package/components/input-tel/test/validators.test.js +7 -14
- package/components/input-tel/test-helpers/mockPhoneUtilManager.js +7 -6
- package/components/input-tel/test-suites/LionInputTel.suite.js +33 -73
- package/components/input-tel/translations/bg-BG.js +0 -1
- package/components/input-tel/translations/cs-CZ.js +0 -1
- package/components/input-tel/translations/de-DE.js +0 -1
- package/components/input-tel/translations/en-AU.js +0 -1
- package/components/input-tel/translations/en-GB.js +0 -1
- package/components/input-tel/translations/en-US.js +0 -1
- package/components/input-tel/translations/es-ES.js +0 -1
- package/components/input-tel/translations/fr-BE.js +0 -1
- package/components/input-tel/translations/fr-FR.js +0 -1
- package/components/input-tel/translations/hu-HU.js +0 -1
- package/components/input-tel/translations/it-IT.js +0 -1
- package/components/input-tel/translations/nl-BE.js +0 -1
- package/components/input-tel/translations/nl-NL.js +0 -1
- package/components/input-tel/translations/pl-PL.js +0 -1
- package/components/input-tel/translations/ro-RO.js +0 -1
- package/components/input-tel/translations/ru-RU.js +0 -1
- package/components/input-tel/translations/sk-SK.js +0 -1
- package/components/input-tel/translations/uk-UA.js +0 -1
- package/components/input-tel-dropdown/src/LionInputTelDropdown.js +10 -28
- package/components/input-tel-dropdown/src/regionCodeToLocale.js +3 -1
- package/components/input-tel-dropdown/test/LionInputTelDropdown.test.js +31 -38
- package/components/input-tel-dropdown/test/regionCodeToLocale.test.js +0 -1
- package/components/input-tel-dropdown/test-helpers/mimicUserChangingDropdown.js +5 -1
- package/components/input-tel-dropdown/test-suites/LionInputTelDropdown--parentheses.suite.js +16 -11
- package/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js +54 -79
- package/components/listbox/src/LionListbox.js +4 -1
- package/components/listbox/src/LionOption.js +8 -7
- package/components/listbox/src/LionOptions.js +0 -3
- package/components/listbox/src/ListboxMixin.js +786 -820
- package/components/listbox/test/lion-listbox.test.js +0 -1
- package/components/listbox/test/lion-option.test.js +53 -64
- package/components/listbox/test/lion-options.test.js +3 -4
- package/components/listbox/test-helpers/getListboxMembers.js +6 -3
- package/components/listbox/test-suites/ListboxMixin.suite.js +101 -261
- package/components/localize/src/LocalizeManager.js +40 -40
- package/components/localize/src/LocalizeMixin.js +130 -157
- package/components/localize/src/date/formatDate.js +1 -5
- package/components/localize/src/date/getDateFormatBasedOnLocale.js +5 -3
- package/components/localize/src/date/getMonthNames.js +3 -5
- package/components/localize/src/date/getWeekdayNames.js +1 -5
- package/components/localize/src/date/parseDate.js +5 -20
- package/components/localize/src/date/utils/normalizeIntlDate.js +0 -7
- package/components/localize/src/getLocalizeManager.js +0 -3
- package/components/localize/src/number/formatNumber.js +3 -7
- package/components/localize/src/number/formatNumberToParts.js +52 -18
- package/components/localize/src/number/getCurrencyName.js +5 -5
- package/components/localize/src/number/getFractionDigits.js +4 -4
- package/components/localize/src/number/getSeparatorsFromNumber.js +1 -3
- package/components/localize/src/number/parseNumber.js +0 -3
- package/components/localize/src/number/utils/normalize-format-number-to-parts/forceAddGroupSeparators.js +0 -1
- package/components/localize/src/number/utils/normalize-format-number-to-parts/forceSpaceBetweenCurrencyCodeAndNumber.js +4 -1
- package/components/localize/test/LocalizeManager.test.js +385 -278
- package/components/localize/test/LocalizeMixin.test.js +28 -112
- package/components/localize/test/date/formatDate.test.js +18 -48
- package/components/localize/test/date/getDateFormatBasedOnLocale.test.js +0 -3
- package/components/localize/test/date/getMonthNames.test.js +27 -12
- package/components/localize/test/date/getWeekdayNames.test.js +93 -49
- package/components/localize/test/date/normalizeDateTime.test.js +0 -2
- package/components/localize/test/date/parseDate.test.js +12 -16
- package/components/localize/test/getLocalizeManager.test.js +0 -3
- package/components/localize/test/isLocalizeESModule.test.js +32 -13
- package/components/localize/test/localize.test.js +0 -4
- package/components/localize/test/number/formatNumber.test.js +215 -106
- package/components/localize/test/number/formatNumberToParts.test.js +31 -38
- package/components/localize/test/number/getCurrencyName.test.js +20 -6
- package/components/localize/test/number/getDecimalSeparator.test.js +5 -4
- package/components/localize/test/number/getFractionDigits.test.js +0 -2
- package/components/localize/test/number/getGroupSeparator.test.js +0 -2
- package/components/localize/test/number/getSeparatorsFromNumber.test.js +5 -3
- package/components/localize/test/number/parseNumber.test.js +123 -56
- package/components/localize/test/side-effect-free-entrypoint.test.js +0 -6
- package/components/localize/test-helpers/fake-imports.js +11 -6
- package/components/localize/test-helpers/localizeTearDown.js +0 -1
- package/components/menu/src/InteractiveListMixin.js +637 -638
- package/components/menu/src/LionMenu.js +46 -59
- package/components/menu/src/MoreButtonMenuMixin.js +215 -238
- package/components/menu/src/MultiLevelListMixin.js +240 -246
- package/components/menu/src/utils/isInView.js +0 -1
- package/components/menu/src/utils/listItemInteractions.js +4 -4
- package/components/menu/test/InteractiveListMixin.test.js +0 -1
- package/components/menu/test/MoreButtonMenuMixin.test.js +3 -2
- package/components/menu/test/MultiLevelListMixin.test.js +0 -1
- package/components/menu/test/lion-menu-interactions.test.js +0 -1
- package/components/menu/test/lion-menu.test.js +6 -2
- package/components/menu/test-helpers/mimicKeyPress.js +12 -2
- package/components/menu/test-suites/InteractiveListMixin.suite.js +4 -43
- package/components/menu/test-suites/LionMenu.suite.js +1 -8
- package/components/menu/test-suites/LionMenuInteractions.suite.js +22 -44
- package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +34 -41
- package/components/menu/test-suites/MultiLevelListMixin.suite.js +5 -23
- package/components/overlays/src/ArrowMixin.js +111 -127
- package/components/overlays/src/OverlayController.js +166 -151
- package/components/overlays/src/OverlayMixin.js +61 -63
- package/components/overlays/src/OverlaysManager.js +30 -32
- package/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.js +0 -1
- package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +11 -11
- package/components/overlays/src/configurations/withBottomSheetConfig.js +12 -13
- package/components/overlays/src/configurations/withDropdownConfig.js +4 -2
- package/components/overlays/src/configurations/withModalDialogConfig.js +12 -13
- package/components/overlays/src/configurations/withPopoverConfig.js +27 -25
- package/components/overlays/src/configurations/withTooltipConfig.js +15 -13
- package/components/overlays/src/overlayDocumentStyle.js +1 -1
- package/components/overlays/src/overlayShadowDomStyle.js +0 -1
- package/components/overlays/src/singleton.js +0 -2
- package/components/overlays/src/utils/adopt-styles.js +18 -18
- package/components/overlays/src/utils/deep-contains.js +7 -6
- package/components/overlays/src/utils/get-focusable-elements.js +7 -10
- package/components/overlays/src/utils/inert-siblings.js +2 -4
- package/components/overlays/src/utils/is-equal-config.js +2 -3
- package/components/overlays/src/utils/is-visible.js +0 -1
- package/components/overlays/src/utils/simulate-tab.js +1 -4
- package/components/overlays/src/utils/sort-by-tabindex.js +2 -4
- package/components/overlays/test/ArrowMixin.test.js +18 -30
- package/components/overlays/test/OverlayController.test.js +375 -555
- package/components/overlays/test/OverlayMixin.test.js +0 -2
- package/components/overlays/test/OverlaysManager.test.js +30 -35
- package/components/overlays/test/global-positioning.test.js +6 -10
- package/components/overlays/test/local-positioning.test.js +101 -103
- package/components/overlays/test/utils-tests/active-element.test.js +12 -27
- package/components/overlays/test/utils-tests/adopt-styles.test.js +25 -56
- package/components/overlays/test/utils-tests/deep-contains.test.js +73 -74
- package/components/overlays/test/utils-tests/get-focusable-elements.test.js +6 -23
- package/components/overlays/test/utils-tests/is-equal-config.test.js +32 -13
- package/components/overlays/test/utils-tests/visibility.test.js +44 -79
- package/components/overlays/test-helpers/createShadowHost.js +5 -3
- package/components/overlays/test-helpers/normalizeTransformStyle.js +2 -4
- package/components/overlays/test-suites/OverlayMixin.suite.js +152 -181
- package/components/overlays/test-suites/WithHoverInteraction.suite.js +96 -79
- package/components/overlays/translations/bg-BG.js +0 -1
- package/components/overlays/translations/cs-CZ.js +0 -1
- package/components/overlays/translations/de-DE.js +0 -1
- package/components/overlays/translations/en-AU.js +0 -1
- package/components/overlays/translations/en-GB.js +0 -1
- package/components/overlays/translations/en-US.js +0 -1
- package/components/overlays/translations/es-ES.js +0 -1
- package/components/overlays/translations/fr-BE.js +0 -1
- package/components/overlays/translations/fr-FR.js +0 -1
- package/components/overlays/translations/hu-HU.js +0 -1
- package/components/overlays/translations/it-IT.js +0 -1
- package/components/overlays/translations/nl-BE.js +0 -1
- package/components/overlays/translations/nl-NL.js +0 -1
- package/components/overlays/translations/pl-PL.js +0 -1
- package/components/overlays/translations/ro-RO.js +0 -1
- package/components/overlays/translations/ru-RU.js +0 -1
- package/components/overlays/translations/sk-SK.js +0 -1
- package/components/overlays/translations/tr-TR.js +0 -1
- package/components/overlays/translations/uk-UA.js +0 -1
- package/components/pagination/src/LionPagination.js +9 -12
- package/components/pagination/test/lion-pagination.test.js +18 -50
- package/components/progress-indicator/src/LionProgressIndicator.js +10 -12
- package/components/progress-indicator/test/lion-progress-indicator.test.js +1 -22
- package/components/radio-group/src/LionRadioGroup.js +1 -2
- package/components/radio-group/test/lion-radio-group-integrations.test.js +0 -1
- package/components/radio-group/test/lion-radio-group.test.js +27 -27
- package/components/radio-group/test/lion-radio-integrations.test.js +3 -2
- package/components/radio-group/test/lion-radio.test.js +30 -16
- package/components/select/src/LionSelect.js +12 -13
- package/components/select/test/lion-select.test.js +7 -12
- package/components/select-rich/src/LionSelectInvoker.js +18 -11
- package/components/select-rich/src/LionSelectRich.js +20 -43
- package/components/select-rich/test/demos.screenshots-test.js +40 -9
- package/components/select-rich/test/lion-select-invoker.test.js +26 -43
- package/components/select-rich/test/lion-select-listbox-suite-integration.test.js +3 -3
- package/components/select-rich/test/lion-select-rich-dialog-integration.test.js +4 -9
- package/components/select-rich/test/lion-select-rich-interaction.test.js +116 -116
- package/components/select-rich/test/lion-select-rich-upgrade.test.js +3 -7
- package/components/select-rich/test/lion-select-rich.test.js +153 -195
- package/components/select-rich/test-helpers/getSelectRichMembers.js +4 -1
- package/components/steps/src/LionStep.js +21 -12
- package/components/steps/src/LionSteps.js +25 -25
- package/components/steps/test/lion-step.test.js +18 -25
- package/components/steps/test/lion-steps.test.js +45 -78
- package/components/switch/src/LionSwitch.js +2 -7
- package/components/switch/src/LionSwitchButton.js +5 -6
- package/components/switch/test/lion-switch-button.test.js +16 -28
- package/components/switch/test/lion-switch.test.js +17 -31
- package/components/tabs/src/LionTabs.js +25 -28
- package/components/tabs/test/lion-tabs.test.js +156 -154
- package/components/textarea/src/LionTextarea.js +4 -23
- package/components/textarea/test/lion-textarea-integrations.test.js +0 -5
- package/components/textarea/test/lion-textarea.test.js +2 -28
- package/components/tooltip/src/LionTooltip.js +6 -6
- package/components/tooltip/test/lion-tooltip.test.js +75 -102
- package/components/validate-messages/src/getLocalizedMessage.js +8 -7
- package/components/validate-messages/src/loadDefaultFeedbackMessages.js +3 -1
- package/components/validate-messages/src/loadDefaultFeedbackMessagesNoSideEffects.js +9 -5
- package/components/validate-messages/src/per-entrypoint/loadComboboxMessagesNoSideEffects.js +5 -2
- package/components/validate-messages/src/per-entrypoint/loadFormCoreMessagesNoSideEffects.js +99 -35
- package/components/validate-messages/src/per-entrypoint/loadInputTelMessagesNoSideEffects.js +4 -3
- package/components/validate-messages/test/loadDefaultFeedbackMessages.test.js +5 -3
- package/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.test.js +80 -45
- package/components/validate-messages/translations/bg-BG.js +0 -1
- package/components/validate-messages/translations/cs-CZ.js +0 -1
- package/components/validate-messages/translations/de-DE.js +0 -1
- package/components/validate-messages/translations/en-AU.js +0 -1
- package/components/validate-messages/translations/en-GB.js +0 -1
- package/components/validate-messages/translations/en-PH.js +0 -1
- package/components/validate-messages/translations/en-US.js +0 -1
- package/components/validate-messages/translations/es-ES.js +0 -1
- package/components/validate-messages/translations/fr-BE.js +0 -1
- package/components/validate-messages/translations/fr-FR.js +0 -1
- package/components/validate-messages/translations/hu-HU.js +0 -1
- package/components/validate-messages/translations/it-IT.js +0 -1
- package/components/validate-messages/translations/nl-BE.js +0 -1
- package/components/validate-messages/translations/nl-NL.js +0 -1
- package/components/validate-messages/translations/pl-PL.js +0 -1
- package/components/validate-messages/translations/ro-RO.js +0 -1
- package/components/validate-messages/translations/ru-RU.js +0 -1
- package/components/validate-messages/translations/sk-SK.js +0 -1
- package/components/validate-messages/translations/tr-TR.js +0 -1
- package/components/validate-messages/translations/uk-UA.js +0 -1
- package/custom-elements.json +191 -56
- package/dist-types/components/core/src/SlotMixin.d.ts +6 -1
- package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
- package/dist-types/components/core/types/SlotMixinTypes.d.ts +5 -1
- package/dist-types/components/core/types/SlotMixinTypes.d.ts.map +1 -1
- package/dist-types/components/form-core/src/LionField.d.ts +3 -1
- package/dist-types/components/form-core/src/LionField.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/LionInputTel.d.ts +6 -6
- package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts +2 -2
- package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/formatters.d.ts +2 -2
- package/dist-types/components/input-tel/src/formatters.d.ts.map +1 -1
- package/dist-types/components/input-tel/src/preprocessors.d.ts +2 -2
- package/dist-types/components/input-tel/src/preprocessors.d.ts.map +1 -1
- package/dist-types/components/input-tel/test/validators.test.d.ts +1 -1
- package/dist-types/components/input-tel/test/validators.test.d.ts.map +1 -1
- package/dist-types/components/listbox/src/LionOption.d.ts +5 -2
- package/dist-types/components/listbox/src/LionOption.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
- package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts +3 -1
- package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/accordion/overview.md +2 -2
- package/docs/components/accordion/reference.md +2 -2
- package/docs/components/accordion/use-cases.md +2 -2
- package/docs/components/button/examples.md +2 -2
- package/docs/components/button/extensions.md +2 -2
- package/docs/components/button/overview.md +2 -2
- package/docs/components/button/use-cases.md +2 -2
- package/docs/components/calendar/overview.md +2 -2
- package/docs/components/calendar/use-cases.md +2 -2
- package/docs/components/checkbox-group/overview.md +4 -4
- package/docs/components/checkbox-group/use-cases.md +2 -2
- package/docs/components/collapsible/examples.md +2 -2
- package/docs/components/collapsible/overview.md +3 -3
- package/docs/components/collapsible/use-cases.md +2 -2
- package/docs/components/combobox/extensions.md +2 -2
- package/docs/components/combobox/overview.md +3 -3
- package/docs/components/combobox/use-cases.md +3 -3
- package/docs/components/dialog/overview.md +3 -3
- package/docs/components/dialog/use-cases.md +2 -2
- package/docs/components/drawer/overview.md +2 -2
- package/docs/components/drawer/use-cases.md +2 -2
- package/docs/components/fieldset/overview.md +7 -7
- package/docs/components/fieldset/use-cases.md +2 -2
- package/docs/components/form/overview.md +5 -5
- package/docs/components/form/use-cases.md +4 -4
- package/docs/components/icon/overview.md +2 -2
- package/docs/components/icon/use-cases.md +3 -3
- package/docs/components/input/overview.md +3 -3
- package/docs/components/input/use-cases.md +2 -2
- package/docs/components/input-amount/overview.md +5 -5
- package/docs/components/input-amount/use-cases.md +2 -2
- package/docs/components/input-amount-dropdown/use-cases.md +2 -2
- package/docs/components/input-date/overview.md +5 -5
- package/docs/components/input-date/use-cases.md +2 -2
- package/docs/components/input-datepicker/overview.md +7 -7
- package/docs/components/input-datepicker/use-cases.md +2 -2
- package/docs/components/input-email/overview.md +4 -4
- package/docs/components/input-email/use-cases.md +2 -2
- package/docs/components/input-file/overview.md +3 -3
- package/docs/components/input-file/use-cases.md +2 -2
- package/docs/components/input-iban/overview.md +4 -4
- package/docs/components/input-iban/use-cases.md +2 -2
- package/docs/components/input-range/overview.md +4 -4
- package/docs/components/input-range/use-cases.md +2 -2
- package/docs/components/input-stepper/overview.md +3 -3
- package/docs/components/input-stepper/use-cases.md +2 -2
- package/docs/components/input-tel/overview.md +3 -3
- package/docs/components/input-tel/use-cases.md +8 -8
- package/docs/components/input-tel-dropdown/extensions.md +2 -2
- package/docs/components/input-tel-dropdown/overview.md +3 -3
- package/docs/components/input-tel-dropdown/use-cases.md +2 -2
- package/docs/components/listbox/overview.md +2 -2
- package/docs/components/listbox/use-cases.md +3 -3
- package/docs/components/menu/extensions.md +2 -2
- package/docs/components/menu/migration.md +2 -2
- package/docs/components/menu/overview.md +2 -2
- package/docs/components/menu/use-cases.md +1 -1
- package/docs/components/pagination/overview.md +2 -2
- package/docs/components/pagination/use-cases.md +2 -2
- package/docs/components/progress-indicator/examples.md +2 -2
- package/docs/components/progress-indicator/overview.md +2 -2
- package/docs/components/radio-group/overview.md +5 -5
- package/docs/components/radio-group/use-cases.md +2 -2
- package/docs/components/select/overview.md +2 -2
- package/docs/components/select/use-cases.md +3 -3
- package/docs/components/select-rich/examples.md +2 -2
- package/docs/components/select-rich/overview.md +2 -2
- package/docs/components/select-rich/use-cases.md +4 -4
- package/docs/components/steps/overview.md +2 -2
- package/docs/components/steps/use-cases.md +2 -2
- package/docs/components/switch/overview.md +2 -2
- package/docs/components/switch/reference.md +2 -2
- package/docs/components/switch/use-cases.md +2 -2
- package/docs/components/tabs/examples.md +3 -3
- package/docs/components/tabs/overview.md +2 -2
- package/docs/components/tabs/use-cases.md +2 -2
- package/docs/components/textarea/overview.md +2 -2
- package/docs/components/textarea/use-cases.md +2 -2
- package/docs/components/tooltip/examples.md +2 -2
- package/docs/components/tooltip/overview.md +2 -2
- package/docs/components/tooltip/use-cases.md +2 -2
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +2 -2
- package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +2 -2
- package/docs/fundamentals/node-tools/providence-analytics/index.md +2 -2
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +2 -2
- package/docs/fundamentals/node-tools/publish-docs/index.md +2 -2
- package/docs/fundamentals/node-tools/publish-docs/overview.md +5 -5
- package/docs/fundamentals/node-tools/remark-extend/index.md +2 -2
- package/docs/fundamentals/node-tools/remark-extend/overview.md +2 -2
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +2 -2
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +4 -4
- package/docs/fundamentals/rationales/TypeScript.md +62 -2
- package/docs/fundamentals/rationales/accessibility.md +5 -5
- package/docs/fundamentals/rationales/side-effects.md +2 -2
- package/docs/fundamentals/rationales/versioning.md +2 -2
- package/docs/fundamentals/systems/core/SlotMixin.md +3 -3
- package/docs/fundamentals/systems/core/index.md +2 -2
- package/docs/fundamentals/systems/core/overview.md +3 -3
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +6 -6
- package/docs/fundamentals/systems/form/index.md +2 -2
- package/docs/fundamentals/systems/form/interaction-states.md +2 -2
- package/docs/fundamentals/systems/form/model-value.md +3 -3
- package/docs/fundamentals/systems/form/overview.md +30 -30
- package/docs/fundamentals/systems/form/styling.md +2 -2
- package/docs/fundamentals/systems/form/use-cases.md +2 -2
- package/docs/fundamentals/systems/form/validate.md +4 -4
- package/docs/fundamentals/systems/icon/index.md +2 -2
- package/docs/fundamentals/systems/icon/overview.md +2 -2
- package/docs/fundamentals/systems/localize/dates.md +2 -2
- package/docs/fundamentals/systems/localize/index.md +2 -2
- package/docs/fundamentals/systems/localize/numbers.md +2 -2
- package/docs/fundamentals/systems/localize/overview.md +6 -6
- package/docs/fundamentals/systems/localize/rationale.md +2 -2
- package/docs/fundamentals/systems/localize/text.md +2 -2
- package/docs/fundamentals/systems/localize/use-cases.md +2 -2
- package/docs/fundamentals/systems/overlays/_edge-cases.md +2 -2
- package/docs/fundamentals/systems/overlays/configuration.md +4 -4
- package/docs/fundamentals/systems/overlays/index.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +7 -7
- package/docs/fundamentals/systems/overlays/rationale.md +2 -2
- package/docs/fundamentals/systems/overlays/use-cases.md +4 -4
- package/docs/fundamentals/tools/ajax/index.md +2 -2
- package/docs/fundamentals/tools/ajax/overview.md +2 -2
- package/docs/fundamentals/tools/ajax/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/action-logger.md +2 -2
- package/docs/fundamentals/tools/helpers/index.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +3 -3
- package/docs/fundamentals/tools/singleton-manager/example-complex/index.md +2 -2
- package/docs/fundamentals/tools/singleton-manager/example-fail/index.md +2 -2
- package/docs/fundamentals/tools/singleton-manager/example-success/index.md +2 -2
- package/docs/fundamentals/tools/singleton-manager/index.md +2 -2
- package/docs/fundamentals/tools/singleton-manager/overview.md +6 -6
- package/docs/guides/how-to/create-a-custom-field.md +7 -7
- package/docs/guides/how-to/create-a-form.md +6 -6
- package/docs/guides/how-to/extend-a-native-input.md +4 -4
- package/docs/guides/how-to/get-started.md +2 -2
- package/docs/guides/how-to/index.md +1 -1
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/definitions-and-terms.md +2 -2
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/scoped-elements.md +2 -2
- package/docs/guides/principles/styling.md +3 -3
- package/docs/guides/principles/subclasser-apis.md +2 -2
- package/exports/define/lion-accordion.js +0 -1
- package/exports/define/lion-button-reset.js +0 -1
- package/exports/define/lion-button-submit.js +0 -1
- package/exports/define/lion-button.js +0 -1
- package/exports/define/lion-calendar.js +0 -1
- package/exports/define/lion-checkbox-group.js +0 -1
- package/exports/define/lion-checkbox-indeterminate.js +0 -1
- package/exports/define/lion-checkbox.js +0 -1
- package/exports/define/lion-collapsible.js +0 -1
- package/exports/define/lion-combobox.js +0 -1
- package/exports/define/lion-dialog.js +0 -1
- package/exports/define/lion-drawer.js +0 -1
- package/exports/define/lion-field.js +0 -1
- package/exports/define/lion-fieldset.js +0 -1
- package/exports/define/lion-form.js +0 -1
- package/exports/define/lion-icon.js +0 -1
- package/exports/define/lion-input-amount-dropdown.js +0 -1
- package/exports/define/lion-input-amount.js +0 -1
- package/exports/define/lion-input-date.js +0 -1
- package/exports/define/lion-input-datepicker.js +0 -1
- package/exports/define/lion-input-email.js +0 -1
- package/exports/define/lion-input-file.js +0 -1
- package/exports/define/lion-input-iban.js +0 -1
- package/exports/define/lion-input-range.js +0 -1
- package/exports/define/lion-input-stepper.js +0 -1
- package/exports/define/lion-input-tel-dropdown.js +0 -1
- package/exports/define/lion-input-tel.js +0 -1
- package/exports/define/lion-input.js +0 -1
- package/exports/define/lion-item.js +0 -1
- package/exports/define/lion-listbox.js +0 -1
- package/exports/define/lion-menu.js +0 -1
- package/exports/define/lion-menuitem.js +0 -1
- package/exports/define/lion-option.js +0 -1
- package/exports/define/lion-options.js +0 -1
- package/exports/define/lion-pagination.js +0 -1
- package/exports/define/lion-progress-indicator.js +0 -1
- package/exports/define/lion-radio-group.js +0 -1
- package/exports/define/lion-radio.js +0 -1
- package/exports/define/lion-select-invoker.js +0 -1
- package/exports/define/lion-select-rich.js +0 -1
- package/exports/define/lion-select.js +0 -1
- package/exports/define/lion-selected-file-list.js +0 -1
- package/exports/define/lion-step.js +0 -1
- package/exports/define/lion-steps.js +0 -1
- package/exports/define/lion-switch-button.js +0 -1
- package/exports/define/lion-switch.js +0 -1
- package/exports/define/lion-tabs.js +0 -1
- package/exports/define/lion-textarea.js +0 -1
- package/exports/define/lion-tooltip.js +0 -1
- package/exports/define/lion-validation-feedback.js +0 -1
- package/exports/define-helpers/sb-action-logger.js +0 -1
- package/exports/define-helpers/sb-locale-switcher.js +0 -1
- package/exports/form-core.js +0 -8
- package/exports/localize-no-side-effects.js +0 -1
- package/exports/localize.js +0 -2
- package/exports/overlays.js +0 -4
- package/generated/awesome-phonenumber/LICENSE +22 -0
- package/generated/awesome-phonenumber/LICENSE.closure-library +176 -0
- package/generated/awesome-phonenumber/LICENSE.libphonenumber +176 -0
- package/generated/awesome-phonenumber/checksums.json +6 -0
- package/generated/awesome-phonenumber/index-esm.mjs +817 -0
- package/generated/awesome-phonenumber/index.d.ts +227 -0
- package/generated/awesome-phonenumber/index.js +45 -0
- package/generated/awesome-phonenumber/lib/index.js +710 -0
- package/generated/awesome-phonenumber/package.json +9 -0
- package/generated/awesome-phonenumber/provenance.json +13 -0
- package/package.json +32 -10
- package/web-types.json +1 -1
- package/vendor/README.md +0 -61
- 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
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
*
|
|
97
|
-
* @
|
|
98
|
-
* @
|
|
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
|
-
|
|
101
|
-
|
|
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
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
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
|
-
|
|
110
|
-
return 'enter';
|
|
111
|
-
}
|
|
178
|
+
this.hasFeedbackFor = [];
|
|
112
179
|
|
|
113
180
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
139
|
-
* @type {
|
|
140
|
-
* @
|
|
198
|
+
* A temporary storage to transition from hasFeedbackFor to showsFeedbackFor
|
|
199
|
+
* @type {ValidationType[]}
|
|
200
|
+
* @readOnly
|
|
201
|
+
* @private
|
|
141
202
|
*/
|
|
142
|
-
|
|
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
|
-
*
|
|
206
|
+
* The outcome of a validation 'round'. Keyed by ValidationType and Validator name
|
|
207
|
+
* @readOnly
|
|
208
|
+
* @type {ValidationStates}
|
|
298
209
|
*/
|
|
299
|
-
|
|
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
|
-
*
|
|
312
|
-
*
|
|
213
|
+
* Flag indicating whether async validation is pending.
|
|
214
|
+
* Creates attribute [is-pending] as a styling hook
|
|
215
|
+
* @type {boolean}
|
|
313
216
|
*/
|
|
314
|
-
|
|
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
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
427
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
242
|
+
* The amount of feedback messages that will visible in LionValidationFeedback
|
|
243
|
+
* @configurable
|
|
244
|
+
* @protected
|
|
443
245
|
*/
|
|
444
|
-
|
|
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
|
-
*
|
|
551
|
-
* @param {Validator[]} syncValidators
|
|
552
|
-
* @param {unknown} value
|
|
249
|
+
* @type {ValidationResultEntry[]}
|
|
553
250
|
* @private
|
|
554
251
|
*/
|
|
555
|
-
|
|
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
|
-
*
|
|
568
|
-
* @param {Validator[]} asyncValidators all Validators except required and MetaValidators
|
|
569
|
-
* @param {any} value
|
|
255
|
+
* @type {ValidationResultEntry[]}
|
|
570
256
|
* @private
|
|
571
257
|
*/
|
|
572
|
-
|
|
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
|
-
*
|
|
586
|
-
* @
|
|
587
|
-
* @param {MetaValidator[]} metaValidators
|
|
261
|
+
* Aggregated result from sync Validators, async Validators and MetaValidators
|
|
262
|
+
* @type {ValidationResultEntry[]}
|
|
588
263
|
* @private
|
|
589
264
|
*/
|
|
590
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
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
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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
|
-
|
|
350
|
+
diff.forEach(type => {
|
|
351
|
+
this.dispatchEvent(new Event(`showsFeedbackFor${pascalCase(type)}Changed`, {
|
|
352
|
+
bubbles: true
|
|
353
|
+
}));
|
|
354
|
+
});
|
|
742
355
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
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
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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
|
-
*
|
|
777
|
-
* @
|
|
778
|
-
*
|
|
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
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
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
|
-
*
|
|
806
|
-
* (delegation of) rendering them.
|
|
448
|
+
* Handle the 'mutually exclusive' Required validator:
|
|
807
449
|
*
|
|
808
|
-
*
|
|
809
|
-
* -
|
|
810
|
-
*
|
|
811
|
-
*
|
|
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
|
-
|
|
832
|
-
|
|
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
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
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
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
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
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
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
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
this.
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
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
|
-
|
|
956
|
-
|
|
957
|
-
|
|
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
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
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
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
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
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
);
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
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
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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);
|