@cnamts/synapse 1.0.23 → 1.0.24
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/dist/AutocompleteFilter-BWLR3U7W.js +114 -0
- package/dist/AutocompleteFilter-D9jzRzAL.cjs +1 -0
- package/dist/{DateFilter-Dc-gSGwk.js → DateFilter-BpwFexzi.js} +1 -1
- package/dist/DateFilter-DTUl8hb1.cjs +1 -0
- package/dist/{NumberFilter-vP38Wp6j.js → NumberFilter-Bz_NTdX9.js} +3 -3
- package/dist/NumberFilter-MAEojdk0.cjs +1 -0
- package/dist/PeriodFilter-CC4WgIhl.cjs +1 -0
- package/dist/{PeriodFilter-Ba1uYUnT.js → PeriodFilter-DX_wy9g-.js} +1 -1
- package/dist/SelectFilter-BR3fvl-a.cjs +1 -0
- package/dist/SelectFilter-xqiPtPgX.js +135 -0
- package/dist/{TextFilter-B84dpnoq.js → TextFilter-BBl3JFqK.js} +7 -7
- package/dist/TextFilter-CCfYFl5F.cjs +1 -0
- package/dist/apLightTheme-CFSRrjv2.cjs +1 -0
- package/dist/apLightTheme-D1P4jcD0.js +1231 -0
- package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +7022 -9616
- package/dist/components/Amelipro/AmeliproCarousel/AmeliproCarousel.d.ts +2 -2
- package/dist/components/Amelipro/AmeliproIconBtn/AmeliproIconBtn.d.ts +2 -2
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/AmeliproPostalAddressCityRow.d.ts +40 -40
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +60 -60
- package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +7168 -9762
- package/dist/components/Amelipro/AmeliproStepper/AmeliproStepper.d.ts +2 -2
- package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +7501 -10095
- package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +21 -21
- package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +41 -41
- package/dist/components/Amelipro/StructureMenu/StructureTabs/StructureTabs.d.ts +2 -2
- package/dist/components/CookiesSelection/CookiesInformation/CookiesInformation.d.ts +20 -498
- package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +108 -146
- package/dist/components/Customs/Selects/SyInputSelect/SyInputSelect.d.ts +5 -5
- package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +12 -16
- package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +8 -8
- package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +28 -506
- package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +28 -506
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +65 -85
- package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +627 -771
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +315 -402
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +112 -155
- package/dist/components/DatePicker/composables/index.d.ts +1 -0
- package/dist/components/DatePicker/composables/useDatePickerFocusTrap.d.ts +11 -0
- package/dist/components/DatePicker/composables/useDateTextField.d.ts +4 -4
- package/dist/components/DatePicker/composables/useDateValidation.d.ts +3 -3
- package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +2 -2
- package/dist/components/DatePicker/composables/useManualDateValidation.d.ts +2 -2
- package/dist/components/HeaderNavigationBar/HeaderNavigationBar.d.ts +4 -4
- package/dist/components/HeaderToolbar/HeaderToolbar.d.ts +20 -28
- package/dist/components/LunarCalendar/useLunarCalendarValidation.d.ts +3 -3
- package/dist/components/MonthPicker/MonthPicker.d.ts +86 -122
- package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +85 -121
- package/dist/components/NirField/NirField.d.ts +206 -270
- package/dist/components/NirField/locales.d.ts +10 -10
- package/dist/components/NirField/useNirValidation.d.ts +64 -0
- package/dist/components/PasswordField/PasswordField.d.ts +8 -9
- package/dist/components/PeriodField/PeriodField.d.ts +1352 -1640
- package/dist/components/PhoneField/PhoneField.d.ts +88 -124
- package/dist/components/RangeField/RangeSlider/RangeSlider.d.ts +12 -12
- package/dist/components/SyTextArea/SyTextArea.d.ts +34 -14
- package/dist/components/SyTextArea/useDefaultValidationRules.d.ts +11 -0
- package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +9 -6
- package/dist/components/Tables/SyTable/SyTable.d.ts +9 -6
- package/dist/components/Tables/common/SyTableFilter.d.ts +2 -3
- package/dist/components/Tables/common/SyTablePagination.d.ts +17 -19
- package/dist/components/Tables/common/filters/AutocompleteFilter.d.ts +120 -0
- package/dist/components/Tables/common/filters/locales.d.ts +0 -1
- package/dist/components/Tables/common/types.d.ts +19 -3
- package/dist/components/Tables/common/useClickableTableRow.d.ts +17 -0
- package/dist/components/Tables/common/usePagination.d.ts +3 -1
- package/dist/components/Tables/common/usePinnedColumns.d.ts +31 -0
- package/dist/components/Tables/common/useTableHeaders.d.ts +2 -0
- package/dist/components/Tables/common/useTableRowCheckboxAccessibility.d.ts +5 -0
- package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +6 -6
- package/dist/composables/date/useDatePickerAccessibility.d.ts +1 -1
- package/dist/composables/rules/useFieldValidation.d.ts +4 -4
- package/dist/composables/unifyValidation/useCustomValidation.d.ts +8 -0
- package/dist/composables/unifyValidation/useValidation.d.ts +102 -0
- package/dist/composables/unifyValidation/useVuetifyValidation.d.ts +18 -0
- package/dist/composables/useFormFieldErrorHandling.d.ts +2 -2
- package/dist/composables/validation/useFormValidation.d.ts +11 -2
- package/dist/composables/validation/useValidation.d.ts +15 -9
- package/dist/design-system-v3.d.ts +2 -0
- package/dist/design-system-v3.js +186 -187
- package/dist/design-system-v3.umd.cjs +1 -1066
- package/dist/{main-aLKwdMi1.js → main-BtTqyn4z.js} +16434 -15672
- package/dist/main-C1e3eoxd.cjs +1067 -0
- package/dist/main.d.ts +0 -1
- package/dist/synapse.css +1 -0
- package/dist/tooth-11-D3sLWv2n.cjs +1 -0
- package/dist/tooth-12-CXrLuH03.cjs +1 -0
- package/dist/tooth-13-BSfo5fpT.cjs +1 -0
- package/dist/tooth-14-DMzulx0h.cjs +1 -0
- package/dist/tooth-15-BKRFVi-9.cjs +1 -0
- package/dist/tooth-16-CpuxAbuM.cjs +1 -0
- package/dist/tooth-17-BPoahUdg.cjs +1 -0
- package/dist/tooth-18-DhHJz8sy.cjs +1 -0
- package/dist/tooth-21-Dgd5hn_X.cjs +1 -0
- package/dist/tooth-22-C2Tn19sB.cjs +1 -0
- package/dist/tooth-23-C9uaaSGb.cjs +1 -0
- package/dist/tooth-24-BrK9UGpf.cjs +1 -0
- package/dist/tooth-25-CE_EfGNp.cjs +1 -0
- package/dist/tooth-26-Ctv4i9Fy.cjs +1 -0
- package/dist/tooth-27-C5J7JkWM.cjs +1 -0
- package/dist/tooth-28-Z9oWqjo0.cjs +1 -0
- package/dist/tooth-31-BrYqmkTi.cjs +1 -0
- package/dist/tooth-32-BNNR0oCZ.cjs +1 -0
- package/dist/tooth-33-DuxvqO2J.cjs +1 -0
- package/dist/tooth-34-BCSCXMB6.cjs +1 -0
- package/dist/tooth-35-BLUXkX88.cjs +1 -0
- package/dist/tooth-36-IrKHYqlA.cjs +1 -0
- package/dist/tooth-37-BYqpdMwo.cjs +1 -0
- package/dist/tooth-38-B_eNXXdu.cjs +1 -0
- package/dist/tooth-41-Ddva4Ot8.cjs +1 -0
- package/dist/tooth-42-szcDqlM0.cjs +1 -0
- package/dist/tooth-43-B3ka6rQm.cjs +1 -0
- package/dist/tooth-44-CazyQucj.cjs +1 -0
- package/dist/tooth-45-B4HQtc8n.cjs +1 -0
- package/dist/tooth-46-BPM40gbG.cjs +1 -0
- package/dist/tooth-47-Dvr20dlh.cjs +1 -0
- package/dist/tooth-48-Bd8ljGsF.cjs +1 -0
- package/dist/tooth-51-OBpwCOF3.cjs +1 -0
- package/dist/tooth-52-aKxyHcmq.cjs +1 -0
- package/dist/tooth-53-vCwJjTOc.cjs +1 -0
- package/dist/tooth-54-DsWu2iFy.cjs +1 -0
- package/dist/tooth-55-BxC1X2Dn.cjs +1 -0
- package/dist/tooth-61-BbLvxMQi.cjs +1 -0
- package/dist/tooth-62-CmTkWczP.cjs +1 -0
- package/dist/tooth-63-DI7l_2qI.cjs +1 -0
- package/dist/tooth-64-B21sOsJh.cjs +1 -0
- package/dist/tooth-65-D2ZC2VEr.cjs +1 -0
- package/dist/tooth-71-D473PPO5.cjs +1 -0
- package/dist/tooth-72-Drh1wnNu.cjs +1 -0
- package/dist/tooth-73-DzlwYI23.cjs +1 -0
- package/dist/tooth-74-8aGvcZPg.cjs +1 -0
- package/dist/tooth-75-BFK7At_r.cjs +1 -0
- package/dist/tooth-81-BZmR-I0M.cjs +1 -0
- package/dist/tooth-82-euVfUUZV.cjs +1 -0
- package/dist/tooth-83-KV010j64.cjs +1 -0
- package/dist/tooth-84-BBg1RjhZ.cjs +1 -0
- package/dist/tooth-85-Cr-kc1wM.cjs +1 -0
- package/dist/vuetifyConfig.js +561 -0
- package/dist/vuetifyConfig.umd.cjs +1 -0
- package/package.json +10 -4
- package/src/assets/overrides/_btns.scss +0 -6
- package/src/assets/overrides/_icons.scss +9 -1
- package/src/assets/overrides/_typography.scss +0 -10
- package/src/components/Amelipro/AmeliproAutoCompleteField/__tests__/__snapshots__/AmeliproAutoCompleteField.spec.ts.snap +2 -2
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/__tests__/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproTextArea/__tests__/__snapshots__/AmeliproTextArea.spec.ts.snap +2 -2
- package/src/components/Captcha/accessibilite/Accessibility.mdx +86 -8
- package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +12 -12
- package/src/components/ChipList/ChipList.stories.ts +0 -15
- package/src/components/ChipList/ChipList.vue +5 -1
- package/src/components/ChipList/accessibilite/Accessibility.mdx +83 -10
- package/src/components/ChipList/tests/ChipList.a11y.spec.ts +41 -0
- package/src/components/Customs/Selects/SelectBtnField/accessibilite/Accessibility.mdx +0 -9
- package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +22 -5
- package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.spec.ts +143 -0
- package/src/components/Customs/Selects/SyAutocomplete/utils/ariaManager.ts +14 -10
- package/src/components/Customs/Selects/SyInputSelect/SyInputSelect.stories.ts +4 -4
- package/src/components/Customs/Selects/SyInputSelect/SyInputSelect.vue +8 -9
- package/src/components/Customs/Selects/SyInputSelect/tests/SyInputSelect.spec.ts +10 -10
- package/src/components/Customs/Selects/SySelect/SySelect.vue +14 -11
- package/src/components/Customs/Selects/SySelect/tests/SySelect.spec.ts +54 -0
- package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +6 -9
- package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +10 -16
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +16 -11
- package/src/components/Customs/SyCheckbox/accessibilite/Accessibility.mdx +35 -0
- package/src/components/Customs/SyCheckbox/tests/SyCheckbox.a11y.spec.ts +134 -2
- package/src/components/Customs/SyForm/SyForm.stories.ts +31 -5
- package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +4 -7
- package/src/components/Customs/SyTextField/SyTextField.mdx +1 -1
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +29 -27
- package/src/components/Customs/SyTextField/SyTextField.vue +154 -157
- package/src/components/Customs/SyTextField/tests/SyTextField.a11y.spec.ts +32 -0
- package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +120 -11
- package/src/components/DatePicker/CalendarMode/DatePicker.stories.ts +62 -58
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +330 -223
- package/src/components/DatePicker/CalendarMode/accessibilite/Accessibility.mdx +82 -0
- package/src/components/DatePicker/CalendarMode/tests/DatePicker.a11y.spec.ts +141 -0
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +2 -56
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +195 -159
- package/src/components/DatePicker/ComplexDatePicker/accessibilite/Accessibility.mdx +76 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +10 -10
- package/src/components/DatePicker/DatePickerValidationExample/CalendarMode.stories.ts +8 -8
- package/src/components/DatePicker/DatePickerValidationExample/ComplexDatePicker.stories.ts +106 -8
- package/src/components/DatePicker/DatePickerValidationExample/DateTextInput.stories.ts +12 -11
- package/src/components/DatePicker/DatePickerValidationExample/MultiMode.stories.ts +12 -12
- package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +0 -12
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +63 -57
- package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +3 -0
- package/src/components/DatePicker/DateTextInput/accessibilite/Accessibility.mdx +66 -0
- package/src/components/DatePicker/DateTextInput/tests/DateTextInput.spec.ts +52 -1
- package/src/components/DatePicker/composables/index.ts +1 -0
- package/src/components/DatePicker/composables/tests/useCalendarKeyboardNavigation.spec.ts +109 -65
- package/src/components/DatePicker/composables/tests/useDatePickerFocusTrap.spec.ts +138 -0
- package/src/components/DatePicker/composables/tests/useDateValidation.spec.ts +74 -18
- package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +39 -0
- package/src/components/DatePicker/composables/tests/useManualDateValidation.spec.ts +91 -0
- package/src/components/DatePicker/composables/useCalendarKeyboardNavigation.ts +442 -36
- package/src/components/DatePicker/composables/useDatePickerFocusTrap.ts +92 -0
- package/src/components/DatePicker/composables/useDateTextField.ts +7 -6
- package/src/components/DatePicker/composables/useDateValidation.ts +36 -35
- package/src/components/DatePicker/composables/useInputBlurHandler.ts +3 -3
- package/src/components/DatePicker/composables/useManualDateValidation.ts +6 -2
- package/src/components/DiacriticPicker/accessibilite/Accessibility.mdx +76 -8
- package/src/components/HeaderBar/HeaderBar.stories.ts +14 -2
- package/src/components/Logo/accessibilite/Accessibility.mdx +73 -11
- package/src/components/LogoBrandSection/accessibilite/Accessibility.mdx +85 -9
- package/src/components/LunarCalendar/tests/LunarCalendar.spec.ts +3 -1
- package/src/components/LunarCalendar/useLunarCalendarValidation.ts +4 -5
- package/src/components/MonthPicker/tests/MonthPicker.spec.ts +2 -1
- package/src/components/MonthPicker/tests/__snapshots__/MonthPicker.spec.ts.snap +7 -7
- package/src/components/NirField/NirField.stories.ts +4 -0
- package/src/components/NirField/NirField.vue +64 -260
- package/src/components/NirField/accessibilite/Accessibility.mdx +2 -2
- package/src/components/NirField/locales.ts +1 -1
- package/src/components/NirField/tests/NirField.spec.ts +6 -0
- package/src/components/NirField/useNirValidation.ts +271 -0
- package/src/components/PasswordField/PasswordField.stories.ts +4 -4
- package/src/components/PasswordField/PasswordField.vue +18 -24
- package/src/components/PasswordField/tests/PasswordField.spec.ts +6 -3
- package/src/components/PeriodField/PeriodField.stories.ts +4 -4
- package/src/components/PeriodField/PeriodField.vue +57 -57
- package/src/components/PeriodField/__tests__/PeriodField.async.spec.ts +32 -0
- package/src/components/PeriodField/accessibilite/Accessibility.mdx +68 -8
- package/src/components/PeriodField/tests/PeriodField.spec.ts +28 -2
- package/src/components/PhoneField/PhoneField.vue +5 -6
- package/src/components/PhoneField/tests/PhoneField.spec.ts +1 -0
- package/src/components/RangeField/RangeField.vue +6 -0
- package/src/components/SyTextArea/SyTextArea.stories.ts +138 -2
- package/src/components/SyTextArea/SyTextArea.vue +53 -23
- package/src/components/SyTextArea/tests/SyTextArea.spec.ts +126 -3
- package/src/components/SyTextArea/useDefaultValidationRules.ts +74 -0
- package/src/components/Tables/SyServerTable/SyServerTable.mdx +25 -0
- package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +673 -1
- package/src/components/Tables/SyServerTable/SyServerTable.vue +148 -91
- package/src/components/Tables/SyServerTable/tests/SyServerTable.a11y.spec.ts +58 -0
- package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +122 -0
- package/src/components/Tables/SyTable/SyTable.mdx +25 -0
- package/src/components/Tables/SyTable/SyTable.stories.ts +452 -1
- package/src/components/Tables/SyTable/SyTable.vue +130 -56
- package/src/components/Tables/SyTable/tests/SyTable.a11y.spec.ts +57 -0
- package/src/components/Tables/SyTable/tests/SyTable.spec.ts +108 -0
- package/src/components/Tables/common/SyTableFilter.vue +22 -2
- package/src/components/Tables/common/TableHeader.vue +5 -1
- package/src/components/Tables/common/filters/AutocompleteFilter.vue +160 -0
- package/src/components/Tables/common/filters/NumberFilter.vue +1 -1
- package/src/components/Tables/common/filters/SelectFilter.vue +10 -11
- package/src/components/Tables/common/filters/TextFilter.vue +1 -1
- package/src/components/Tables/common/filters/getFilterComponent.ts +8 -1
- package/src/components/Tables/common/filters/locales.ts +0 -1
- package/src/components/Tables/common/filters/tests/AutocompleteFilter.a11y.spec.ts +110 -0
- package/src/components/Tables/common/filters/tests/AutocompleteFilter.spec.ts +203 -0
- package/src/components/Tables/common/filters/tests/SelectFilter.a11y.spec.ts +104 -0
- package/src/components/Tables/common/filters/tests/SelectFilter.spec.ts +152 -16
- package/src/components/Tables/common/tableFilterUtils.ts +3 -0
- package/src/components/Tables/common/tableStyles.scss +48 -4
- package/src/components/Tables/common/tests/filterByRange.spec.ts +2 -1
- package/src/components/Tables/common/types.ts +13 -4
- package/src/components/Tables/common/useClickableTableRow.ts +103 -0
- package/src/components/Tables/common/usePagination.ts +13 -0
- package/src/components/Tables/common/usePinnedColumns.ts +237 -0
- package/src/components/Tables/common/useTableHeaders.ts +3 -3
- package/src/components/Tables/common/useTableRowCheckboxAccessibility.ts +41 -0
- package/src/composables/date/tests/useDatePickerAccessibility.spec.ts +2 -6
- package/src/composables/date/useDatePickerAccessibility.ts +42 -207
- package/src/composables/rules/tests/useFieldValidation.spec.ts +120 -120
- package/src/composables/rules/useFieldValidation.ts +34 -17
- package/src/composables/unifyValidation/tests/useCustomValidation.spec.ts +601 -0
- package/src/composables/unifyValidation/tests/useValidation.spec.ts +2048 -0
- package/src/composables/unifyValidation/tests/useVuetifyValidation.spec.ts +184 -0
- package/src/composables/unifyValidation/useCustomValidation.ts +95 -0
- package/src/composables/unifyValidation/useValidation.ts +190 -0
- package/src/composables/unifyValidation/useVuetifyValidation.ts +54 -0
- package/src/composables/useFormFieldErrorHandling.ts +4 -7
- package/src/composables/validation/tests/useFormValidation.spec.ts +14 -0
- package/src/composables/validation/tests/useValidation.spec.ts +116 -21
- package/src/composables/validation/useFormValidation.ts +20 -13
- package/src/composables/validation/useValidatable.ts +8 -1
- package/src/composables/validation/useValidation.ts +135 -99
- package/src/composantsVuetify/Introduction.mdx +48 -0
- package/src/composantsVuetify/VBtn/VBtn.mdx +72 -0
- package/src/composantsVuetify/VBtn/v-btn.stories.ts +121 -0
- package/src/composantsVuetify/VTooltip/VTooltip.mdx +32 -0
- package/src/composantsVuetify/VTooltip/v-tooltip.stories.ts +95 -0
- package/src/designTokens/tokens/cnam/cnamSemantic.ts +2 -2
- package/src/main.ts +0 -2
- package/src/stories/Components/Components.stories.ts +74 -9
- package/src/stories/Demarrer/Accueil.stories.ts +3 -3
- package/src/stories/GuideDuDev/Amelipro.mdx +15 -0
- package/src/stories/GuideDuDev/Amelipro.stories.ts +209 -0
- package/src/stories/GuideDuDev/vuetifyOptions.mdx +3 -3
- package/dist/SelectFilter-BioGT6Nn.js +0 -136
- package/dist/style.css +0 -1
- package/src/components/DatePicker/Accessibilite.mdx +0 -14
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { type ValidationRule as SyValidationRule } from '@/composables/validation/useValidation'
|
|
2
|
+
import { computed, nextTick, onBeforeUnmount, onMounted, ref, type Ref } from 'vue'
|
|
3
|
+
import { checkNIR, isNIRKeyValid } from './nirValidation'
|
|
4
|
+
import type { locales } from './locales'
|
|
5
|
+
import { useValidation } from '@/composables/unifyValidation/useValidation'
|
|
6
|
+
import type { SyTextField } from '@/main'
|
|
7
|
+
import type { ValidationRule as VuetifyValidationRule } from 'vuetify'
|
|
8
|
+
|
|
9
|
+
export type NirValidationProps = {
|
|
10
|
+
customKeyRules?: SyValidationRule[]
|
|
11
|
+
customKeyWarningRules?: SyValidationRule[]
|
|
12
|
+
customNumberRules?: SyValidationRule[]
|
|
13
|
+
customNumberWarningRules?: SyValidationRule[]
|
|
14
|
+
customRulesPrecedence?: boolean
|
|
15
|
+
disabled?: boolean
|
|
16
|
+
isValidateOnBlur?: boolean
|
|
17
|
+
keyLabel?: string
|
|
18
|
+
keyRules?: VuetifyValidationRule[]
|
|
19
|
+
nirType?: 'simple' | 'complexe'
|
|
20
|
+
numberLabel?: string
|
|
21
|
+
numberRules?: VuetifyValidationRule[]
|
|
22
|
+
readonly?: boolean
|
|
23
|
+
required?: boolean
|
|
24
|
+
showSuccessMessages?: boolean
|
|
25
|
+
useVuetifyValidation?: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handle validation for NIR fields, including both the number and the key
|
|
30
|
+
*/
|
|
31
|
+
export function useNirValidation(
|
|
32
|
+
numberValue: Ref<string>,
|
|
33
|
+
keyValue: Ref<string>,
|
|
34
|
+
unmaskedNumberValue: Ref<string>,
|
|
35
|
+
unmaskedKeyValue: Ref<string>,
|
|
36
|
+
readonly: Ref<boolean>,
|
|
37
|
+
disabled: Ref<boolean>,
|
|
38
|
+
required: Ref<boolean>,
|
|
39
|
+
numberField: Ref<InstanceType<typeof SyTextField> | null>,
|
|
40
|
+
keyField: Ref<InstanceType<typeof SyTextField> | null>,
|
|
41
|
+
customLocale: Ref<typeof locales>,
|
|
42
|
+
numberLabel: Ref<string>,
|
|
43
|
+
keyLabel: Ref<string>,
|
|
44
|
+
customNumberRules: Ref<SyValidationRule[]>,
|
|
45
|
+
customKeyRules: Ref<SyValidationRule[]>,
|
|
46
|
+
customNumberWarningRules: Ref<SyValidationRule[]>,
|
|
47
|
+
customKeyWarningRules: Ref<SyValidationRule[]>,
|
|
48
|
+
displayKey: Ref<boolean>,
|
|
49
|
+
customRulesPrecedence: Ref<boolean>,
|
|
50
|
+
nirType: Ref<'simple' | 'complexe'>,
|
|
51
|
+
label: Ref<string>,
|
|
52
|
+
showSuccessMessages: Ref<boolean>,
|
|
53
|
+
disableErrorHandling: Ref<boolean>,
|
|
54
|
+
isValidateOnBlur: Ref<boolean>,
|
|
55
|
+
useVuetifyValidation: Ref<boolean>,
|
|
56
|
+
vuetifyNumberRules: Ref<VuetifyValidationRule[]>,
|
|
57
|
+
vuetifyKeyRules: Ref<VuetifyValidationRule[]>,
|
|
58
|
+
) {
|
|
59
|
+
// Règles de validation
|
|
60
|
+
const numberRules = computed(() => {
|
|
61
|
+
if (useVuetifyValidation.value) {
|
|
62
|
+
return []
|
|
63
|
+
}
|
|
64
|
+
const rules: SyValidationRule[] = []
|
|
65
|
+
if (required.value) {
|
|
66
|
+
rules.push({
|
|
67
|
+
type: 'required',
|
|
68
|
+
options: {
|
|
69
|
+
message: customLocale.value.errorRequiredNumber,
|
|
70
|
+
fieldIdentifier: numberLabel.value,
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Ajout des règles personnalisées avec prévalence si demandé
|
|
76
|
+
if (customRulesPrecedence.value && customNumberRules.value && customNumberRules.value.length > 0) {
|
|
77
|
+
rules.push(...customNumberRules.value.map(rule => ({
|
|
78
|
+
...rule,
|
|
79
|
+
options: rule.options || {},
|
|
80
|
+
})))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Règle de validation standard du NIR
|
|
84
|
+
rules.push({
|
|
85
|
+
type: 'custom',
|
|
86
|
+
options: {
|
|
87
|
+
validate: (value: string) => {
|
|
88
|
+
if (!value) return true
|
|
89
|
+
// Ne valider que si tous les caractères sont saisis
|
|
90
|
+
if (value.length < 13) {
|
|
91
|
+
return customLocale.value.errorInvalidNumber || customLocale.value.errorInvalidNumber
|
|
92
|
+
}
|
|
93
|
+
const result = checkNIR(value, nirType.value)
|
|
94
|
+
return result ? true : customLocale.value.errorInvalidNumber || customLocale.value.errorInvalidNumber
|
|
95
|
+
},
|
|
96
|
+
message: customLocale.value.errorInvalidNumber,
|
|
97
|
+
successMessage: customLocale.value.successNumberValid,
|
|
98
|
+
fieldIdentifier: numberLabel.value,
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// Ajout des règles personnalisées sans prévalence (comportement par défaut)
|
|
103
|
+
if (!customRulesPrecedence.value && customNumberRules.value && customNumberRules.value.length > 0) {
|
|
104
|
+
rules.push(...customNumberRules.value.map(rule => ({
|
|
105
|
+
...rule,
|
|
106
|
+
options: rule.options || {},
|
|
107
|
+
})))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return rules
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const keyRules = computed(() => {
|
|
114
|
+
if (useVuetifyValidation.value) {
|
|
115
|
+
return []
|
|
116
|
+
}
|
|
117
|
+
const rules: SyValidationRule[] = []
|
|
118
|
+
if (required.value) {
|
|
119
|
+
rules.push({
|
|
120
|
+
type: 'required',
|
|
121
|
+
options: {
|
|
122
|
+
message: customLocale.value.errorRequiredKey,
|
|
123
|
+
fieldIdentifier: keyLabel.value,
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const validateKey = (value: string) => {
|
|
129
|
+
if (!value) return true
|
|
130
|
+
if (!unmaskedNumberValue.value) return true
|
|
131
|
+
const fullNir = unmaskedNumberValue.value + value
|
|
132
|
+
return isNIRKeyValid(fullNir)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Ajout des règles personnalisées
|
|
136
|
+
if (customKeyRules.value) {
|
|
137
|
+
rules.push(...customKeyRules.value)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Ajout de la règle de validation par défaut si pas de règle personnalisée avec validation de clé
|
|
141
|
+
if (!customKeyRules.value?.some(rule => rule.options.validate)) {
|
|
142
|
+
rules.push({
|
|
143
|
+
type: 'custom',
|
|
144
|
+
options: {
|
|
145
|
+
validate: validateKey,
|
|
146
|
+
message: customLocale.value.errorInvalidKey,
|
|
147
|
+
successMessage: customLocale.value.successKeyValid,
|
|
148
|
+
fieldIdentifier: keyLabel.value,
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return rules
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// État pour suivre si une validation est en cours
|
|
157
|
+
const isValidating = ref(false)
|
|
158
|
+
const shouldValidateOnBlur = ref(false)
|
|
159
|
+
const numberFieldFocused = ref(false)
|
|
160
|
+
const keyFieldFocused = ref(false)
|
|
161
|
+
|
|
162
|
+
// update focus state on blur and focus
|
|
163
|
+
const onNumberFocus = () => {
|
|
164
|
+
numberFieldFocused.value = true
|
|
165
|
+
}
|
|
166
|
+
const onNumberBlur = () => {
|
|
167
|
+
numberFieldFocused.value = false
|
|
168
|
+
}
|
|
169
|
+
const onKeyFocus = () => {
|
|
170
|
+
keyFieldFocused.value = true
|
|
171
|
+
}
|
|
172
|
+
const onKeyBlur = () => {
|
|
173
|
+
keyFieldFocused.value = false
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let numberInput: HTMLInputElement | null = null
|
|
177
|
+
let keyInput: HTMLInputElement | null = null
|
|
178
|
+
|
|
179
|
+
onMounted(() => {
|
|
180
|
+
numberInput = numberField.value?.$el?.querySelector('input') ?? null
|
|
181
|
+
if (numberInput) {
|
|
182
|
+
numberInput.addEventListener('focus', onNumberFocus)
|
|
183
|
+
numberInput.addEventListener('blur', onNumberBlur)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
keyInput = keyField.value?.$el?.querySelector('input') ?? null
|
|
187
|
+
if (keyInput) {
|
|
188
|
+
keyInput.addEventListener('focus', onKeyFocus)
|
|
189
|
+
keyInput.addEventListener('blur', onKeyBlur)
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
onBeforeUnmount(() => {
|
|
194
|
+
numberInput?.removeEventListener('focus', onNumberFocus)
|
|
195
|
+
numberInput?.removeEventListener('blur', onNumberBlur)
|
|
196
|
+
keyInput?.removeEventListener('focus', onKeyFocus)
|
|
197
|
+
keyInput?.removeEventListener('blur', onKeyBlur)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
const numberValidation = useValidation({
|
|
201
|
+
modelValue: numberValue,
|
|
202
|
+
readonly,
|
|
203
|
+
disabled,
|
|
204
|
+
required,
|
|
205
|
+
isValidateOnBlur,
|
|
206
|
+
showSuccessMessages,
|
|
207
|
+
disableErrorHandling,
|
|
208
|
+
useVuetifyValidation,
|
|
209
|
+
label,
|
|
210
|
+
customRules: numberRules,
|
|
211
|
+
customWarningRules: computed(() => unmaskedNumberValue.value.length === 13 ? customNumberWarningRules.value : []),
|
|
212
|
+
rules: vuetifyNumberRules,
|
|
213
|
+
focused: numberFieldFocused,
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
const keyValidation = useValidation({
|
|
217
|
+
modelValue: keyValue,
|
|
218
|
+
readonly,
|
|
219
|
+
disabled,
|
|
220
|
+
required,
|
|
221
|
+
isValidateOnBlur,
|
|
222
|
+
showSuccessMessages,
|
|
223
|
+
disableErrorHandling,
|
|
224
|
+
useVuetifyValidation,
|
|
225
|
+
label,
|
|
226
|
+
customRules: keyRules,
|
|
227
|
+
customWarningRules: computed(() => (displayKey.value && unmaskedKeyValue.value.length === 2) ? customKeyWarningRules.value : []),
|
|
228
|
+
rules: vuetifyKeyRules,
|
|
229
|
+
focused: keyFieldFocused,
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
// Validation des champs
|
|
233
|
+
const validateFields = async (onBlur = false) => {
|
|
234
|
+
// Éviter les validations redondantes
|
|
235
|
+
if (isValidating.value) {
|
|
236
|
+
shouldValidateOnBlur.value = shouldValidateOnBlur.value || onBlur
|
|
237
|
+
return true
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
isValidating.value = true
|
|
241
|
+
|
|
242
|
+
await numberValidation.validate()
|
|
243
|
+
|
|
244
|
+
if (displayKey.value) {
|
|
245
|
+
await keyValidation.validate()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (onBlur || shouldValidateOnBlur.value) {
|
|
249
|
+
await nextTick()
|
|
250
|
+
if (numberValidation.hasError.value) {
|
|
251
|
+
numberField.value?.$el?.querySelector?.('input')?.focus()
|
|
252
|
+
}
|
|
253
|
+
else if (keyValidation.hasError.value) {
|
|
254
|
+
keyField.value?.$el?.querySelector?.('input')?.focus()
|
|
255
|
+
}
|
|
256
|
+
shouldValidateOnBlur.value = false
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
isValidating.value = false
|
|
260
|
+
return !numberValidation.hasError.value && !keyValidation.hasError.value
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const hasFieldErrors = computed(() => numberValidation.hasError.value || keyValidation.hasError.value)
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
numberValidation,
|
|
267
|
+
keyValidation,
|
|
268
|
+
validateFields,
|
|
269
|
+
hasFieldErrors,
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -962,9 +962,9 @@ export const WithFormValidation: Story = {
|
|
|
962
962
|
]
|
|
963
963
|
|
|
964
964
|
// Fonction de soumission du formulaire
|
|
965
|
-
const handleSubmit = () => {
|
|
965
|
+
const handleSubmit = async (): Promise<void> => {
|
|
966
966
|
if (passwordFieldRef.value) {
|
|
967
|
-
const isValid = passwordFieldRef.value.validateOnSubmit()
|
|
967
|
+
const isValid = await passwordFieldRef.value.validateOnSubmit()
|
|
968
968
|
if (isValid) {
|
|
969
969
|
formStatus.value = 'Formulaire soumis avec succès !'
|
|
970
970
|
} else {
|
|
@@ -1013,9 +1013,9 @@ export const WithFormValidation: Story = {
|
|
|
1013
1013
|
]
|
|
1014
1014
|
|
|
1015
1015
|
// Fonction de soumission du formulaire
|
|
1016
|
-
const handleSubmit = () => {
|
|
1016
|
+
const handleSubmit = async () => {
|
|
1017
1017
|
if (passwordFieldRef.value) {
|
|
1018
|
-
const isValid = passwordFieldRef.value.validateOnSubmit()
|
|
1018
|
+
const isValid = await passwordFieldRef.value.validateOnSubmit()
|
|
1019
1019
|
if (isValid) {
|
|
1020
1020
|
formStatus.value = 'Formulaire soumis avec succès !'
|
|
1021
1021
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
modelValue?: string | null
|
|
21
21
|
variantStyle?: 'outlined' | 'underlined'
|
|
22
22
|
color?: ColorType
|
|
23
|
-
label
|
|
23
|
+
label: string
|
|
24
24
|
required?: boolean
|
|
25
25
|
errorMessages?: string[] | null
|
|
26
26
|
warningMessages?: string[] | null
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
modelValue: null,
|
|
42
42
|
variantStyle: 'outlined',
|
|
43
43
|
color: 'primary',
|
|
44
|
-
label: undefined,
|
|
45
44
|
required: false,
|
|
46
45
|
errorMessages: null,
|
|
47
46
|
warningMessages: null,
|
|
@@ -96,25 +95,12 @@
|
|
|
96
95
|
})
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
// Règle pour le message de succès
|
|
100
|
-
// rules.push({
|
|
101
|
-
// type: 'custom',
|
|
102
|
-
// options: {
|
|
103
|
-
// validate: (value: string) => value ? true : 'Ce champ est requis',
|
|
104
|
-
// successMessage: 'Mot de passe fort',
|
|
105
|
-
// fieldIdentifier: props.label || 'password',
|
|
106
|
-
// },
|
|
107
|
-
// })
|
|
108
|
-
|
|
109
98
|
return rules
|
|
110
99
|
})
|
|
111
100
|
|
|
112
101
|
// Initialisation du composable de validation
|
|
113
102
|
const { errors, warnings, successes, validateField } = !props.readonly
|
|
114
103
|
? useValidation({
|
|
115
|
-
customRules: defaultRules.value,
|
|
116
|
-
warningRules: props.customWarningRules || [],
|
|
117
|
-
successRules: props.customSuccessRules || [],
|
|
118
104
|
showSuccessMessages: props.showSuccessMessages,
|
|
119
105
|
fieldIdentifier: props.label || 'password',
|
|
120
106
|
disableErrorHandling: props.disableErrorHandling,
|
|
@@ -123,7 +109,7 @@
|
|
|
123
109
|
errors: ref<string[]>([]),
|
|
124
110
|
warnings: ref<string[]>([]),
|
|
125
111
|
successes: ref<string[]>([]),
|
|
126
|
-
validateField: () => {},
|
|
112
|
+
validateField: () => ({ hasError: false, hasWarning: false, hasSuccess: false, state: { errors: [], warnings: [], successes: [] } }),
|
|
127
113
|
}
|
|
128
114
|
|
|
129
115
|
const hasError = computed(() => errors.value.length > 0)
|
|
@@ -199,15 +185,15 @@
|
|
|
199
185
|
})
|
|
200
186
|
}
|
|
201
187
|
|
|
202
|
-
function handleKeydown(event: KeyboardEvent): void {
|
|
188
|
+
async function handleKeydown(event: KeyboardEvent): Promise<void> {
|
|
203
189
|
if (event.key === 'Enter') {
|
|
204
|
-
validateOnSubmit()
|
|
190
|
+
await validateOnSubmit()
|
|
205
191
|
}
|
|
206
192
|
}
|
|
207
193
|
|
|
208
|
-
const validateOnSubmit = (): boolean => {
|
|
194
|
+
const validateOnSubmit = async (): Promise<boolean> => {
|
|
209
195
|
if (props.readonly) return true // Retourner true au lieu de undefined
|
|
210
|
-
validateField(password.value, [...defaultRules.value, ...(props.customRules || [])], props.customWarningRules || [], props.customSuccessRules || [])
|
|
196
|
+
await validateField(password.value, [...defaultRules.value, ...(props.customRules || [])], props.customWarningRules || [], props.customSuccessRules || [])
|
|
211
197
|
const isValid = errors.value.length === 0
|
|
212
198
|
if (isValid) {
|
|
213
199
|
emit('submit')
|
|
@@ -280,7 +266,16 @@
|
|
|
280
266
|
:autocomplete="props.autocompleteType"
|
|
281
267
|
class="vd-password"
|
|
282
268
|
:validate-on="props.isValidateOnBlur ? 'blur lazy' : 'lazy'"
|
|
283
|
-
@blur="
|
|
269
|
+
@blur="async () => {
|
|
270
|
+
if (props.isValidateOnBlur && !props.readonly) {
|
|
271
|
+
await validateField(
|
|
272
|
+
password,
|
|
273
|
+
[...defaultRules, ...(props.customRules || [])],
|
|
274
|
+
props.customWarningRules || [],
|
|
275
|
+
props.customSuccessRules || []
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
}"
|
|
284
279
|
@keydown="handleKeydown"
|
|
285
280
|
>
|
|
286
281
|
<template #append-inner>
|
|
@@ -293,8 +288,7 @@
|
|
|
293
288
|
decorative
|
|
294
289
|
class="mr-2"
|
|
295
290
|
/>
|
|
296
|
-
|
|
297
|
-
<v-button
|
|
291
|
+
<VBtn
|
|
298
292
|
type="button"
|
|
299
293
|
class="password-toggle-button"
|
|
300
294
|
:aria-label="btnLabel"
|
|
@@ -311,7 +305,7 @@
|
|
|
311
305
|
:aria-hidden="true"
|
|
312
306
|
decorative
|
|
313
307
|
/>
|
|
314
|
-
</
|
|
308
|
+
</VBtn>
|
|
315
309
|
</div>
|
|
316
310
|
<div
|
|
317
311
|
:id="`${passwordFieldId}-status`"
|
|
@@ -6,7 +6,7 @@ import { describe, it, expect } from 'vitest'
|
|
|
6
6
|
interface PasswordFieldVM {
|
|
7
7
|
showEyeIcon: boolean
|
|
8
8
|
errors: string[]
|
|
9
|
-
validateOnSubmit: () => boolean
|
|
9
|
+
validateOnSubmit: () => Promise<boolean>
|
|
10
10
|
hasError: boolean
|
|
11
11
|
hasWarning: boolean
|
|
12
12
|
hasSuccess: boolean
|
|
@@ -65,12 +65,12 @@ describe('PasswordField.vue', () => {
|
|
|
65
65
|
})
|
|
66
66
|
const vm = wrapper.vm as unknown as PasswordFieldVM
|
|
67
67
|
|
|
68
|
-
const result = vm.validateOnSubmit()
|
|
68
|
+
const result = await vm.validateOnSubmit()
|
|
69
69
|
expect(result).toBe(false)
|
|
70
70
|
expect(vm.errors).toContain('Le mot de passe est requis')
|
|
71
71
|
|
|
72
72
|
await wrapper.setProps({ modelValue: 'valid-password' })
|
|
73
|
-
const validResult = vm.validateOnSubmit()
|
|
73
|
+
const validResult = await vm.validateOnSubmit()
|
|
74
74
|
expect(validResult).toBe(true)
|
|
75
75
|
expect(wrapper.emitted().submit).toBeTruthy()
|
|
76
76
|
})
|
|
@@ -78,6 +78,7 @@ describe('PasswordField.vue', () => {
|
|
|
78
78
|
it('displays warning and success messages', async () => {
|
|
79
79
|
const wrapper = mount(PasswordField, {
|
|
80
80
|
props: {
|
|
81
|
+
label: 'Password',
|
|
81
82
|
modelValue: 'test',
|
|
82
83
|
warningMessages: ['Attention: mot de passe court'],
|
|
83
84
|
successMessages: ['Mot de passe valide'],
|
|
@@ -97,6 +98,7 @@ describe('PasswordField.vue', () => {
|
|
|
97
98
|
it('handles custom validation rules', async () => {
|
|
98
99
|
const wrapper = mount(PasswordField, {
|
|
99
100
|
props: {
|
|
101
|
+
label: 'Password',
|
|
100
102
|
modelValue: 'test',
|
|
101
103
|
customRules: [{
|
|
102
104
|
type: 'custom',
|
|
@@ -141,6 +143,7 @@ describe('PasswordField.vue', () => {
|
|
|
141
143
|
it('displays validation states based on validation rules', async () => {
|
|
142
144
|
const wrapper = mount(PasswordField, {
|
|
143
145
|
props: {
|
|
146
|
+
label: 'Password',
|
|
144
147
|
modelValue: 'test',
|
|
145
148
|
customRules: [{
|
|
146
149
|
type: 'custom',
|
|
@@ -995,9 +995,9 @@ export const FormValidation: Story = {
|
|
|
995
995
|
]
|
|
996
996
|
|
|
997
997
|
// Soumission du formulaire
|
|
998
|
-
const submitForm = () => {
|
|
998
|
+
const submitForm = async (): Promise<void> => {
|
|
999
999
|
if (periodFieldRef.value) {
|
|
1000
|
-
const isValid = periodFieldRef.value.validateOnSubmit()
|
|
1000
|
+
const isValid = await periodFieldRef.value.validateOnSubmit()
|
|
1001
1001
|
if (isValid) {
|
|
1002
1002
|
formStatus.value = 'Formulaire soumis avec succès !'
|
|
1003
1003
|
isFormSubmitted.value = true
|
|
@@ -1035,9 +1035,9 @@ export const FormValidation: Story = {
|
|
|
1035
1035
|
]
|
|
1036
1036
|
|
|
1037
1037
|
// Soumission du formulaire
|
|
1038
|
-
const submitForm = () => {
|
|
1038
|
+
const submitForm = async (): Promise<void> => {
|
|
1039
1039
|
if (periodFieldRef.value) {
|
|
1040
|
-
const isValid = periodFieldRef.value.validateOnSubmit()
|
|
1040
|
+
const isValid = await periodFieldRef.value.validateOnSubmit()
|
|
1041
1041
|
if (isValid) {
|
|
1042
1042
|
formStatus.value = 'Formulaire soumis avec succès !'
|
|
1043
1043
|
isFormSubmitted.value = true
|
|
@@ -11,51 +11,51 @@
|
|
|
11
11
|
type PeriodValue = { from: DateInput, to: DateInput }
|
|
12
12
|
|
|
13
13
|
const props = withDefaults(defineProps<{
|
|
14
|
+
bgColor?: string
|
|
15
|
+
customRules?: ValidationRule[]
|
|
16
|
+
customWarningRules?: ValidationRule[]
|
|
17
|
+
dateFormatReturn?: string
|
|
18
|
+
density?: 'default' | 'comfortable' | 'compact'
|
|
19
|
+
disableErrorHandling?: boolean
|
|
20
|
+
disabled?: boolean
|
|
21
|
+
displayAppendIcon?: boolean
|
|
22
|
+
displayIcon?: boolean
|
|
23
|
+
format?: string
|
|
24
|
+
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6
|
|
25
|
+
hideDetails?: boolean | 'auto'
|
|
26
|
+
isOutlined?: boolean
|
|
14
27
|
modelValue?: PeriodValue
|
|
28
|
+
noCalendar?: boolean
|
|
29
|
+
noIcon?: boolean
|
|
15
30
|
placeholderFrom?: string
|
|
16
31
|
placeholderTo?: string
|
|
17
|
-
|
|
18
|
-
dateFormatReturn?: string
|
|
19
|
-
showWeekNumber?: boolean
|
|
32
|
+
readonly?: boolean
|
|
20
33
|
required?: boolean
|
|
21
|
-
displayIcon?: boolean
|
|
22
|
-
displayAppendIcon?: boolean
|
|
23
|
-
disabled?: boolean
|
|
24
|
-
noIcon?: boolean
|
|
25
|
-
noCalendar?: boolean
|
|
26
|
-
isOutlined?: boolean
|
|
27
34
|
showSuccessMessages?: boolean
|
|
28
|
-
|
|
29
|
-
customWarningRules?: ValidationRule[]
|
|
30
|
-
disableErrorHandling?: boolean
|
|
31
|
-
readonly?: boolean
|
|
32
|
-
bgColor?: string
|
|
33
|
-
density?: 'default' | 'comfortable' | 'compact'
|
|
34
|
-
hideDetails?: boolean | 'auto'
|
|
35
|
-
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6
|
|
35
|
+
showWeekNumber?: boolean
|
|
36
36
|
}>(), {
|
|
37
|
+
bgColor: 'white',
|
|
38
|
+
customRules: () => [],
|
|
39
|
+
customWarningRules: () => [],
|
|
40
|
+
dateFormatReturn: '',
|
|
41
|
+
density: 'default',
|
|
42
|
+
disableErrorHandling: false,
|
|
43
|
+
disabled: false,
|
|
44
|
+
displayAppendIcon: false,
|
|
45
|
+
displayIcon: true,
|
|
46
|
+
format: 'DD/MM/YYYY',
|
|
47
|
+
headingLevel: 2,
|
|
48
|
+
hideDetails: false,
|
|
49
|
+
isOutlined: true,
|
|
37
50
|
modelValue: () => ({ from: null, to: null }),
|
|
51
|
+
noCalendar: false,
|
|
52
|
+
noIcon: false,
|
|
38
53
|
placeholderFrom: 'Début',
|
|
39
54
|
placeholderTo: 'Fin',
|
|
40
|
-
|
|
41
|
-
dateFormatReturn: '',
|
|
42
|
-
showWeekNumber: false,
|
|
55
|
+
readonly: false,
|
|
43
56
|
required: false,
|
|
44
|
-
displayIcon: true,
|
|
45
|
-
displayAppendIcon: false,
|
|
46
|
-
disabled: false,
|
|
47
|
-
noIcon: false,
|
|
48
|
-
noCalendar: false,
|
|
49
|
-
isOutlined: true,
|
|
50
57
|
showSuccessMessages: true,
|
|
51
|
-
|
|
52
|
-
customWarningRules: () => [],
|
|
53
|
-
disableErrorHandling: false,
|
|
54
|
-
readonly: false,
|
|
55
|
-
bgColor: 'white',
|
|
56
|
-
density: 'default',
|
|
57
|
-
hideDetails: false,
|
|
58
|
-
headingLevel: 2,
|
|
58
|
+
showWeekNumber: false,
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -230,42 +230,42 @@
|
|
|
230
230
|
})
|
|
231
231
|
|
|
232
232
|
// Synchronisation lorsque l'une des dates change
|
|
233
|
-
function validateBothDates() {
|
|
233
|
+
async function validateBothDates() {
|
|
234
234
|
if (fromDateRef.value) {
|
|
235
235
|
fromDateRef.value.validateOnSubmit()
|
|
236
236
|
}
|
|
237
237
|
if (toDateRef.value) {
|
|
238
|
-
toDateRef.value.validateOnSubmit()
|
|
238
|
+
await toDateRef.value.validateOnSubmit()
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
// Validation complète du PeriodField
|
|
243
|
-
function validateFields() {
|
|
244
|
-
fromDateValidation.validateField(parsedFromDate.value, fromDateRules.value, props.customWarningRules)
|
|
245
|
-
toDateValidation.validateField(parsedToDate.value, toDateRules.value, props.customWarningRules)
|
|
243
|
+
async function validateFields() {
|
|
244
|
+
await fromDateValidation.validateField(parsedFromDate.value, fromDateRules.value, props.customWarningRules)
|
|
245
|
+
await toDateValidation.validateField(parsedToDate.value, toDateRules.value, props.customWarningRules)
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
// Gestionnaires d'événements closed
|
|
249
|
-
function handleFromDateClosed() {
|
|
250
|
-
validateBothDates()
|
|
249
|
+
async function handleFromDateClosed() {
|
|
250
|
+
await validateBothDates()
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
function handleToDateClosed() {
|
|
254
|
-
validateBothDates()
|
|
253
|
+
async function handleToDateClosed() {
|
|
254
|
+
await validateBothDates()
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
// Watch pour les changements des dates - validation croisée
|
|
258
|
-
watch(formattedFromDate, () => {
|
|
259
|
-
validateFields()
|
|
258
|
+
watch(formattedFromDate, async () => {
|
|
259
|
+
await validateFields()
|
|
260
260
|
if (formattedToDate.value && toDateRef.value) {
|
|
261
|
-
toDateRef.value.validateOnSubmit()
|
|
261
|
+
await toDateRef.value.validateOnSubmit()
|
|
262
262
|
}
|
|
263
263
|
})
|
|
264
264
|
|
|
265
|
-
watch(formattedToDate, () => {
|
|
266
|
-
validateFields()
|
|
265
|
+
watch(formattedToDate, async () => {
|
|
266
|
+
await validateFields()
|
|
267
267
|
if (formattedFromDate.value && fromDateRef.value) {
|
|
268
|
-
fromDateRef.value.validateOnSubmit()
|
|
268
|
+
await fromDateRef.value.validateOnSubmit()
|
|
269
269
|
}
|
|
270
270
|
})
|
|
271
271
|
|
|
@@ -278,7 +278,7 @@
|
|
|
278
278
|
})
|
|
279
279
|
|
|
280
280
|
// Watch pour les changements externes - Synchronisation
|
|
281
|
-
watch(() => props.modelValue, (newValue) => {
|
|
281
|
+
watch(() => props.modelValue, async (newValue) => {
|
|
282
282
|
if (!newValue) return
|
|
283
283
|
|
|
284
284
|
const newFromDate = formatDateValue(newValue.from)
|
|
@@ -291,28 +291,28 @@
|
|
|
291
291
|
internalToDate.value = newToDate
|
|
292
292
|
}
|
|
293
293
|
// Valider les champs après la mise à jour des valeurs
|
|
294
|
-
validateFields()
|
|
294
|
+
await validateFields()
|
|
295
295
|
}, { deep: true, immediate: true })
|
|
296
296
|
|
|
297
297
|
// Fonction publique de validation
|
|
298
|
-
const validateOnSubmit = (): boolean => {
|
|
298
|
+
const validateOnSubmit = async (): Promise<boolean> => {
|
|
299
299
|
// Valider les deux CalendarMode
|
|
300
|
-
const fromDateValid = fromDateRef.value?.validateOnSubmit() ?? true
|
|
301
|
-
const toDateValid = toDateRef.value?.validateOnSubmit() ?? true
|
|
300
|
+
const fromDateValid = await fromDateRef.value?.validateOnSubmit() ?? true
|
|
301
|
+
const toDateValid = await toDateRef.value?.validateOnSubmit() ?? true
|
|
302
302
|
|
|
303
303
|
// Valider avec les règles personnalisées
|
|
304
|
-
validateFields()
|
|
304
|
+
await validateFields()
|
|
305
305
|
|
|
306
306
|
// Retourner true seulement si tout est valide
|
|
307
307
|
return fromDateValid && toDateValid && isValid.value
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
// Initialisation
|
|
311
|
-
onMounted(() => {
|
|
311
|
+
onMounted(async () => {
|
|
312
312
|
internalFromDate.value = formatDateValue(props.modelValue?.from)
|
|
313
313
|
internalToDate.value = formatDateValue(props.modelValue?.to)
|
|
314
314
|
// Validation initiale
|
|
315
|
-
validateFields()
|
|
315
|
+
await validateFields()
|
|
316
316
|
})
|
|
317
317
|
|
|
318
318
|
defineExpose({
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { mount, flushPromises } from '@vue/test-utils'
|
|
2
|
+
import PeriodField from '../PeriodField.vue'
|
|
3
|
+
import { describe, it, expect } from 'vitest'
|
|
4
|
+
import { nextTick } from 'vue'
|
|
5
|
+
|
|
6
|
+
describe('PeriodField async validation', () => {
|
|
7
|
+
it('shows error when from date is after to date', async () => {
|
|
8
|
+
const wrapper = mount(PeriodField, {
|
|
9
|
+
props: {
|
|
10
|
+
modelValue: { from: '2024-01-01', to: '2024-01-31' },
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
// Find both DatePicker components
|
|
15
|
+
const datePickers = wrapper.findAllComponents({ name: 'DatePicker' })
|
|
16
|
+
expect(datePickers.length).toBe(2)
|
|
17
|
+
|
|
18
|
+
const fromInput = datePickers[0]!.find('input')
|
|
19
|
+
await fromInput.setValue('15/01/2024')
|
|
20
|
+
await fromInput.trigger('blur')
|
|
21
|
+
await flushPromises()
|
|
22
|
+
|
|
23
|
+
const toInput = datePickers[1]!.find('input')
|
|
24
|
+
await toInput.setValue('10/01/2024')
|
|
25
|
+
await toInput.trigger('blur')
|
|
26
|
+
await flushPromises()
|
|
27
|
+
await nextTick()
|
|
28
|
+
|
|
29
|
+
expect(datePickers[0]?.text()).toContain('date de début ne peut pas être supérieure à la date de fin')
|
|
30
|
+
expect(datePickers[1]?.text()).toContain('La date de fin ne peut pas être inférieure à la date de début')
|
|
31
|
+
})
|
|
32
|
+
})
|