@cnamts/synapse 1.0.26 → 1.0.27
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-BPR-a55G.js → AutocompleteFilter-C9eLKyW8.js} +3 -3
- package/dist/{DateFilter-CknrJWs2.js → DateFilter-y-GLkAkn.js} +8 -8
- package/dist/{NumberFilter-DJ-yNlzv.js → NumberFilter-DN6hIBS7.js} +1 -1
- package/dist/{PeriodFilter-CiB5Oa9Z.js → PeriodFilter-MoUUp9qS.js} +1 -1
- package/dist/{SelectFilter-EiafX97M.js → SelectFilter-bCbrdLmu.js} +1 -1
- package/dist/{TextFilter-BzOmpdxj.js → TextFilter-CvjgEaoM.js} +4 -4
- package/dist/apLightTheme2026-ug4Y23ns.js +611 -0
- package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +2369 -353
- package/dist/components/Customs/Selects/SyAutocomplete/composables/useSyAutocompleteValidation.d.ts +18 -0
- package/dist/components/Customs/Selects/SyAutocomplete/utils/ariaManager.d.ts +1 -1
- package/dist/components/Customs/Selects/SyAutocomplete/utils/useKeyboardHandler.d.ts +3 -1
- package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +9 -10
- package/dist/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.d.ts +1 -0
- package/dist/components/Customs/Selects/SySelect/composables/useSySelectValidation.d.ts +15 -0
- package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +3 -3
- package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +3 -3
- package/dist/components/Customs/SyIconButton/SyIconButton.d.ts +18 -0
- package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +20 -38
- package/dist/components/Customs/SyRadioGroup/composables/useSyRadioGroupValidation.d.ts +50 -0
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +6 -6
- package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +147 -136
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +62 -54
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +27 -24
- package/dist/components/DatePicker/composables/index.d.ts +1 -0
- package/dist/components/DatePicker/composables/useDatePickerValidationBridge.d.ts +51 -0
- package/dist/components/MonthPicker/MonthPicker.d.ts +23 -23
- package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +23 -23
- package/dist/components/NirField/NirField.d.ts +56 -56
- package/dist/components/PasswordField/PasswordField.d.ts +3 -3
- package/dist/components/PeriodField/PeriodField.d.ts +236 -212
- package/dist/components/PhoneField/PhoneField.d.ts +23 -23
- package/dist/components/SyTextArea/SyTextArea.d.ts +25 -15
- package/dist/components/SyTextArea/composables/useSyTextAreaValidation.d.ts +20 -0
- package/dist/components/SyTextArea/locales.d.ts +1 -0
- package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +1 -0
- package/dist/components/Tables/SyTable/SyTable.d.ts +1 -0
- package/dist/components/Tables/common/SyTablePagination.d.ts +25 -25
- package/dist/components/Tables/common/types.d.ts +2 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/composables/unifyValidation/documentationValidationProps.d.ts +160 -160
- package/dist/composables/unifyValidation/useValidation.d.ts +16 -14
- package/dist/design-system-v3.js +81 -80
- package/dist/designTokens/tokens/amelipro/apContextual.d.ts +6 -6
- package/dist/designTokens/tokens/amelipro/apDarkTheme.d.ts +3 -1
- package/dist/designTokens/tokens/amelipro/apLightTheme.d.ts +53 -100
- package/dist/designTokens/tokens/baseContextualTokens.d.ts +0 -6
- package/dist/designTokens/tokens/baseTokens.d.ts +232 -0
- package/dist/designTokens/tokens/cnam/cnamContextual.d.ts +6 -6
- package/dist/designTokens/tokens/cnam/cnamDarkTheme.d.ts +1 -1
- package/dist/designTokens/tokens/cnam/cnamLightTheme.d.ts +57 -101
- package/dist/designTokens/tokens/pa/paContextual.d.ts +0 -6
- package/dist/designTokens/tokens/pa/paDarkTheme.d.ts +1 -1
- package/dist/designTokens/tokens/pa/paLightTheme.d.ts +53 -97
- package/dist/designTokens/tokens/pa/paSemantic.d.ts +1 -0
- package/dist/designTokens/tokens/semanticTokens.d.ts +112 -0
- package/dist/main-CI6Q9nmO.js +39234 -0
- package/dist/synapse.css +1 -1
- package/dist/vuetifyConfig.js +208 -72
- package/package.json +4 -2
- package/src/assets/overrides/_icons.scss +5 -4
- package/src/assets/overrides/_otp.scss +4 -4
- package/src/assets/overrides/_typography.scss +2 -1
- package/src/assets/overrides/_utilities.scss +1 -42
- package/src/components/ChipList/ChipList.vue +30 -18
- package/src/components/ChipList/tests/chipList.spec.ts +4 -4
- package/src/components/CopyBtn/CopyBtn.vue +2 -2
- package/src/components/Customs/Selects/SelectBtnField/SelectBtnField.stories.ts +4 -0
- package/src/components/Customs/Selects/SelectBtnField/SelectBtnField.vue +7 -6
- package/src/components/Customs/Selects/SelectBtnField/tests/SelectBtnField.spec.ts +223 -0
- package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.stories.ts +283 -351
- package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +182 -218
- package/src/components/Customs/Selects/SyAutocomplete/composables/useSyAutocompleteValidation.ts +101 -0
- package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.spec.ts +761 -1
- package/src/components/Customs/Selects/SyAutocomplete/utils/ariaManager.ts +3 -1
- package/src/components/Customs/Selects/SyAutocomplete/utils/useKeyboardHandler.ts +79 -5
- package/src/components/Customs/Selects/SyAutocomplete/validation/Validation.stories.ts +1029 -0
- package/src/components/Customs/Selects/SySelect/SySelect.stories.ts +9 -491
- package/src/components/Customs/Selects/SySelect/SySelect.vue +46 -79
- package/src/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.ts +3 -0
- package/src/components/Customs/Selects/SySelect/composables/useSySelectValidation.ts +64 -0
- package/src/components/Customs/Selects/SySelect/tests/SySelect.spec.ts +196 -0
- package/src/components/Customs/Selects/SySelect/validation/Validation.stories.ts +1026 -0
- package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.stories.ts +18 -7
- package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +2 -2
- package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +8 -8
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +8 -8
- package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +1 -1
- package/src/components/Customs/SyIcon/accessibilite/Accessibility.mdx +0 -6
- package/src/components/Customs/SyIcon/utils/tests/iconUtils.spec.ts +107 -0
- package/src/components/Customs/SyRadioGroup/SyRadioGroup.mdx +2 -2
- package/src/components/Customs/SyRadioGroup/SyRadioGroup.stories.ts +395 -200
- package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +82 -127
- package/src/components/Customs/SyRadioGroup/composables/useSyRadioGroupValidation.ts +127 -0
- package/src/components/Customs/SyRadioGroup/tests/SyRadioGroup.a11y.spec.ts +93 -1
- package/src/components/Customs/SyRadioGroup/tests/SyRadioGroup.spec.ts +146 -9
- package/src/components/Customs/SyRadioGroup/tests/SyRadioGroup.visual.cy.ts +165 -0
- package/src/components/Customs/SyRadioGroup/validation/Validation.stories.ts +773 -0
- package/src/components/Customs/SyTabs/config.ts +3 -3
- package/src/components/Customs/SyTabs/tests/SyTabs.spec.ts +265 -0
- package/src/components/Customs/SyTabs/tests/useTabTransition.spec.ts +188 -0
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +10 -29
- package/src/components/Customs/SyTextField/SyTextField.vue +23 -15
- package/src/components/DataList/DataList.stories.ts +1 -1
- package/src/components/DataListItem/tests/DataListItem.spec.ts +3 -1
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +37 -142
- package/src/components/DatePicker/CalendarMode/tests/DatePicker.coverage.spec.ts +156 -0
- package/src/components/DatePicker/CalendarMode/tests/DatePicker.spec.ts +495 -4
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +47 -66
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +206 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/bridge-integration.regression.spec.ts +210 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/calendar-navigation.regression.spec.ts +214 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/validation-cross.regression.spec.ts +194 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/validation-success-messages.regression.spec.ts +83 -0
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +129 -54
- package/src/components/DatePicker/DateTextInput/tests/DateTextInput.spec.ts +320 -0
- package/src/components/DatePicker/composables/index.ts +1 -0
- package/src/components/DatePicker/composables/tests/useCalendarKeyboardNavigation.spec.ts +360 -0
- package/src/components/DatePicker/composables/tests/useDatePickerValidationBridge.spec.ts +129 -0
- package/src/components/DatePicker/composables/useDatePickerValidationBridge.ts +205 -0
- package/src/components/DatePicker/docExamples/BidirectionalComplexValidation.vue +1 -1
- package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +1 -1
- package/src/components/DatePicker/tests/exposed-methods.coverage.spec.ts +75 -0
- package/src/components/DialogBox/DialogBox.vue +1 -1
- package/src/components/FileList/UploadItem/UploadItem.vue +4 -4
- package/src/components/FileUpload/FileUpload.vue +2 -2
- package/src/components/FileUpload/FileUploadContent.vue +1 -1
- package/src/components/FilterInline/FilterInline.mdx +2 -2
- package/src/components/FilterSideBar/FilterSideBar.stories.ts +1 -1
- package/src/components/FilterSideBar/FilterSideBar.vue +2 -2
- package/src/components/FooterBar/FooterBar.vue +7 -7
- package/src/components/FranceConnectBtn/FranceConnectBtn.vue +1 -1
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +2 -2
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +7 -7
- package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +2 -2
- package/src/components/HeaderLoading/tests/HeaderLoading.spec.ts +87 -8
- package/src/components/HeaderNavigationBar/HorizontalNavbar/HorizontalNavbar.vue +3 -3
- package/src/components/HeaderNavigationBar/HorizontalNavbar/tests/HorizontalNavbar.spec.ts +589 -0
- package/src/components/HeaderToolbar/tests/HeaderToolBar.spec.ts +153 -1
- package/src/components/HeaderToolbar/tests/useMobileRightMenu.spec.ts +258 -0
- package/src/components/LogoBrandSection/tests/LogoBrandSection.spec.ts +2 -2
- package/src/components/LogoBrandSection/tests/__snapshots__/LogoBrandSection.spec.ts.snap +1 -1
- package/src/components/LunarCalendar/tests/useLunarCalendarRules.spec.ts +184 -0
- package/src/components/MonthPicker/MonthPickerVisual/MonthSelector.vue +3 -3
- package/src/components/MonthPicker/MonthPickerVisual/VisualPickerFooter.vue +1 -1
- package/src/components/MonthPicker/MonthPickerVisual/VisualPickerHeader.vue +2 -2
- package/src/components/MonthPicker/MonthPickerVisual/YearSelector.vue +1 -1
- package/src/components/NirField/NirField.vue +3 -3
- package/src/components/NotificationBar/Notification/Notification.vue +12 -12
- package/src/components/NotificationBar/NotificationBar.stories.ts +8 -8
- package/src/components/PaginatedTable/Pagination.vue +2 -2
- package/src/components/PasswordField/PasswordField.vue +8 -8
- package/src/components/PasswordField/tests/PasswordField.spec.ts +3 -3
- package/src/components/RangeField/RangeSlider/RangeSlider.vue +2 -2
- package/src/components/RangeField/RangeSlider/Tooltip/Tooltip.vue +1 -1
- package/src/components/StatusPage/tests/StatusPage.spec.ts +149 -0
- package/src/components/SubHeader/SubHeader.vue +1 -1
- package/src/components/SyAlert/SyAlert.vue +23 -23
- package/src/components/SyTextArea/SyTextArea.stories.ts +177 -131
- package/src/components/SyTextArea/SyTextArea.vue +235 -83
- package/src/components/SyTextArea/composables/useSyTextAreaValidation.ts +81 -0
- package/src/components/SyTextArea/locales.ts +1 -0
- package/src/components/SyTextArea/tests/SyTextArea.spec.ts +449 -1
- package/src/components/SyTextArea/useDefaultValidationRules.ts +2 -7
- package/src/components/SyTextArea/validation/Validation.stories.ts +856 -0
- package/src/components/TableToolbar/TableToolbar.vue +6 -6
- package/src/components/TableToolbar/accessibilite/Accessibility.mdx +81 -7
- package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +163 -0
- package/src/components/Tables/SyServerTable/SyServerTable.vue +2 -1
- package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +67 -0
- package/src/components/Tables/SyTable/SyTable.stories.ts +94 -0
- package/src/components/Tables/SyTable/SyTable.vue +2 -1
- package/src/components/Tables/SyTable/tests/SyTable.spec.ts +64 -0
- package/src/components/Tables/common/TableHeader.vue +2 -2
- package/src/components/Tables/common/filters/logics/tests/NumberFilterLogic.spec.ts +176 -0
- package/src/components/Tables/common/filters/logics/tests/SelectFilterLogic.spec.ts +111 -0
- package/src/components/Tables/common/tableStyles.scss +6 -6
- package/src/components/Tables/common/types.ts +2 -0
- package/src/components/UploadWorkflow/tests/UploadWorkflow.spec.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/composables/date/tests/useDateFormatDayjs.spec.ts +31 -0
- package/src/composables/date/tests/useHolidayDay.spec.ts +109 -0
- package/src/composables/rules/tests/useFieldValidation.spec.ts +374 -0
- package/src/composables/tests/useError.spec.ts +30 -0
- package/src/composables/tests/useFormFieldErrorHandling.spec.ts +234 -0
- package/src/composables/unifyValidation/documentationValidationProps.ts +5 -5
- package/src/composables/unifyValidation/tests/documentationValidationProps.spec.ts +177 -0
- package/src/composables/unifyValidation/tests/useCustomValidation.spec.ts +30 -0
- package/src/composables/unifyValidation/tests/useValidation.spec.ts +6 -2
- package/src/composables/unifyValidation/useCustomValidation.ts +19 -9
- package/src/composables/unifyValidation/useValidation.ts +18 -21
- package/src/composables/useFilterable/useFilterable.spec.ts +42 -0
- package/src/composables/useFilterable/useFilterable.ts +11 -7
- package/src/composables/useFormFieldErrorHandling.ts +2 -2
- package/src/composantsVuetify/VBtn/VBtn.mdx +9 -39
- package/src/composantsVuetify/VBtn/v-btn.stories.ts +26 -86
- package/src/designTokens/tokens/amelipro/apContextual.ts +6 -0
- package/src/designTokens/tokens/amelipro/apDarkTheme.ts +2 -2
- package/src/designTokens/tokens/amelipro/apLightTheme.ts +72 -103
- package/src/designTokens/tokens/amelipro/apSemantic.ts +1 -1
- package/src/designTokens/tokens/baseContextualTokens.ts +1 -6
- package/src/designTokens/tokens/baseTokens.ts +232 -0
- package/src/designTokens/tokens/cnam/cnamContextual.ts +6 -0
- package/src/designTokens/tokens/cnam/cnamDarkTheme.ts +2 -2
- package/src/designTokens/tokens/cnam/cnamLightTheme.ts +76 -104
- package/src/designTokens/tokens/pa/paDarkTheme.ts +2 -2
- package/src/designTokens/tokens/pa/paLightTheme.ts +73 -99
- package/src/designTokens/tokens/pa/paSemantic.ts +2 -0
- package/src/designTokens/tokens/semanticTokens.ts +114 -0
- package/src/stories/Components/Components.stories.ts +7 -3
- package/src/stories/DesignTokens/ColorIntegrationExample.vue +2 -3
- package/src/stories/DesignTokens/Colors.mdx +6 -8
- package/src/stories/DesignTokens/colors.stories.ts +244 -1081
- package/src/utils/amelipro/toKebabCase/tests/toKebabCase.spec.ts +52 -0
- package/src/utils/formatNir/tests/formatNir.spec.ts +34 -0
- package/src/utils/tests/insertAt.spec.ts +44 -0
- package/dist/apLightTheme-DS0Uy44H.js +0 -954
- package/dist/components/RatingPicker/tests/RatingPicker.a11y.spect.d.ts +0 -1
- package/dist/main-BsJ9ec3i.js +0 -38954
- package/src/components/BackBtn/tests/__snapshots__/back-btn-custom-bg.snap.png +0 -0
- package/src/components/BackBtn/tests/__snapshots__/back-btn-dark-mode.snap.png +0 -0
- package/src/components/BackBtn/tests/__snapshots__/back-btn-default.snap.png +0 -0
- package/src/components/BackBtn/tests/__snapshots__/back-btn-no-icon.snap.png +0 -0
- package/src/components/DatePicker/CalendarMode/tests/DatePicker.events.spec.ts +0 -178
- package/src/components/DialogBox/tests/__snapshots__/dialog-box-custom-texts.snap.png +0 -0
- package/src/components/DialogBox/tests/__snapshots__/dialog-box-default.snap.png +0 -0
- package/src/components/DialogBox/tests/__snapshots__/dialog-box-no-actions.snap.png +0 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/header-burger-menu-generated-submenu-open.snap.png +0 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/header-burger-menu-generated.snap.png +0 -0
- package/src/components/HeaderBar/tests/__snapshots__/header-bar-custom-width.snap.png +0 -0
- package/src/components/HeaderBar/tests/__snapshots__/header-bar-default.snap.png +0 -0
- package/src/components/HeaderBar/tests/__snapshots__/header-bar-no-sticky.snap.png +0 -0
- package/src/components/HeaderBar/tests/__snapshots__/header-bar-with-prepend.snap.png +0 -0
- package/src/components/HeaderBar/tests/__snapshots__/header-bar-with-side.snap.png +0 -0
- package/src/components/HeaderBar/tests/__snapshots__/header-bar-with-subtitle.snap.png +0 -0
- package/src/components/Logo/tests/__snapshots__/logo-avatar.snap.png +0 -0
- package/src/components/Logo/tests/__snapshots__/logo-dark.snap.png +0 -0
- package/src/components/Logo/tests/__snapshots__/logo-default.snap.png +0 -0
- package/src/components/Logo/tests/__snapshots__/logo-no-organism.snap.png +0 -0
- package/src/components/Logo/tests/__snapshots__/logo-no-signature.snap.png +0 -0
- package/src/components/Logo/tests/__snapshots__/logo-risque-pro.snap.png +0 -0
- package/src/components/RangeField/tests/__snapshots__/range-field-custom-bg.snap.png +0 -0
- package/src/components/RangeField/tests/__snapshots__/range-field-custom-range.snap.png +0 -0
- package/src/components/RangeField/tests/__snapshots__/range-field-default.snap.png +0 -0
- package/src/components/RangeField/tests/__snapshots__/range-field-step.snap.png +0 -0
- package/src/components/RangeField/tests/__snapshots__/range-field-with-label.snap.png +0 -0
- package/src/components/SyAlert/tests/__snapshots__/sy-alert-closable.snap.png +0 -0
- package/src/components/SyAlert/tests/__snapshots__/sy-alert-error.snap.png +0 -0
- package/src/components/SyAlert/tests/__snapshots__/sy-alert-info.snap.png +0 -0
- package/src/components/SyAlert/tests/__snapshots__/sy-alert-success.snap.png +0 -0
- package/src/components/SyAlert/tests/__snapshots__/sy-alert-variant-outlined.snap.png +0 -0
- package/src/components/SyAlert/tests/__snapshots__/sy-alert-variant-tonal.snap.png +0 -0
- package/src/components/SyAlert/tests/__snapshots__/sy-alert-warning.snap.png +0 -0
- /package/src/components/RatingPicker/tests/{RatingPicker.a11y.spect.ts → RatingPicker.a11y.spec.ts} +0 -0
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
type ComponentPublicInstance,
|
|
4
4
|
computed,
|
|
5
|
-
watch,
|
|
6
|
-
onMounted,
|
|
7
|
-
onBeforeUnmount,
|
|
8
5
|
nextTick,
|
|
9
|
-
|
|
6
|
+
onBeforeUnmount,
|
|
7
|
+
onMounted,
|
|
8
|
+
ref,
|
|
10
9
|
type Ref,
|
|
10
|
+
watch,
|
|
11
11
|
} from 'vue'
|
|
12
12
|
import {
|
|
13
|
-
useDateInitialization,
|
|
14
13
|
type DateInput,
|
|
15
14
|
type DateModelValue,
|
|
15
|
+
useDateInitialization,
|
|
16
16
|
} from '@/composables/date/useDateInitializationDayjs'
|
|
17
17
|
import {
|
|
18
18
|
useAsteriskDisplay,
|
|
19
|
+
useCalendarKeyboardNavigation,
|
|
20
|
+
useDateFormatValidation,
|
|
19
21
|
useDatePickerFocusTrap,
|
|
20
22
|
useDatePickerState,
|
|
21
|
-
|
|
22
|
-
useDateValidation,
|
|
23
|
+
useDatePickerValidationBridge,
|
|
23
24
|
useDatePickerViewMode,
|
|
24
25
|
useDatePickerVisibility,
|
|
25
26
|
useDateRangeValidation,
|
|
26
27
|
useDateSelection,
|
|
27
28
|
useDisplayedDateString,
|
|
29
|
+
useHolidayHighlighting,
|
|
28
30
|
useInputBlurHandler,
|
|
29
31
|
useManualDateValidation,
|
|
30
32
|
useMonthButtonCustomization,
|
|
31
33
|
useTodayButton,
|
|
32
|
-
useHolidayHighlighting,
|
|
33
|
-
useCalendarKeyboardNavigation,
|
|
34
34
|
} from '../composables'
|
|
35
35
|
import dayjs from 'dayjs'
|
|
36
36
|
import SyTextField from '@/components/Customs/SyTextField/SyTextField.vue'
|
|
37
37
|
import DateTextInput from '../DateTextInput/DateTextInput.vue'
|
|
38
38
|
import { VDatePicker } from 'vuetify/components'
|
|
39
39
|
import { useInputHandler } from '../composables/useInputHandler'
|
|
40
|
-
import { useValidation } from '@/composables/validation/useValidation'
|
|
41
40
|
import { useValidatable } from '@/composables/validation/useValidatable'
|
|
42
41
|
import { useDateFormat } from '@/composables/date/useDateFormatDayjs'
|
|
43
42
|
import type { DateObjectValue } from '../types'
|
|
@@ -232,22 +231,6 @@
|
|
|
232
231
|
* Validation + messages
|
|
233
232
|
*/
|
|
234
233
|
const isDatePickerVisible = ref(false)
|
|
235
|
-
const validation = useValidation({
|
|
236
|
-
showSuccessMessages: props.showSuccessMessages,
|
|
237
|
-
fieldIdentifier: 'Date',
|
|
238
|
-
disableErrorHandling: props.disableErrorHandling,
|
|
239
|
-
})
|
|
240
|
-
const { errors, warnings, successes, validateField, clearValidation } = validation
|
|
241
|
-
const errorMessages = computed(() => errors.value)
|
|
242
|
-
const warningMessages = computed(() => warnings.value)
|
|
243
|
-
const successMessages = computed(() => successes.value)
|
|
244
|
-
|
|
245
|
-
const getMessageClasses = () => ({
|
|
246
|
-
'dp-width': true,
|
|
247
|
-
'v-messages__message--error': errorMessages.value.length > 0,
|
|
248
|
-
'v-messages__message--warning': warningMessages.value.length > 0 && errorMessages.value.length === 0,
|
|
249
|
-
'v-messages__message--success': successMessages.value.length > 0 && errorMessages.value.length === 0 && warningMessages.value.length === 0,
|
|
250
|
-
})
|
|
251
234
|
|
|
252
235
|
/**
|
|
253
236
|
* Selection state
|
|
@@ -275,22 +258,36 @@
|
|
|
275
258
|
disableErrorHandling: props.disableErrorHandling,
|
|
276
259
|
})
|
|
277
260
|
|
|
278
|
-
const {
|
|
261
|
+
const {
|
|
262
|
+
errors,
|
|
263
|
+
warnings,
|
|
264
|
+
successes,
|
|
265
|
+
validateField,
|
|
266
|
+
clearValidation,
|
|
267
|
+
validateDates,
|
|
268
|
+
} = useDatePickerValidationBridge({
|
|
269
|
+
showSuccessMessages: props.showSuccessMessages,
|
|
270
|
+
disableErrorHandling: props.disableErrorHandling,
|
|
279
271
|
noCalendar: props.noCalendar,
|
|
280
272
|
required: props.required,
|
|
281
273
|
displayRange: props.displayRange,
|
|
282
|
-
disableErrorHandling: props.disableErrorHandling,
|
|
283
274
|
customRules: computed(() => props.customRules),
|
|
284
275
|
customWarningRules: computed(() => props.customWarningRules),
|
|
285
276
|
selectedDates,
|
|
286
277
|
isUpdatingFromInternal,
|
|
287
278
|
currentRangeIsValid,
|
|
288
279
|
getRangeValidationError,
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
280
|
+
revalidateOnCustomRulesChange: true,
|
|
281
|
+
})
|
|
282
|
+
const errorMessages = computed(() => errors.value)
|
|
283
|
+
const warningMessages = computed(() => warnings.value)
|
|
284
|
+
const successMessages = computed(() => successes.value)
|
|
285
|
+
|
|
286
|
+
const getMessageClasses = () => ({
|
|
287
|
+
'dp-width': true,
|
|
288
|
+
'v-messages__message--error': errorMessages.value.length > 0,
|
|
289
|
+
'v-messages__message--warning': warningMessages.value.length > 0 && errorMessages.value.length === 0,
|
|
290
|
+
'v-messages__message--success': successMessages.value.length > 0 && errorMessages.value.length === 0 && warningMessages.value.length === 0,
|
|
294
291
|
})
|
|
295
292
|
|
|
296
293
|
const {
|
|
@@ -343,30 +340,12 @@
|
|
|
343
340
|
}
|
|
344
341
|
}
|
|
345
342
|
else {
|
|
346
|
-
|
|
347
|
-
selectedDates.value = dateObject
|
|
343
|
+
selectedDates.value = parseDate(value, returnFormat.value)
|
|
348
344
|
}
|
|
349
345
|
|
|
350
346
|
// 3) Re-emit upward
|
|
351
347
|
emit('date-selected', value)
|
|
352
348
|
}
|
|
353
|
-
// Watcher pour re-valider quand les customRules changent
|
|
354
|
-
watch(() => props.customRules, () => {
|
|
355
|
-
if (selectedDates.value !== null) {
|
|
356
|
-
// Retarder légèrement pour s'assurer que les computed sont mis à jour
|
|
357
|
-
setTimeout(async () => {
|
|
358
|
-
clearValidation()
|
|
359
|
-
const datesToValidate = Array.isArray(selectedDates.value) ? selectedDates.value : [selectedDates.value]
|
|
360
|
-
for (const date of datesToValidate) {
|
|
361
|
-
await Promise.resolve(validateField(
|
|
362
|
-
date,
|
|
363
|
-
props.customRules,
|
|
364
|
-
props.customWarningRules,
|
|
365
|
-
))
|
|
366
|
-
}
|
|
367
|
-
}, 5)
|
|
368
|
-
}
|
|
369
|
-
}, { deep: true })
|
|
370
349
|
// Range handling
|
|
371
350
|
const rangeBoundaryDates = ref<[Date | null, Date | null] | null>(null)
|
|
372
351
|
const dateSelectionResult = useDateSelection(parseDate, selectedDates, props.format, props.displayRange)
|
|
@@ -728,8 +707,7 @@
|
|
|
728
707
|
|
|
729
708
|
if (!charBeforeCursor || !/\d/.test(charBeforeCursor)) {
|
|
730
709
|
event.preventDefault()
|
|
731
|
-
|
|
732
|
-
displayFormattedDate.value = newValue
|
|
710
|
+
displayFormattedDate.value = input.value.substring(0, cursorPos - 2) + input.value.substring(cursorPos)
|
|
733
711
|
queueMicrotask(() => {
|
|
734
712
|
const newCursorPos = cursorPos - 2
|
|
735
713
|
input.setSelectionRange(newCursorPos, newCursorPos)
|
|
@@ -901,9 +879,9 @@
|
|
|
901
879
|
}
|
|
902
880
|
}
|
|
903
881
|
finally {
|
|
904
|
-
|
|
882
|
+
queueMicrotask(() => {
|
|
905
883
|
isUpdatingFromInternal.value = false
|
|
906
|
-
}
|
|
884
|
+
})
|
|
907
885
|
}
|
|
908
886
|
}
|
|
909
887
|
|
|
@@ -1073,6 +1051,7 @@
|
|
|
1073
1051
|
:title="props.title"
|
|
1074
1052
|
:hint="props.hint"
|
|
1075
1053
|
:persistent-hint="props.persistentHint"
|
|
1054
|
+
:skip-internal-validation="true"
|
|
1076
1055
|
@focus="emit('focus')"
|
|
1077
1056
|
@blur="emit('blur')"
|
|
1078
1057
|
/>
|
|
@@ -1106,6 +1085,7 @@
|
|
|
1106
1085
|
ref="dateCalendarTextInputRef"
|
|
1107
1086
|
:key="fieldKey"
|
|
1108
1087
|
:model-value="textInputValue"
|
|
1088
|
+
:skip-internal-validation="true"
|
|
1109
1089
|
:label="labelWithAsterisk"
|
|
1110
1090
|
:placeholder="props.placeholder"
|
|
1111
1091
|
:format="props.format"
|
|
@@ -1273,40 +1253,40 @@
|
|
|
1273
1253
|
.v-messages__message--success {
|
|
1274
1254
|
:deep(.v-input__control),
|
|
1275
1255
|
:deep(.v-messages__message) {
|
|
1276
|
-
color: rgb(var(--v-theme-
|
|
1256
|
+
color: rgb(var(--v-theme-success)) !important;
|
|
1277
1257
|
|
|
1278
1258
|
--v-medium-emphasis-opacity: 1;
|
|
1279
1259
|
}
|
|
1280
1260
|
|
|
1281
1261
|
.v-field--active & {
|
|
1282
|
-
color: rgb(var(--v-theme-
|
|
1262
|
+
color: rgb(var(--v-theme-success)) !important;
|
|
1283
1263
|
}
|
|
1284
1264
|
}
|
|
1285
1265
|
|
|
1286
1266
|
.v-messages__message--error {
|
|
1287
1267
|
:deep(.v-input__control),
|
|
1288
1268
|
:deep(.v-messages__message) {
|
|
1289
|
-
color: rgb(var(--v-theme-
|
|
1269
|
+
color: rgb(var(--v-theme-error)) !important;
|
|
1290
1270
|
}
|
|
1291
1271
|
|
|
1292
1272
|
.v-field--active & {
|
|
1293
|
-
color: rgb(var(--v-theme-
|
|
1273
|
+
color: rgb(var(--v-theme-error)) !important;
|
|
1294
1274
|
}
|
|
1295
1275
|
}
|
|
1296
1276
|
|
|
1297
1277
|
.v-messages__message--warning {
|
|
1298
1278
|
:deep(.v-input__control) {
|
|
1299
|
-
color: rgb(var(--v-theme-
|
|
1279
|
+
color: rgb(var(--v-theme-warning)) !important;
|
|
1300
1280
|
|
|
1301
1281
|
--v-medium-emphasis-opacity: 1;
|
|
1302
1282
|
}
|
|
1303
1283
|
|
|
1304
1284
|
:deep(.v-messages__message) {
|
|
1305
|
-
color: rgb(var(--v-theme-
|
|
1285
|
+
color: rgb(var(--v-theme-warning)) !important;
|
|
1306
1286
|
}
|
|
1307
1287
|
|
|
1308
1288
|
.v-field--active & {
|
|
1309
|
-
color: rgb(var(--v-theme-
|
|
1289
|
+
color: rgb(var(--v-theme-warning)) !important;
|
|
1310
1290
|
}
|
|
1311
1291
|
}
|
|
1312
1292
|
|
|
@@ -1342,7 +1322,8 @@
|
|
|
1342
1322
|
}
|
|
1343
1323
|
|
|
1344
1324
|
:deep(.v-date-picker-month__day .v-btn:hover) {
|
|
1345
|
-
background-color: rgb(var(--v-theme-
|
|
1325
|
+
// background-color: rgb(var(--v-theme-background));
|
|
1326
|
+
background: green !important;
|
|
1346
1327
|
}
|
|
1347
1328
|
|
|
1348
1329
|
:deep(.v-date-picker-month__day--selected, .v-date-picker-month__day--adjacent) {
|
|
@@ -1350,7 +1331,7 @@
|
|
|
1350
1331
|
}
|
|
1351
1332
|
|
|
1352
1333
|
:deep(.v-date-picker-month__day--selected .v-btn:hover) {
|
|
1353
|
-
background-color: rgb(var(--v-theme-
|
|
1334
|
+
background-color: rgb(var(--v-theme-primaryVariant)) !important;
|
|
1354
1335
|
}
|
|
1355
1336
|
|
|
1356
1337
|
:deep(.weekend .v-date-picker-month__day--week-end .v-btn) {
|
|
@@ -59,6 +59,24 @@ describe('ComplexDatePicker.clean', () => {
|
|
|
59
59
|
expect(wrapper.vm.currentMonthName).toBeTruthy()
|
|
60
60
|
})
|
|
61
61
|
|
|
62
|
+
it('preserves autoClamp in text input mode', async () => {
|
|
63
|
+
const wrapper = mountComponent({
|
|
64
|
+
label: 'Date Field',
|
|
65
|
+
format: 'DD/MM/YYYY',
|
|
66
|
+
autoClamp: true,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const input = wrapper.find('input')
|
|
70
|
+
await input.setValue('31/04/2025')
|
|
71
|
+
await input.trigger('blur')
|
|
72
|
+
await flushPromises()
|
|
73
|
+
|
|
74
|
+
expect(input.element.value).toBe('30/04/2025')
|
|
75
|
+
const emitted = wrapper.emitted('update:modelValue')
|
|
76
|
+
expect(emitted).toBeTruthy()
|
|
77
|
+
expect(emitted && emitted[emitted.length - 1]?.[0]).toBe('30/04/2025')
|
|
78
|
+
})
|
|
79
|
+
|
|
62
80
|
it('respects disabled and readonly props when opening the calendar', async () => {
|
|
63
81
|
const wrapper = mountComponent({
|
|
64
82
|
label: 'Date Field',
|
|
@@ -319,6 +337,29 @@ describe('ComplexDatePicker.clean', () => {
|
|
|
319
337
|
expect(wrapper.vm.errorMessages.length).toBeGreaterThan(0)
|
|
320
338
|
})
|
|
321
339
|
|
|
340
|
+
it('surfaces custom warning rules without blocking submit in calendar mode', async () => {
|
|
341
|
+
const wrapper = mountComponent({
|
|
342
|
+
label: 'Date Field',
|
|
343
|
+
format: 'DD/MM/YYYY',
|
|
344
|
+
customWarningRules: [
|
|
345
|
+
{
|
|
346
|
+
type: 'custom',
|
|
347
|
+
options: {
|
|
348
|
+
validate: () => false,
|
|
349
|
+
warningMessage: 'Warning de contrat ComplexDatePicker',
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
wrapper.vm.selectedDates = new Date(2025, 0, 1)
|
|
356
|
+
const result = await wrapper.vm.validateOnSubmit()
|
|
357
|
+
|
|
358
|
+
expect(result).toBe(true)
|
|
359
|
+
expect(wrapper.vm.errorMessages).toEqual([])
|
|
360
|
+
expect(wrapper.vm.warningMessages).toContain('Warning de contrat ComplexDatePicker')
|
|
361
|
+
})
|
|
362
|
+
|
|
322
363
|
it('validateDates flags an error when end date is before start date in range mode', async () => {
|
|
323
364
|
const wrapper = mountComponent({
|
|
324
365
|
label: 'Date Field',
|
|
@@ -379,4 +420,169 @@ describe('ComplexDatePicker.clean', () => {
|
|
|
379
420
|
expect(wrapper.vm.errorMessages.length).toBe(0)
|
|
380
421
|
expect(wrapper.vm.isDatePickerVisible).toBe(false)
|
|
381
422
|
})
|
|
423
|
+
|
|
424
|
+
it('handleDateSelected avec value null efface la sélection', async () => {
|
|
425
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY' })
|
|
426
|
+
wrapper.vm.selectedDates = new Date(2025, 0, 1)
|
|
427
|
+
await wrapper.vm.handleDateSelected(null)
|
|
428
|
+
await flushPromises()
|
|
429
|
+
expect(wrapper.vm.selectedDates).toBeNull()
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
it('handleDateSelected avec tableau range met à jour selectedDates', async () => {
|
|
433
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY', displayRange: true })
|
|
434
|
+
await wrapper.vm.handleDateSelected(['01/01/2025', '10/01/2025'])
|
|
435
|
+
await flushPromises()
|
|
436
|
+
expect(wrapper.vm.selectedDates).not.toBeNull()
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
it('watcher selectedDates null remet les dates à aujourd hui', async () => {
|
|
440
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY' })
|
|
441
|
+
wrapper.vm.selectedDates = new Date(2025, 0, 1)
|
|
442
|
+
await nextTick()
|
|
443
|
+
wrapper.vm.selectedDates = null
|
|
444
|
+
await flushPromises()
|
|
445
|
+
// currentYear doit être une année valide (reset vers today)
|
|
446
|
+
const year = Number(wrapper.vm.currentYear)
|
|
447
|
+
expect(year).toBeGreaterThanOrEqual(2025)
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
it('syncFromModelValue initialise depuis un array range', async () => {
|
|
451
|
+
const wrapper = mountComponent({
|
|
452
|
+
label: 'Test',
|
|
453
|
+
format: 'DD/MM/YYYY',
|
|
454
|
+
displayRange: true,
|
|
455
|
+
modelValue: ['01/01/2025', '10/01/2025'],
|
|
456
|
+
})
|
|
457
|
+
await flushPromises()
|
|
458
|
+
expect(wrapper.vm.selectedDates).not.toBeNull()
|
|
459
|
+
expect(wrapper.vm.displayFormattedDate).toContain('01/01/2025')
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
it('syncFromModelValue initialise depuis une string', async () => {
|
|
463
|
+
const wrapper = mountComponent({
|
|
464
|
+
label: 'Test',
|
|
465
|
+
format: 'DD/MM/YYYY',
|
|
466
|
+
modelValue: '15/06/2025',
|
|
467
|
+
})
|
|
468
|
+
await flushPromises()
|
|
469
|
+
expect(wrapper.vm.displayFormattedDate).toBe('15/06/2025')
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
it('reset avec disabled incrémente fieldKey', async () => {
|
|
473
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY', disabled: true })
|
|
474
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
475
|
+
const before = (wrapper.vm as any).fieldKey
|
|
476
|
+
wrapper.vm.reset()
|
|
477
|
+
await flushPromises()
|
|
478
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
479
|
+
expect((wrapper.vm as any).fieldKey).toBe(before + 1)
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
it('navigation année : bridge Dec→Jan quand currentMonth=11 et année monte', async () => {
|
|
483
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY' })
|
|
484
|
+
wrapper.vm.isDatePickerVisible = true
|
|
485
|
+
// Simuler mois=11 (décembre) et année qui monte
|
|
486
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
487
|
+
;(wrapper.vm as any).currentMonth = '11'
|
|
488
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
489
|
+
;(wrapper.vm as any).currentYear = '2024'
|
|
490
|
+
await nextTick()
|
|
491
|
+
// Émettre update:year avec une année supérieure
|
|
492
|
+
const dp = wrapper.findComponent({ name: 'VDatePicker' })
|
|
493
|
+
if (dp.exists()) {
|
|
494
|
+
await dp.vm.$emit('update:year', '2025')
|
|
495
|
+
await nextTick()
|
|
496
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
497
|
+
expect((wrapper.vm as any).currentMonth).toBe('0')
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
// VDatePicker non rendu sans le calendrier ouvert – appel direct
|
|
501
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
502
|
+
;(wrapper.vm as any).handleYearUpdate?.()
|
|
503
|
+
}
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
const makeKeydownEvent = (key: string, inputProps: Partial<HTMLInputElement> = {}) => {
|
|
507
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
508
|
+
const fakeInput = Object.assign(document.createElement('input'), inputProps) as any
|
|
509
|
+
fakeInput.setSelectionRange = () => {}
|
|
510
|
+
const event = new KeyboardEvent('keydown', { key, bubbles: true })
|
|
511
|
+
Object.defineProperty(event, 'target', { value: fakeInput, writable: false })
|
|
512
|
+
return event
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
it('handleKeydown Backspace sur séparateur supprime le séparateur', async () => {
|
|
516
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY' })
|
|
517
|
+
const event = makeKeydownEvent('Backspace', { value: '01/', selectionStart: 3, selectionEnd: 3 })
|
|
518
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
519
|
+
;(wrapper.vm as any).handleKeydown(event)
|
|
520
|
+
await nextTick()
|
|
521
|
+
expect(wrapper.exists()).toBe(true)
|
|
522
|
+
})
|
|
523
|
+
|
|
524
|
+
it('handleKeydown ArrowLeft saute le séparateur', async () => {
|
|
525
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY' })
|
|
526
|
+
const event = makeKeydownEvent('ArrowLeft', { value: '01/01/2025', selectionStart: 3, selectionEnd: 3 })
|
|
527
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
528
|
+
;(wrapper.vm as any).handleKeydown(event)
|
|
529
|
+
await nextTick()
|
|
530
|
+
expect(wrapper.exists()).toBe(true)
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
it('handleKeydown ArrowRight saute le séparateur', async () => {
|
|
534
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY' })
|
|
535
|
+
const event = makeKeydownEvent('ArrowRight', { value: '01/01/2025', selectionStart: 2, selectionEnd: 2 })
|
|
536
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
537
|
+
;(wrapper.vm as any).handleKeydown(event)
|
|
538
|
+
await nextTick()
|
|
539
|
+
expect(wrapper.exists()).toBe(true)
|
|
540
|
+
})
|
|
541
|
+
|
|
542
|
+
it('handleDateTextInputUpdate en mode noCalendar met à jour le modèle depuis une string', async () => {
|
|
543
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY', noCalendar: true })
|
|
544
|
+
const input = wrapper.find('input')
|
|
545
|
+
await input.setValue('15/06/2025')
|
|
546
|
+
await input.trigger('blur')
|
|
547
|
+
await flushPromises()
|
|
548
|
+
const emitted = wrapper.emitted('update:modelValue')
|
|
549
|
+
expect(emitted).toBeTruthy()
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
it('handleDateTextInputUpdate avec valeur null efface selectedDates via reset', async () => {
|
|
553
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY', noCalendar: true })
|
|
554
|
+
wrapper.vm.selectedDates = new Date(2025, 0, 1)
|
|
555
|
+
wrapper.vm.reset()
|
|
556
|
+
await flushPromises()
|
|
557
|
+
expect(wrapper.vm.selectedDates).toBeNull()
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
it('handleDateTextInputUpdate avec array range startDate only via noCalendar', async () => {
|
|
561
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY', noCalendar: true, displayRange: true })
|
|
562
|
+
const input = wrapper.find('input')
|
|
563
|
+
await input.setValue('01/01/2025 - ')
|
|
564
|
+
await input.trigger('blur')
|
|
565
|
+
await flushPromises()
|
|
566
|
+
expect(wrapper.exists()).toBe(true)
|
|
567
|
+
})
|
|
568
|
+
|
|
569
|
+
it('handleKeydown readonly ne fait rien', async () => {
|
|
570
|
+
const wrapper = mountComponent({ label: 'Test', format: 'DD/MM/YYYY', readonly: true })
|
|
571
|
+
const event = makeKeydownEvent('Backspace', { value: '01/01/2025', selectionStart: 3, selectionEnd: 3 })
|
|
572
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
573
|
+
;(wrapper.vm as any).handleKeydown(event)
|
|
574
|
+
await nextTick()
|
|
575
|
+
expect(wrapper.exists()).toBe(true)
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
it('keeps deprecated birthDate prop as an alias for birth date mode', () => {
|
|
579
|
+
const wrapper = mountComponent({
|
|
580
|
+
label: 'Date Field',
|
|
581
|
+
birthDate: true,
|
|
582
|
+
format: 'DD/MM/YYYY',
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
expect(wrapper.props('birthDate')).toBe(true)
|
|
586
|
+
expect(wrapper.vm.currentViewMode).toBe('year')
|
|
587
|
+
})
|
|
382
588
|
})
|
package/src/components/DatePicker/ComplexDatePicker/tests/bridge-integration.regression.spec.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { mount, flushPromises } from '@vue/test-utils'
|
|
2
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
3
|
+
import { nextTick } from 'vue'
|
|
4
|
+
import ComplexDatePicker from '../ComplexDatePicker.vue'
|
|
5
|
+
import DateTextInput from '../../DateTextInput/DateTextInput.vue'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Tests de régression pour l'intégration Bridge + validation
|
|
9
|
+
* Couvrent les cas critiques non testés précédemment
|
|
10
|
+
*/
|
|
11
|
+
describe('Bridge Integration Regression Tests', () => {
|
|
12
|
+
/**
|
|
13
|
+
* Test 1: Réactivité des customRules
|
|
14
|
+
* Bug potentiel : Si les règles ne sont pas réactives,
|
|
15
|
+
* la validation croisée (dateA -> dateB) ne fonctionne pas
|
|
16
|
+
*/
|
|
17
|
+
it('réagit aux changements de customRules dynamiques', async () => {
|
|
18
|
+
const wrapper = mount(ComplexDatePicker, {
|
|
19
|
+
props: {
|
|
20
|
+
modelValue: '',
|
|
21
|
+
label: 'Date',
|
|
22
|
+
format: 'DD/MM/YYYY',
|
|
23
|
+
// Première règle qui passe toujours
|
|
24
|
+
customRules: [{ type: 'custom', options: { validate: () => true, message: 'Erreur' } }],
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// Changer les règles via setProps (comme le ferait le parent)
|
|
29
|
+
await wrapper.setProps({
|
|
30
|
+
customRules: [{ type: 'custom', options: { validate: () => false, message: 'Nouvelle erreur' } }],
|
|
31
|
+
})
|
|
32
|
+
await nextTick()
|
|
33
|
+
|
|
34
|
+
// La nouvelle règle doit être prise en compte
|
|
35
|
+
const input = wrapper.find('input')
|
|
36
|
+
await input.setValue('15/05/2025')
|
|
37
|
+
await input.trigger('blur')
|
|
38
|
+
await flushPromises()
|
|
39
|
+
|
|
40
|
+
// Avec la nouvelle règle qui retourne false, on doit avoir une erreur
|
|
41
|
+
const errors = wrapper.findAll('.v-messages__message--error')
|
|
42
|
+
expect(errors.length).toBeGreaterThan(0)
|
|
43
|
+
|
|
44
|
+
wrapper.unmount()
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Test 2: Mode readonly - pas de validation active
|
|
49
|
+
* Bug potentiel : Validation qui s'exécute quand même en readonly
|
|
50
|
+
*/
|
|
51
|
+
it('ne valide pas quand readonly est true', async () => {
|
|
52
|
+
const validateSpy = vi.fn(() => true)
|
|
53
|
+
|
|
54
|
+
const wrapper = mount(DateTextInput, {
|
|
55
|
+
props: {
|
|
56
|
+
modelValue: '',
|
|
57
|
+
label: 'Date',
|
|
58
|
+
format: 'DD/MM/YYYY',
|
|
59
|
+
readonly: true,
|
|
60
|
+
showSuccessMessages: true,
|
|
61
|
+
customRules: [{ type: 'custom', options: { validate: validateSpy } }],
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// Attendre un tick pour s'assurer que la validation ne s'est pas déclenchée
|
|
66
|
+
await nextTick()
|
|
67
|
+
|
|
68
|
+
// La règle ne doit pas avoir été appelée
|
|
69
|
+
expect(validateSpy).not.toHaveBeenCalled()
|
|
70
|
+
|
|
71
|
+
wrapper.unmount()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Test 3: Coordonnation parent/enfant avec skipInternalValidation
|
|
76
|
+
* Bug potentiel : DateTextInput valide en parallèle du parent
|
|
77
|
+
*/
|
|
78
|
+
it('ComplexDatePicker contrôle la validation quand DateTextInput a skipInternalValidation', async () => {
|
|
79
|
+
const parentValidate = vi.fn(() => ({ hasError: false, hasWarning: false, hasSuccess: true, state: { errors: [], warnings: [], successes: ['OK'] } }))
|
|
80
|
+
|
|
81
|
+
// Ce test vérifie que le parent gère la validation, pas l'enfant
|
|
82
|
+
const wrapper = mount(ComplexDatePicker, {
|
|
83
|
+
props: {
|
|
84
|
+
modelValue: '',
|
|
85
|
+
label: 'Date parent',
|
|
86
|
+
format: 'DD/MM/YYYY',
|
|
87
|
+
showSuccessMessages: true,
|
|
88
|
+
customRules: [{ type: 'custom', options: { validate: parentValidate } }],
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const input = wrapper.find('input')
|
|
93
|
+
await input.setValue('20/06/2025')
|
|
94
|
+
await input.trigger('blur')
|
|
95
|
+
await flushPromises()
|
|
96
|
+
|
|
97
|
+
// Vérifier qu'on a un message de succès (du parent)
|
|
98
|
+
const successMessages = wrapper.findAll('.v-messages__message--success')
|
|
99
|
+
expect(successMessages.length).toBeLessThanOrEqual(1)
|
|
100
|
+
|
|
101
|
+
wrapper.unmount()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Test 4: Pas de double validation avec queueMicrotask
|
|
106
|
+
* Bug potentiel : queueMicrotask pourrait causer des validations en cascade
|
|
107
|
+
*/
|
|
108
|
+
it('ne déclenche pas de validation en cascade avec queueMicrotask', async () => {
|
|
109
|
+
let validationCount = 0
|
|
110
|
+
const validateRule = () => {
|
|
111
|
+
validationCount++
|
|
112
|
+
return true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const wrapper = mount(DateTextInput, {
|
|
116
|
+
props: {
|
|
117
|
+
modelValue: '',
|
|
118
|
+
label: 'Date',
|
|
119
|
+
format: 'DD/MM/YYYY',
|
|
120
|
+
customRules: [{ type: 'custom', options: { validate: validateRule } }],
|
|
121
|
+
showSuccessMessages: true,
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// Attendre que les microtasks soient traitées
|
|
126
|
+
await nextTick()
|
|
127
|
+
await new Promise(resolve => queueMicrotask(() => resolve(undefined)))
|
|
128
|
+
|
|
129
|
+
// La validation ne doit pas avoir été déclenchée automatiquement
|
|
130
|
+
// (seulement au blur ou changement de valeur)
|
|
131
|
+
expect(validationCount).toBe(0)
|
|
132
|
+
|
|
133
|
+
wrapper.unmount()
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Test 5: Clear reset correctement les messages
|
|
138
|
+
* Bug potentiel : Messages qui restent après clear
|
|
139
|
+
*/
|
|
140
|
+
it('reset les messages de validation après clear', async () => {
|
|
141
|
+
const wrapper = mount(DateTextInput, {
|
|
142
|
+
props: {
|
|
143
|
+
modelValue: '15/05/2025',
|
|
144
|
+
label: 'Date',
|
|
145
|
+
format: 'DD/MM/YYYY',
|
|
146
|
+
showSuccessMessages: true,
|
|
147
|
+
required: true,
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// D'abord s'assurer qu'on a un message de succès
|
|
152
|
+
await flushPromises()
|
|
153
|
+
|
|
154
|
+
// Puis clear
|
|
155
|
+
await wrapper.setProps({ modelValue: '' })
|
|
156
|
+
await flushPromises()
|
|
157
|
+
await nextTick()
|
|
158
|
+
|
|
159
|
+
// Plus de message de succès
|
|
160
|
+
const successMessages = wrapper.findAll('.v-messages__message--success')
|
|
161
|
+
expect(successMessages.length).toBe(0)
|
|
162
|
+
|
|
163
|
+
wrapper.unmount()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Test 6: useDatePickerValidationBridge expose les bonnes méthodes
|
|
168
|
+
* Bug potentiel : Methods exposées qui ne fonctionnent pas
|
|
169
|
+
*/
|
|
170
|
+
it('expose validateOnSubmit qui retourne un booléen', async () => {
|
|
171
|
+
const wrapper = mount(DateTextInput, {
|
|
172
|
+
props: {
|
|
173
|
+
modelValue: '',
|
|
174
|
+
label: 'Date',
|
|
175
|
+
format: 'DD/MM/YYYY',
|
|
176
|
+
required: true,
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// Appeler validateOnSubmit exposé
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Testing internal API
|
|
182
|
+
const result = await (wrapper.vm as any).validateOnSubmit?.()
|
|
183
|
+
|
|
184
|
+
// Doit retourner false car champ vide et required
|
|
185
|
+
expect(result).toBe(false)
|
|
186
|
+
|
|
187
|
+
wrapper.unmount()
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Test 7: Pas de fuite mémoire avec les watchers
|
|
192
|
+
* Bug potentiel : Watchers qui s'accumulent
|
|
193
|
+
*/
|
|
194
|
+
it('nettoie les watchers quand le composant est détruit', async () => {
|
|
195
|
+
const wrapper = mount(DateTextInput, {
|
|
196
|
+
props: {
|
|
197
|
+
modelValue: '',
|
|
198
|
+
label: 'Date',
|
|
199
|
+
format: 'DD/MM/YYYY',
|
|
200
|
+
},
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// Détruire le composant
|
|
204
|
+
wrapper.unmount()
|
|
205
|
+
|
|
206
|
+
// Aucune erreur ne doit être levée
|
|
207
|
+
// (les watchers sont nettoyés automatiquement par Vue)
|
|
208
|
+
expect(() => wrapper.vm).not.toThrow()
|
|
209
|
+
})
|
|
210
|
+
})
|