@cnamts/synapse 1.0.4 → 1.0.6
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/DateFilter-BlOpwEVq.js +98 -0
- package/dist/NumberFilter-BPUXE4wY.js +121 -0
- package/dist/PeriodFilter-B2yx329_.js +112 -0
- package/dist/SelectFilter-CedKn1oV.js +136 -0
- package/dist/TextFilter-DkhJjRtR.js +114 -0
- package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordion.d.ts +103 -0
- package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.d.ts +105 -0
- package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.d.ts +132 -0
- package/dist/components/Amelipro/AmeliproCaptcha/types.d.ts +5 -0
- package/dist/components/Amelipro/AmeliproCard/AmeliproCard.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.d.ts +126 -0
- package/dist/components/Amelipro/AmeliproCustomSelector/types.d.ts +6 -0
- package/dist/components/Amelipro/AmeliproIllustratedDataTile/AmeliproIllustratedDataTile.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproMultipleFoldingCard/AmeliproMultipleFoldingCard.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproTable/AmeliproTable.d.ts +190 -0
- package/dist/components/Amelipro/AmeliproTable/types.d.ts +34 -0
- package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproTileBtn/AmeliproTileBtn.d.ts +1 -1
- package/dist/components/Amelipro/types.d.ts +6 -0
- package/dist/components/CookieBanner/CookieBanner.d.ts +1 -1
- package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +11 -2
- package/dist/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.d.ts +6 -1
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +3 -1
- package/dist/components/DataList/DataList.d.ts +9 -0
- package/dist/components/DataListGroup/DataListGroup.d.ts +10 -1
- package/dist/components/DataListItem/DataListItem.d.ts +1 -1
- package/dist/components/DataListItem/config.d.ts +1 -1
- package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +18 -8
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +16 -6
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +6 -1
- package/dist/components/DatePicker/composables/useDateInputEditing.d.ts +17 -8
- package/dist/components/DatePicker/composables/useKeyboardEvents.d.ts +41 -0
- package/dist/components/DatePicker/composables/useManualDateValidation.d.ts +4 -9
- package/dist/components/DatePicker/utils/dateFormattingUtils.d.ts +72 -0
- package/dist/components/DatePicker/utils/validationUtils.d.ts +38 -0
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.d.ts +9 -3
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.d.ts +6 -1
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.d.ts +11 -1
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.d.ts +11 -1
- package/dist/components/HeaderBar/HeaderBurgerMenu/locals.d.ts +2 -0
- package/dist/components/HeaderBar/HeaderBurgerMenu/useMenuPosition.d.ts +4 -0
- package/dist/components/NirField/NirField.d.ts +14 -4
- package/dist/components/PeriodField/PeriodField.d.ts +24 -4
- package/dist/components/Tables/common/SyTablePagination.d.ts +10 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/usePagination.d.ts +16 -0
- package/dist/design-system-v3.js +165 -160
- package/dist/design-system-v3.umd.cjs +120 -138
- package/dist/directives/lockFocus.d.ts +17 -0
- package/dist/{main-BzyNNvHX.js → main-BXPFSAB4.js} +14664 -13282
- package/dist/style.css +1 -0
- package/package.json +5 -2
- package/src/assets/amelipro/apTheme.scss +149 -0
- package/src/assets/amelipro/apTokens.scss +0 -148
- package/src/assets/overrides/_btns.scss +15 -0
- package/src/assets/overrides/_container.scss +36 -0
- package/src/assets/overrides/_forms.scss +7 -0
- package/src/assets/{_spacers.scss → overrides/_spacers.scss} +0 -7
- package/src/assets/overrides/_tables.scss +18 -0
- package/src/assets/overrides/_tooltips.scss +10 -0
- package/src/assets/overrides/_typography.scss +196 -0
- package/src/assets/settings.scss +11 -51
- package/src/assets/themes.scss +10 -0
- package/src/assets/tokens.scss +9 -156
- package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +80 -40
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.mdx +15 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.stories.ts +83 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.vue +86 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.vue +242 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/__tests__/AmeliproAccordionTemplate.spec.ts +20 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/__tests__/__snapshots__/AmeliproAccordionTemplate.spec.ts.snap +124 -0
- package/src/components/Amelipro/AmeliproAccordion/__tests__/AmeliproAccordion.spec.ts +20 -0
- package/src/components/Amelipro/AmeliproAccordion/__tests__/__snapshots__/AmeliproAccordion.spec.ts.snap +124 -0
- package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.mdx +15 -0
- package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.stories.ts +87 -0
- package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.vue +233 -0
- package/src/components/Amelipro/AmeliproCaptcha/__tests__/AmeliproCaptcha.spec.ts +24 -0
- package/src/components/Amelipro/AmeliproCaptcha/__tests__/__snapshots__/AmeliproCaptcha.spec.ts.snap +384 -0
- package/src/components/Amelipro/AmeliproCaptcha/types.d.ts +5 -0
- package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.mdx +15 -0
- package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.stories.ts +143 -0
- package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.vue +351 -0
- package/src/components/Amelipro/AmeliproCustomSelector/__tests__/AmeliproCustomSelector.spec.ts +50 -0
- package/src/components/Amelipro/AmeliproCustomSelector/__tests__/__snapshots__/AmeliproCustomSelector.spec.ts.snap +186 -0
- package/src/components/Amelipro/AmeliproCustomSelector/types.d.ts +6 -0
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/tests/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/tests/__snapshots__/AmeliproHeaderBar.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproHeader/tests/__snapshots__/AmeliproHeader.spec.ts.snap +1 -708
- package/src/components/Amelipro/AmeliproMenu/tests/__snapshots__/AmeliproMenu.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproPageLayout/tests/__snapshots__/AmeliproPageLayout.spec.ts.snap +1 -708
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.mdx +22 -0
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.stories.ts +550 -0
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.vue +421 -0
- package/src/components/Amelipro/AmeliproTable/__tests__/AmeliproTable.spec.ts +72 -0
- package/src/components/Amelipro/AmeliproTable/__tests__/__snapshots__/AmeliproTable.spec.ts.snap +427 -0
- package/src/components/Amelipro/AmeliproTable/types.d.ts +34 -0
- package/src/components/Amelipro/ServiceMenu/ServiceMenu.vue +12 -1
- package/src/components/Amelipro/ServiceMenu/tests/__snapshots__/ServiceMenu.spec.ts.snap +0 -820
- package/src/components/Amelipro/types.ts +8 -0
- package/src/components/CollapsibleList/CollapsibleList.vue +0 -2
- package/src/components/CookieBanner/CookieBanner.vue +1 -3
- package/src/components/CopyBtn/CopyBtn.vue +9 -2
- package/src/components/CopyBtn/tests/CopyBtn.spec.ts +3 -1
- package/src/components/Customs/Selects/SySelect/Accessibilite.mdx +7 -0
- package/src/components/Customs/Selects/SySelect/Accessibilite.stories.ts +4 -1
- package/src/components/Customs/Selects/SySelect/SySelect.stories.ts +80 -0
- package/src/components/Customs/Selects/SySelect/SySelect.vue +280 -34
- package/src/components/Customs/Selects/SySelect/composables/tests/useSySelectKeyboard.spec.ts +14 -5
- package/src/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.ts +129 -12
- package/src/components/Customs/SyIcon/SyIcon.spec.ts +3 -0
- package/src/components/Customs/SyTextField/Accessibilite.stories.ts +3 -1
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +79 -6
- package/src/components/Customs/SyTextField/SyTextField.vue +218 -24
- package/src/components/DataList/Accessibilite.stories.ts +4 -0
- package/src/components/DataList/DataList.vue +19 -12
- package/src/components/DataListGroup/Accessibilite.stories.ts +4 -0
- package/src/components/DataListGroup/DataListGroup.vue +32 -15
- package/src/components/DataListItem/DataListItem.vue +14 -11
- package/src/components/DataListItem/config.ts +1 -1
- package/src/components/DataListItem/tests/DataListItem.spec.ts +2 -2
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +12 -7
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +174 -0
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +27 -5
- package/src/components/DatePicker/DatePickerValidationExample/DatePickerValidation.stories.ts +286 -0
- package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +1 -1
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +29 -31
- package/src/components/DatePicker/composables/tests/useManualDateValidation.spec.ts +11 -3
- package/src/components/DatePicker/composables/useDateInputEditing.ts +73 -209
- package/src/components/DatePicker/composables/useKeyboardEvents.ts +149 -0
- package/src/components/DatePicker/composables/useManualDateValidation.ts +27 -68
- package/src/components/DatePicker/utils/dateFormattingUtils.ts +228 -0
- package/src/components/DatePicker/utils/validationUtils.ts +90 -0
- package/src/components/DialogBox/Accessibilite.stories.ts +4 -0
- package/src/components/DialogBox/DialogBox.stories.ts +10 -10
- package/src/components/DialogBox/DialogBox.vue +83 -21
- package/src/components/DialogBox/tests/__snapshots__/DialogBox.spec.ts.snap +12 -6
- package/src/components/FileUpload/tests/FileUpload.spec.ts +3 -0
- package/src/components/FooterBar/FooterBar.vue +1 -0
- package/src/components/HeaderBar/Accessibilite.stories.ts +4 -0
- package/src/components/HeaderBar/HeaderBar.mdx +47 -22
- package/src/components/HeaderBar/HeaderBar.stories.ts +54 -13
- package/src/components/HeaderBar/HeaderBar.vue +2 -1
- package/src/components/HeaderBar/HeaderBurgerMenu/Accessibilite.stories.ts +4 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.stories.ts +160 -82
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.vue +41 -56
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +10 -3
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.vue +41 -18
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/tests/HeaderMenuSection.spec.ts +7 -2
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +36 -9
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +41 -9
- package/src/components/HeaderBar/HeaderBurgerMenu/locals.ts +2 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/tests/HeaderBurgerMenu.spec.ts +1 -1
- package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/HeaderBurgerMenu.spec.ts.snap +8 -3
- package/src/components/HeaderBar/HeaderBurgerMenu/useMenuPosition.ts +50 -0
- package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +5 -5
- package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +7 -4
- package/src/components/HeaderBar/locales.ts +1 -1
- package/src/components/HeaderBar/tests/__snapshots__/HeaderBar.spec.ts.snap +2 -1
- package/src/components/HeaderLoading/HeaderLoading.vue +0 -1
- package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.spec.ts +2 -0
- package/src/components/LangBtn/LangBtn.vue +0 -3
- package/src/components/LogoBrandSection/Accessibilite.stories.ts +4 -1
- package/src/components/LogoBrandSection/LogoBrandSection.stories.ts +2 -2
- package/src/components/LogoBrandSection/LogoBrandSection.vue +13 -8
- package/src/components/LogoBrandSection/locales.ts +1 -1
- package/src/components/LogoBrandSection/tests/LogoBrandSection.spec.ts +1 -1
- package/src/components/LogoBrandSection/tests/__snapshots__/LogoBrandSection.spec.ts.snap +6 -4
- package/src/components/NirField/NirField.vue +5 -5
- package/src/components/NirField/tests/NirField.spec.ts +78 -12
- package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +104 -6
- package/src/components/Tables/common/TableHeader.vue +10 -7
- package/src/components/Tables/common/tableAccessibilityUtils.ts +13 -2
- package/src/components/Tables/common/useTableAria.ts +17 -1
- package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +2 -1
- package/src/components/index.ts +4 -0
- package/src/composables/date/tests/useDatePickerAccessibility.spec.ts +34 -5
- package/src/composables/index.ts +3 -0
- package/src/composables/useFilterable/useFilterable.ts +13 -1
- package/src/composables/usePagination.ts +103 -0
- package/src/directives/lockFocus.ts +48 -0
- package/src/main.ts +1 -2
- package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +1 -8
- package/src/stories/Accessibilite/{Aculturation/AuditDesignSystem.mdx → AuditDesignSystem.mdx} +1 -1
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.mdx +102 -0
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.stories.ts +219 -0
- package/src/stories/Accessibilite/KitDePreAudit/Outils/{Tanaguru.mdx → Tanaguru/Utilisation.mdx} +1 -1
- package/src/stories/DesignTokens/ColorIntegrationExample.vue +43 -0
- package/src/stories/DesignTokens/Colors.mdx +2 -0
- package/src/stories/DesignTokens/colors.stories.ts +9 -0
- package/src/vuetifyConfig.ts +3 -3
- package/dist/DateFilter-yrwJv_2R.js +0 -95
- package/dist/NumberFilter-BQXtywZI.js +0 -117
- package/dist/PeriodFilter-BYXVSzr5.js +0 -108
- package/dist/SelectFilter-CJV_mlN3.js +0 -133
- package/dist/TextFilter-DN0ejYIs.js +0 -110
- package/dist/design-system-v3.css +0 -1
- package/dist/directives/letterSpacing.d.ts +0 -27
- package/src/assets/_fonts.scss +0 -6
- package/src/assets/_typography.scss +0 -157
- package/src/directives/letterSpacing.ts +0 -233
- /package/src/assets/{_elevations.scss → overrides/_elevations.scss} +0 -0
- /package/src/assets/{_radius.scss → overrides/_radius.scss} +0 -0
|
@@ -166,8 +166,8 @@ describe('useManualDateValidation', () => {
|
|
|
166
166
|
|
|
167
167
|
it('devrait appeler validateField avec les règles personnalisées', () => {
|
|
168
168
|
const date = new Date('2023-01-01')
|
|
169
|
-
const customRules = [{ type: 'custom', options: {} }]
|
|
170
|
-
const customWarningRules = [{ type: 'warning', options: {} }]
|
|
169
|
+
const customRules = [{ type: 'custom', options: { validate: () => true } }]
|
|
170
|
+
const customWarningRules = [{ type: 'warning', options: { validate: () => true } }]
|
|
171
171
|
|
|
172
172
|
mockIsDateComplete.mockReturnValue(true)
|
|
173
173
|
mockValidateDateFormat.mockReturnValue({ isValid: true, message: '' })
|
|
@@ -189,7 +189,15 @@ describe('useManualDateValidation', () => {
|
|
|
189
189
|
|
|
190
190
|
validateManualInput('01/01/2023')
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
// Vérifier que validateField a été appelé
|
|
193
|
+
expect(mockValidateField).toHaveBeenCalled()
|
|
194
|
+
// Vérifier que le premier argument est la date attendue
|
|
195
|
+
expect(mockValidateField.mock.calls[0][0]).toBe(date)
|
|
196
|
+
// Vérifier la structure des règles sans comparer les références de fonctions
|
|
197
|
+
expect(mockValidateField.mock.calls[0][1][0].type).toBe('custom')
|
|
198
|
+
expect(typeof mockValidateField.mock.calls[0][1][0].options.validate).toBe('function')
|
|
199
|
+
expect(mockValidateField.mock.calls[0][2][0].type).toBe('warning')
|
|
200
|
+
expect(typeof mockValidateField.mock.calls[0][2][0].options.validate).toBe('function')
|
|
193
201
|
})
|
|
194
202
|
|
|
195
203
|
it('devrait retourner le résultat de validateField', () => {
|
|
@@ -1,31 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
import { useKeyboardEvents } from './useKeyboardEvents'
|
|
2
|
+
import {
|
|
3
|
+
formatDateInput as formatDateInputUtil,
|
|
4
|
+
getDateDescription as getDateDescriptionUtil,
|
|
5
|
+
type FormatDateInputResult,
|
|
6
|
+
} from '../utils/dateFormattingUtils'
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
* Options pour le composable useDateInputEditing
|
|
5
10
|
*/
|
|
6
11
|
export interface DateInputEditingOptions {
|
|
7
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Format de date (ex: 'DD/MM/YYYY')
|
|
14
|
+
*/
|
|
8
15
|
format: string
|
|
9
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Fonction pour mettre à jour la valeur d'affichage
|
|
18
|
+
*/
|
|
10
19
|
updateDisplayValue: (value: string) => void
|
|
11
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Fonction pour mettre à jour l'attribut aria-label (pour l'accessibilité)
|
|
22
|
+
*/
|
|
12
23
|
updateAriaLabel?: (value: string) => void
|
|
13
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Caractère à utiliser pour les positions non remplies
|
|
26
|
+
*/
|
|
14
27
|
placeholderChar?: string
|
|
15
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Si true, utilise des caractères invisibles pour les lecteurs d'écran
|
|
30
|
+
*/
|
|
16
31
|
accessiblePlaceholders?: boolean
|
|
17
32
|
}
|
|
18
33
|
|
|
19
|
-
/**
|
|
20
|
-
* Résultat du formatage d'une date
|
|
21
|
-
*/
|
|
22
|
-
export interface FormatDateInputResult {
|
|
23
|
-
// Valeur formatée
|
|
24
|
-
formatted: string
|
|
25
|
-
// Position du curseur après formatage
|
|
26
|
-
cursorPos: number
|
|
27
|
-
}
|
|
28
|
-
|
|
29
34
|
/**
|
|
30
35
|
* Composable pour gérer l'édition manuelle des dates
|
|
31
36
|
* Ce composable fournit des fonctions pour formater les dates pendant la saisie
|
|
@@ -44,162 +49,63 @@ export const useDateInputEditing = (options: DateInputEditingOptions) => {
|
|
|
44
49
|
} = options
|
|
45
50
|
|
|
46
51
|
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* @param cursorPosition - Position actuelle du curseur
|
|
51
|
-
* @returns Objet contenant la chaîne formatée et la nouvelle position du curseur
|
|
52
|
-
*/
|
|
53
|
-
const formatDateInput = (input: string, cursorPosition?: number): FormatDateInputResult => {
|
|
54
|
-
// Nettoyer l'entrée pour ne garder que les chiffres
|
|
55
|
-
let cleanedInput = input.replace(/[^\d]/g, '')
|
|
56
|
-
|
|
57
|
-
// Déterminer le séparateur utilisé dans le format
|
|
58
|
-
const separator = format.match(/[^DMY]/)?.[0] || '/'
|
|
59
|
-
|
|
60
|
-
// Calculer la position du curseur dans l'entrée nettoyée (sans séparateurs)
|
|
61
|
-
const inputBeforeCursor = input.substring(0, cursorPosition || 0)
|
|
62
|
-
const digitsBeforeCursor = inputBeforeCursor.replace(/[^\d]/g, '').length
|
|
52
|
+
* Détermine le séparateur utilisé dans le format
|
|
53
|
+
*/
|
|
54
|
+
const separator = format.match(/[^DMY]/)?.[0] || '/'
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
digitGroups.push(currentGroup)
|
|
74
|
-
currentGroup = ''
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Ajouter le dernier groupe s'il existe
|
|
79
|
-
if (currentGroup) {
|
|
80
|
-
digitGroups.push(currentGroup)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Calculer le nombre total de chiffres attendus dans le format
|
|
84
|
-
const expectedDigits = format.replace(/[^DMY]/g, '').length
|
|
56
|
+
/**
|
|
57
|
+
* Wrapper pour formatDateInput avec les options prédéfinies
|
|
58
|
+
*/
|
|
59
|
+
const formatDateInput = (input: string, cursorPosition?: number): FormatDateInputResult => {
|
|
60
|
+
return formatDateInputUtil(input, format, {
|
|
61
|
+
cursorPosition,
|
|
62
|
+
placeholderChar,
|
|
63
|
+
})
|
|
64
|
+
}
|
|
85
65
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Gère la suppression des séparateurs
|
|
68
|
+
*/
|
|
69
|
+
const handleBackspace = (event: KeyboardEvent & { target: HTMLInputElement }): void => {
|
|
70
|
+
const input = event.target
|
|
71
|
+
if (!input.selectionStart || input.selectionStart !== input.selectionEnd) {
|
|
72
|
+
return
|
|
89
73
|
}
|
|
90
74
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
let digitIndex = 0
|
|
94
|
-
|
|
95
|
-
// Parcourir les groupes de chiffres pour construire la date formatée
|
|
96
|
-
for (let groupIndex = 0; groupIndex < digitGroups.length; groupIndex++) {
|
|
97
|
-
const group = digitGroups[groupIndex]
|
|
98
|
-
const groupLength = group.length
|
|
99
|
-
|
|
100
|
-
// Ajouter les chiffres pour ce groupe
|
|
101
|
-
for (let j = 0; j < groupLength; j++) {
|
|
102
|
-
if (digitIndex < cleanedInput.length) {
|
|
103
|
-
result += cleanedInput[digitIndex]
|
|
104
|
-
digitIndex++
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
// Utiliser le caractère de placeholder configuré pour les positions non remplies
|
|
108
|
-
result += placeholderChar
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Ajouter le séparateur après chaque groupe sauf le dernier
|
|
113
|
-
if (groupIndex < digitGroups.length - 1) {
|
|
114
|
-
result += separator
|
|
115
|
-
}
|
|
116
|
-
}
|
|
75
|
+
const cursorPos = input.selectionStart
|
|
76
|
+
const charBeforeCursor = input.value[cursorPos - 1]
|
|
117
77
|
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
78
|
+
// Si le caractère avant le curseur n'est pas un chiffre
|
|
79
|
+
if (!/\d/.test(charBeforeCursor)) {
|
|
80
|
+
event.preventDefault()
|
|
121
81
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
newCursorPos++
|
|
125
|
-
if (/\d/.test(result[i])) {
|
|
126
|
-
digitCount++
|
|
127
|
-
}
|
|
128
|
-
}
|
|
82
|
+
const newValue = input.value.substring(0, cursorPos - 2) + input.value.substring(cursorPos)
|
|
83
|
+
updateDisplayValue(newValue)
|
|
129
84
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
85
|
+
// Positionner le curseur après un court délai
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
const newCursorPos = cursorPos - 2
|
|
88
|
+
input.setSelectionRange(newCursorPos, newCursorPos)
|
|
89
|
+
}, 0)
|
|
133
90
|
}
|
|
134
91
|
}
|
|
135
92
|
|
|
136
93
|
/**
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
*/
|
|
141
|
-
const handleKeydown = (event: KeyboardEvent & { target: HTMLInputElement }): void => {
|
|
142
|
-
// Bloquer la saisie de caractères non numériques
|
|
143
|
-
// Autoriser uniquement : chiffres, touches de navigation, touches de modification et touches de contrôle
|
|
144
|
-
if (
|
|
145
|
-
// Si la touche n'est pas un chiffre
|
|
146
|
-
!/^\d$/.test(event.key)
|
|
147
|
-
// Et n'est pas une touche spéciale autorisée
|
|
148
|
-
&& ![
|
|
149
|
-
'Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown',
|
|
150
|
-
'Home', 'End', 'Tab', 'Escape', 'Enter',
|
|
151
|
-
'Control', 'Alt', 'Shift', 'Meta',
|
|
152
|
-
].includes(event.key)
|
|
153
|
-
// Et n'est pas une combinaison de touches (Ctrl+A, Ctrl+C, Ctrl+V, etc.)
|
|
154
|
-
&& !(event.ctrlKey || event.metaKey)
|
|
155
|
-
) {
|
|
156
|
-
// Empêcher la saisie de caractères non numériques
|
|
157
|
-
event.preventDefault()
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Gérer la suppression des séparateurs
|
|
94
|
+
* Gestionnaire d'événement keydown personnalisé
|
|
95
|
+
*/
|
|
96
|
+
const onSpecialKeyDown = (event: KeyboardEvent & { target: HTMLInputElement }): void => {
|
|
162
97
|
if (event.key === 'Backspace') {
|
|
163
|
-
|
|
164
|
-
if (!input.selectionStart || input.selectionStart !== input.selectionEnd) {
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const cursorPos = input.selectionStart
|
|
169
|
-
const charBeforeCursor = input.value[cursorPos - 1]
|
|
170
|
-
|
|
171
|
-
if (!/\d/.test(charBeforeCursor)) {
|
|
172
|
-
// Si le caractère avant le curseur n'est pas un chiffre, on le supprime aussi
|
|
173
|
-
// et on supprime le chiffre avant le séparateur
|
|
174
|
-
event.preventDefault() // Empêcher le comportement par défaut
|
|
175
|
-
|
|
176
|
-
const newValue = input.value.substring(0, cursorPos - 2)
|
|
177
|
-
+ input.value.substring(cursorPos)
|
|
178
|
-
|
|
179
|
-
// Mettre à jour la valeur
|
|
180
|
-
updateDisplayValue(newValue)
|
|
181
|
-
|
|
182
|
-
// Positionner le curseur après un court délai
|
|
183
|
-
setTimeout(() => {
|
|
184
|
-
const newCursorPos = cursorPos - 2
|
|
185
|
-
input.setSelectionRange(newCursorPos, newCursorPos)
|
|
186
|
-
}, 0)
|
|
187
|
-
}
|
|
98
|
+
handleBackspace(event)
|
|
188
99
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
|
100
|
+
else if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
|
101
|
+
// Handle arrow key navigation around separators
|
|
192
102
|
const input = event.target
|
|
193
103
|
const cursorPos = input.selectionStart || 0
|
|
194
104
|
|
|
195
|
-
// Déterminer le séparateur utilisé dans le format
|
|
196
|
-
const separator = format.match(/[^DMY]/)?.[0] || '/'
|
|
197
|
-
|
|
198
105
|
if (event.key === 'ArrowLeft' && cursorPos > 0) {
|
|
199
106
|
const charBeforeCursor = input.value[cursorPos - 1]
|
|
200
107
|
|
|
201
108
|
if (charBeforeCursor === separator) {
|
|
202
|
-
// Si on se déplace à gauche et qu'on rencontre un séparateur, sauter par-dessus
|
|
203
109
|
event.preventDefault()
|
|
204
110
|
input.setSelectionRange(cursorPos - 2, cursorPos - 2)
|
|
205
111
|
}
|
|
@@ -208,7 +114,6 @@ export const useDateInputEditing = (options: DateInputEditingOptions) => {
|
|
|
208
114
|
const charAtCursor = input.value[cursorPos]
|
|
209
115
|
|
|
210
116
|
if (charAtCursor === separator) {
|
|
211
|
-
// Si on se déplace à droite et qu'on rencontre un séparateur, sauter par-dessus
|
|
212
117
|
event.preventDefault()
|
|
213
118
|
input.setSelectionRange(cursorPos + 2, cursorPos + 2)
|
|
214
119
|
}
|
|
@@ -216,11 +121,16 @@ export const useDateInputEditing = (options: DateInputEditingOptions) => {
|
|
|
216
121
|
}
|
|
217
122
|
}
|
|
218
123
|
|
|
124
|
+
// Utiliser le composable commun pour la gestion des événements clavier
|
|
125
|
+
const keyboardEvents = useKeyboardEvents({
|
|
126
|
+
allowedCharacters: /^\d$/,
|
|
127
|
+
onKeyDown: onSpecialKeyDown,
|
|
128
|
+
separator,
|
|
129
|
+
})
|
|
130
|
+
|
|
219
131
|
/**
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
* @param event - Événement paste
|
|
223
|
-
*/
|
|
132
|
+
* Gère l'événement paste pour formater correctement les dates collées
|
|
133
|
+
*/
|
|
224
134
|
const handlePaste = (event: ClipboardEvent): void => {
|
|
225
135
|
if (!event.clipboardData) return
|
|
226
136
|
|
|
@@ -254,7 +164,7 @@ export const useDateInputEditing = (options: DateInputEditingOptions) => {
|
|
|
254
164
|
const accessibleValue = formatted.replace(new RegExp(placeholderChar, 'g'), ' ')
|
|
255
165
|
|
|
256
166
|
// Créer un message descriptif pour le lecteur d'écran
|
|
257
|
-
const dateDescription = getDateDescription(accessibleValue
|
|
167
|
+
const dateDescription = getDateDescription(accessibleValue)
|
|
258
168
|
updateAriaLabel(dateDescription)
|
|
259
169
|
}
|
|
260
170
|
|
|
@@ -265,61 +175,15 @@ export const useDateInputEditing = (options: DateInputEditingOptions) => {
|
|
|
265
175
|
}
|
|
266
176
|
|
|
267
177
|
/**
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
* @returns Une description de la date adaptée aux lecteurs d'écran
|
|
273
|
-
*/
|
|
274
|
-
const getDateDescription = (dateStr: string, format: string): string => {
|
|
275
|
-
// Si la chaîne est vide, retourner un message simple
|
|
276
|
-
if (!dateStr.trim()) {
|
|
277
|
-
return 'Aucune date saisie'
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Déterminer le séparateur utilisé dans le format
|
|
281
|
-
const separator = format.match(/[^DMY]/)?.[0] || '/'
|
|
282
|
-
|
|
283
|
-
// Extraire les parties de la date
|
|
284
|
-
const dateParts = dateStr.split(separator)
|
|
285
|
-
const formatParts = format.split(separator)
|
|
286
|
-
|
|
287
|
-
// Créer une description en fonction du format
|
|
288
|
-
let description = 'Date en cours de saisie: '
|
|
289
|
-
|
|
290
|
-
for (let i = 0; i < formatParts.length; i++) {
|
|
291
|
-
if (i >= dateParts.length) break
|
|
292
|
-
|
|
293
|
-
const part = dateParts[i].trim()
|
|
294
|
-
const formatPart = formatParts[i].charAt(0).toUpperCase()
|
|
295
|
-
|
|
296
|
-
// Ignorer les parties vides ou contenant uniquement des placeholders
|
|
297
|
-
if (!part || part.replace(new RegExp(placeholderChar, 'g'), '').length === 0) {
|
|
298
|
-
continue
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
switch (formatPart) {
|
|
302
|
-
case 'D':
|
|
303
|
-
description += `jour ${part}, `
|
|
304
|
-
break
|
|
305
|
-
case 'M':
|
|
306
|
-
description += `mois ${part}, `
|
|
307
|
-
break
|
|
308
|
-
case 'Y':
|
|
309
|
-
description += `année ${part}, `
|
|
310
|
-
break
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Supprimer la virgule finale si elle existe
|
|
315
|
-
return description.endsWith(', ')
|
|
316
|
-
? description.slice(0, -2)
|
|
317
|
-
: description
|
|
178
|
+
* Wrapper pour getDateDescription avec les options prédéfinies
|
|
179
|
+
*/
|
|
180
|
+
const getDateDescription = (dateStr: string): string => {
|
|
181
|
+
return getDateDescriptionUtil(dateStr, format, placeholderChar)
|
|
318
182
|
}
|
|
319
183
|
|
|
320
184
|
return {
|
|
321
185
|
formatDateInput,
|
|
322
|
-
handleKeydown,
|
|
186
|
+
handleKeydown: keyboardEvents.handleKeyDown,
|
|
323
187
|
handlePaste,
|
|
324
188
|
getDateDescription,
|
|
325
189
|
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable pour centraliser la gestion des événements clavier
|
|
3
|
+
* Utilisé dans les différents composants de saisie de date
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options pour la gestion des événements clavier
|
|
8
|
+
*/
|
|
9
|
+
export interface KeyboardEventsOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Expression régulière pour les caractères autorisés
|
|
12
|
+
* Par défaut, seuls les chiffres sont autorisés
|
|
13
|
+
*/
|
|
14
|
+
allowedCharacters?: RegExp
|
|
15
|
+
/**
|
|
16
|
+
* Fonction à appeler lors d'un appui sur une touche
|
|
17
|
+
* Appelée après la validation des caractères
|
|
18
|
+
*/
|
|
19
|
+
onKeyDown?: (event: KeyboardEvent & { target: HTMLInputElement }) => void
|
|
20
|
+
/**
|
|
21
|
+
* Séparateur utilisé dans le format de date
|
|
22
|
+
* Utilisé pour gérer les touches de navigation
|
|
23
|
+
*/
|
|
24
|
+
separator?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Composable pour gérer les événements clavier communs aux champs de date
|
|
29
|
+
*
|
|
30
|
+
* @param options - Options de configuration
|
|
31
|
+
* @returns Fonctions pour gérer les événements clavier
|
|
32
|
+
*/
|
|
33
|
+
export const useKeyboardEvents = (options: KeyboardEventsOptions = {}) => {
|
|
34
|
+
const {
|
|
35
|
+
allowedCharacters = /^\d$/,
|
|
36
|
+
onKeyDown,
|
|
37
|
+
separator = '/',
|
|
38
|
+
} = options
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Liste des touches spéciales toujours autorisées
|
|
42
|
+
*/
|
|
43
|
+
const SPECIAL_KEYS = [
|
|
44
|
+
'Backspace', 'Delete',
|
|
45
|
+
'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown',
|
|
46
|
+
'Home', 'End', 'Tab', 'Escape', 'Enter',
|
|
47
|
+
'Control', 'Alt', 'Shift', 'Meta',
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Traite les événements keydown en filtrant les caractères non autorisés
|
|
52
|
+
*/
|
|
53
|
+
const handleKeyDown = (event: KeyboardEvent & { target: HTMLInputElement }): void => {
|
|
54
|
+
// Autoriser uniquement : caractères autorisés, touches spéciales et combinaisons de touches
|
|
55
|
+
if (
|
|
56
|
+
!allowedCharacters.test(event.key)
|
|
57
|
+
&& !SPECIAL_KEYS.includes(event.key)
|
|
58
|
+
&& !(event.ctrlKey || event.metaKey)
|
|
59
|
+
) {
|
|
60
|
+
event.preventDefault()
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Appeler le gestionnaire personnalisé s'il existe
|
|
65
|
+
if (onKeyDown) {
|
|
66
|
+
onKeyDown(event)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Gère la navigation autour des séparateurs
|
|
72
|
+
* Évite que le curseur se positionne entre un chiffre et un séparateur
|
|
73
|
+
*/
|
|
74
|
+
const handleArrowKeys = (event: KeyboardEvent & { target: HTMLInputElement }): void => {
|
|
75
|
+
const input = event.target
|
|
76
|
+
const cursorPos = input.selectionStart || 0
|
|
77
|
+
|
|
78
|
+
if (event.key === 'ArrowLeft' && cursorPos > 0) {
|
|
79
|
+
const charBeforeCursor = input.value[cursorPos - 1]
|
|
80
|
+
|
|
81
|
+
if (charBeforeCursor === separator) {
|
|
82
|
+
event.preventDefault()
|
|
83
|
+
input.setSelectionRange(cursorPos - 2, cursorPos - 2)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (event.key === 'ArrowRight' && cursorPos < input.value.length) {
|
|
87
|
+
const charAtCursor = input.value[cursorPos]
|
|
88
|
+
|
|
89
|
+
if (charAtCursor === separator) {
|
|
90
|
+
event.preventDefault()
|
|
91
|
+
input.setSelectionRange(cursorPos + 2, cursorPos + 2)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Gère les événements paste pour filtrer les caractères non autorisés
|
|
98
|
+
*/
|
|
99
|
+
const handlePaste = (event: ClipboardEvent): void => {
|
|
100
|
+
if (!event.clipboardData) return
|
|
101
|
+
|
|
102
|
+
const pastedText = event.clipboardData.getData('text')
|
|
103
|
+
if (!pastedText) return
|
|
104
|
+
|
|
105
|
+
// Filtrer pour ne garder que les caractères autorisés
|
|
106
|
+
const filteredText = pastedText
|
|
107
|
+
.split('')
|
|
108
|
+
.filter(char => allowedCharacters.test(char))
|
|
109
|
+
.join('')
|
|
110
|
+
|
|
111
|
+
// Si le texte collé ne contient pas de caractères autorisés, annuler l'opération
|
|
112
|
+
if (filteredText.length === 0) {
|
|
113
|
+
event.preventDefault()
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Si le texte a été modifié (des caractères non autorisés ont été supprimés)
|
|
118
|
+
if (filteredText !== pastedText) {
|
|
119
|
+
event.preventDefault()
|
|
120
|
+
|
|
121
|
+
const input = event.target as HTMLInputElement
|
|
122
|
+
if (!input) return
|
|
123
|
+
|
|
124
|
+
const start = input.selectionStart || 0
|
|
125
|
+
const end = input.selectionEnd || 0
|
|
126
|
+
|
|
127
|
+
// Construire la nouvelle valeur
|
|
128
|
+
const newValue = input.value.substring(0, start) + filteredText + input.value.substring(end)
|
|
129
|
+
|
|
130
|
+
// Mettre à jour la valeur (via l'événement input)
|
|
131
|
+
const inputEvent = new InputEvent('input', { bubbles: true, cancelable: true, data: newValue })
|
|
132
|
+
Object.defineProperty(inputEvent, 'target', { value: input, enumerable: true })
|
|
133
|
+
input.value = newValue
|
|
134
|
+
input.dispatchEvent(inputEvent)
|
|
135
|
+
|
|
136
|
+
// Positionner le curseur après le texte collé
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
const newCursorPos = start + filteredText.length
|
|
139
|
+
input.setSelectionRange(newCursorPos, newCursorPos)
|
|
140
|
+
}, 0)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
handleKeyDown,
|
|
146
|
+
handleArrowKeys,
|
|
147
|
+
handlePaste,
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type Ref } from 'vue'
|
|
2
2
|
import { type ValidationResult } from '@/composables/validation/useValidation'
|
|
3
3
|
import { DATE_PICKER_MESSAGES } from '../constants/messages'
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
adaptCustomRules,
|
|
6
|
+
validateEmptyOrIncompleteDate,
|
|
7
|
+
type CustomRule,
|
|
8
|
+
} from '../utils/validationUtils'
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Composable pour la validation manuelle des dates saisies
|
|
@@ -15,10 +18,8 @@ export const useManualDateValidation = (options: {
|
|
|
15
18
|
format: string
|
|
16
19
|
required?: boolean
|
|
17
20
|
disableErrorHandling?: boolean
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Règles d'avertissement personnalisées
|
|
21
|
-
customWarningRules?: { type: string, options: any }[]
|
|
21
|
+
customRules?: CustomRule[]
|
|
22
|
+
customWarningRules?: CustomRule[]
|
|
22
23
|
|
|
23
24
|
// Références réactives
|
|
24
25
|
hasInteracted: Ref<boolean>
|
|
@@ -29,8 +30,7 @@ export const useManualDateValidation = (options: {
|
|
|
29
30
|
validateDateFormat: (dateStr: string) => { isValid: boolean, message: string }
|
|
30
31
|
isDateComplete: (value: string) => boolean
|
|
31
32
|
parseDate: (dateStr: string, format: string) => Date | null
|
|
32
|
-
|
|
33
|
-
validateField: (value: any, rules?: any[], warningRules?: any[]) => ValidationResult
|
|
33
|
+
validateField: (value: unknown, rules?: CustomRule[], warningRules?: CustomRule[]) => ValidationResult
|
|
34
34
|
}) => {
|
|
35
35
|
const {
|
|
36
36
|
format,
|
|
@@ -57,23 +57,22 @@ export const useManualDateValidation = (options: {
|
|
|
57
57
|
// Réinitialiser la validation
|
|
58
58
|
clearValidation()
|
|
59
59
|
|
|
60
|
-
// Vérifier
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
if (!
|
|
70
|
-
|
|
60
|
+
// Vérifier les cas de champ vide ou incomplet
|
|
61
|
+
const emptyCheck = validateEmptyOrIncompleteDate(
|
|
62
|
+
value,
|
|
63
|
+
required,
|
|
64
|
+
isDateComplete,
|
|
65
|
+
hasInteracted.value,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
// Gérer les erreurs pour champ vide requis
|
|
69
|
+
if (!emptyCheck.isValid && !disableErrorHandling && emptyCheck.errorMessage) {
|
|
70
|
+
errors.value.push(DATE_PICKER_MESSAGES.ERROR_REQUIRED)
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
//
|
|
74
|
-
if (!
|
|
75
|
-
|
|
76
|
-
return true
|
|
73
|
+
// Si on ne doit pas continuer la validation (champ vide/incomplet)
|
|
74
|
+
if (!emptyCheck.shouldContinue) {
|
|
75
|
+
return emptyCheck.isValid
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
// Valider le format de la date
|
|
@@ -97,52 +96,12 @@ export const useManualDateValidation = (options: {
|
|
|
97
96
|
|
|
98
97
|
// Valider les règles personnalisées
|
|
99
98
|
if (!disableErrorHandling) {
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// Pré-traitement des règles personnalisées pour éviter l'erreur "value.includes is not a function"
|
|
105
|
-
const safeCustomRules = customRules.map((rule) => {
|
|
106
|
-
if (rule.type === 'custom' && rule.options && rule.options.validate) {
|
|
107
|
-
// Créer une copie de la règle pour ne pas modifier l'original
|
|
108
|
-
const safeCopy = { ...rule }
|
|
109
|
-
const originalValidate = rule.options.validate
|
|
110
|
-
|
|
111
|
-
// Remplacer la fonction validate par une version sécurisée
|
|
112
|
-
safeCopy.options = { ...rule.options }
|
|
113
|
-
safeCopy.options.validate = (val: string | Date | null | undefined) => {
|
|
114
|
-
// Si la valeur est une Date mais que la fonction originale attend une chaîne
|
|
115
|
-
// (détecté par la présence de includes dans le code source)
|
|
116
|
-
if (val instanceof Date && originalValidate.toString().includes('.includes')) {
|
|
117
|
-
// Convertir la date en chaîne au format spécifié
|
|
118
|
-
return originalValidate(format ? formatDate(dayjs(val), format) : val.toISOString())
|
|
119
|
-
}
|
|
120
|
-
return originalValidate(val)
|
|
121
|
-
}
|
|
122
|
-
return safeCopy
|
|
123
|
-
}
|
|
124
|
-
return rule
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
// Faire de même pour les règles d'avertissement
|
|
128
|
-
const safeWarningRules = customWarningRules.map((rule) => {
|
|
129
|
-
if (rule.type === 'custom' && rule.options && rule.options.validate) {
|
|
130
|
-
const safeCopy = { ...rule }
|
|
131
|
-
const originalValidate = rule.options.validate
|
|
132
|
-
|
|
133
|
-
safeCopy.options = { ...rule.options }
|
|
134
|
-
safeCopy.options.validate = (val: string | Date | null | undefined) => {
|
|
135
|
-
if (val instanceof Date && originalValidate.toString().includes('.includes')) {
|
|
136
|
-
return originalValidate(format ? formatDate(dayjs(val), format) : val.toISOString())
|
|
137
|
-
}
|
|
138
|
-
return originalValidate(val)
|
|
139
|
-
}
|
|
140
|
-
return safeCopy
|
|
141
|
-
}
|
|
142
|
-
return rule
|
|
143
|
-
})
|
|
99
|
+
// Adapter les règles pour maintenir la compatibilité avec les tests existants
|
|
100
|
+
// en utilisant notre utilitaire pour éviter les erreurs de type
|
|
101
|
+
const safeCustomRules = adaptCustomRules(customRules, format)
|
|
102
|
+
const safeWarningRules = adaptCustomRules(customWarningRules, format)
|
|
144
103
|
|
|
145
|
-
// Appeler validateField
|
|
104
|
+
// Appeler validateField pour évaluer les règles
|
|
146
105
|
const result = validateField(
|
|
147
106
|
date,
|
|
148
107
|
safeCustomRules,
|