@cnamts/synapse 0.0.14-alpha → 0.0.16-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/components/CookiesSelection/CookiesSelection.d.ts +26 -26
  2. package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -2
  3. package/dist/components/Customs/SySelect/SySelect.d.ts +24 -12
  4. package/dist/components/Customs/SySelect/locales.d.ts +3 -0
  5. package/dist/components/Customs/SyTextField/SyTextField.d.ts +1393 -3
  6. package/dist/components/DatePicker/DatePicker.d.ts +3532 -22
  7. package/dist/components/DatePicker/DateTextInput.d.ts +1408 -11
  8. package/dist/components/DialogBox/config.d.ts +1 -1
  9. package/dist/components/DownloadBtn/DownloadBtn.d.ts +2 -0
  10. package/dist/components/LangBtn/LangBtn.d.ts +467 -1
  11. package/dist/components/LangBtn/config.d.ts +1 -3
  12. package/dist/components/NirField/NirField.d.ts +2805 -15
  13. package/dist/components/PasswordField/PasswordField.d.ts +2 -2
  14. package/dist/components/PeriodField/PeriodField.d.ts +7345 -325
  15. package/dist/components/PhoneField/PhoneField.d.ts +3 -3
  16. package/dist/components/SelectBtnField/SelectBtnField.d.ts +1 -1
  17. package/dist/components/SkipLink/SkipLink.d.ts +3 -2
  18. package/dist/components/SyAlert/SyAlert.d.ts +72 -1
  19. package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +26 -26
  20. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +2 -0
  21. package/dist/components/index.d.ts +2 -0
  22. package/dist/composables/date/useDateFormat.d.ts +2 -2
  23. package/dist/composables/date/useDateFormatDayjs.d.ts +23 -0
  24. package/dist/composables/date/useDateInitializationDayjs.d.ts +18 -0
  25. package/dist/design-system-v3.js +4314 -3987
  26. package/dist/design-system-v3.umd.cjs +1 -1
  27. package/dist/style.css +1 -1
  28. package/dist/vuetifyConfig.d.ts +1 -0
  29. package/package.json +1 -1
  30. package/src/components/BackBtn/Accessibilite.stories.ts +4 -0
  31. package/src/components/BackBtn/BackBtn.vue +2 -1
  32. package/src/components/BackToTopBtn/Accessibilite.stories.ts +4 -0
  33. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +78 -21
  34. package/src/components/BackToTopBtn/BackToTopBtn.vue +15 -0
  35. package/src/components/BackToTopBtn/config.ts +2 -2
  36. package/src/components/BackToTopBtn/tests/__snapshots__/BackToTopBtn.spec.ts.snap +4 -4
  37. package/src/components/CopyBtn/Accessibilite.stories.ts +4 -0
  38. package/src/components/Customs/SyBtnSelect/SyBtnSelect.stories.ts +2 -2
  39. package/src/components/Customs/SyBtnSelect/SyBtnSelect.vue +0 -1
  40. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +3 -3
  41. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +4 -4
  42. package/src/components/Customs/SySelect/SySelect.stories.ts +4 -0
  43. package/src/components/Customs/SySelect/SySelect.vue +75 -10
  44. package/src/components/Customs/SySelect/locales.ts +3 -0
  45. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +24 -2
  46. package/src/components/Customs/SyTextField/Accessibilite.stories.ts +7 -0
  47. package/src/components/Customs/SyTextField/SyTextField.stories.ts +14 -1
  48. package/src/components/Customs/SyTextField/SyTextField.vue +85 -20
  49. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +795 -0
  50. package/src/components/DatePicker/DatePicker.stories.ts +432 -1
  51. package/src/components/DatePicker/DatePicker.vue +143 -76
  52. package/src/components/DatePicker/DatePickerValidation.mdx +338 -0
  53. package/src/components/DatePicker/DatePickerValidation.stories.ts +30 -0
  54. package/src/components/DatePicker/DateTextInput.vue +87 -135
  55. package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +282 -0
  56. package/src/components/DatePicker/docExamples/DatePickerValidationExamples.vue +535 -0
  57. package/src/components/DatePicker/tests/DatePicker.spec.ts +33 -32
  58. package/src/components/DatePicker/tests/DateTextInput.spec.ts +83 -35
  59. package/src/components/DialogBox/DialogBox.stories.ts +5 -2
  60. package/src/components/DialogBox/DialogBox.vue +1 -1
  61. package/src/components/DialogBox/config.ts +1 -1
  62. package/src/components/DownloadBtn/Accessibilite.stories.ts +4 -0
  63. package/src/components/DownloadBtn/DownloadBtn.stories.ts +17 -8
  64. package/src/components/DownloadBtn/DownloadBtn.vue +13 -6
  65. package/src/components/DownloadBtn/tests/__snapshots__/DownloadBtn.spec.ts.snap +0 -2
  66. package/src/components/FranceConnectBtn/Accessibilite.stories.ts +4 -0
  67. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +3 -0
  68. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +3 -0
  69. package/src/components/HeaderBar/HeaderBurgerMenu/menu.scss +19 -0
  70. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +12 -2
  71. package/src/components/LangBtn/Accessibilite.stories.ts +4 -0
  72. package/src/components/LangBtn/LangBtn.stories.ts +1 -4
  73. package/src/components/LangBtn/LangBtn.vue +68 -9
  74. package/src/components/LangBtn/config.ts +0 -1
  75. package/src/components/LangBtn/tests/LangBtn.spec.ts +30 -2
  76. package/src/components/PageContainer/Accessibilite.stories.ts +36 -23
  77. package/src/components/PaginatedTable/PaginatedTable.stories.ts +144 -18
  78. package/src/components/PasswordField/PasswordField.stories.ts +6 -6
  79. package/src/components/PasswordField/PasswordField.vue +3 -3
  80. package/src/components/PeriodField/PeriodField.vue +4 -4
  81. package/src/components/PhoneField/PhoneField.stories.ts +216 -24
  82. package/src/components/PhoneField/PhoneField.vue +32 -2
  83. package/src/components/PhoneField/tests/PhoneField.spec.ts +161 -14
  84. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +2 -1
  85. package/src/components/RatingPicker/RatingPicker.stories.ts +1 -1
  86. package/src/components/SkipLink/Accessibilite.stories.ts +8 -0
  87. package/src/components/SkipLink/SkipLink.vue +11 -9
  88. package/src/components/SkipLink/tests/__snapshots__/skipLink.spec.ts.snap +7 -4
  89. package/src/components/SkipLink/tests/skipLink.spec.ts +120 -6
  90. package/src/components/SyAlert/Accessibilite.stories.ts +4 -0
  91. package/src/components/SyAlert/SyAlert.mdx +3 -7
  92. package/src/components/SyAlert/SyAlert.stories.ts +19 -12
  93. package/src/components/SyAlert/SyAlert.vue +88 -51
  94. package/src/components/SyAlert/tests/SyAlert.spec.ts +20 -2
  95. package/src/components/SyAlert/tests/__snapshots__/SyAlert.spec.ts.snap +83 -75
  96. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +56 -0
  97. package/src/components/UserMenuBtn/UserMenuBtn.vue +4 -2
  98. package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +41 -0
  99. package/src/components/index.ts +2 -0
  100. package/src/composables/date/useDateFormat.ts +17 -1
  101. package/src/composables/date/useDateFormatDayjs.ts +84 -0
  102. package/src/composables/date/useDateInitializationDayjs.ts +133 -0
  103. package/src/composables/rules/useFieldValidation.ts +26 -3
  104. package/src/stories/Accessibilite/Avancement/Avancement.mdx +12 -0
  105. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +134 -0
  106. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +1 -1
  107. package/src/stories/GuideDuDev/LesBreackingChanges.mdx +31 -2
  108. package/src/components/LangBtn/tests/Config.spec.ts +0 -24
@@ -1,12 +1,17 @@
1
1
  <script lang="ts" setup>
2
- import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
2
+ import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick, type ComponentPublicInstance } from 'vue'
3
3
  import SyTextField from '@/components/Customs/SyTextField/SyTextField.vue'
4
4
  import DateTextInput from './DateTextInput.vue'
5
5
  import { VDatePicker } from 'vuetify/components'
6
6
  import { useValidation } from '@/composables/validation/useValidation'
7
- import { useDateFormat } from '@/composables/date/useDateFormat'
8
- import { useDateInitialization, type DateValue, type DateInput } from '@/composables/date/useDateInitialization'
7
+ import { useDateFormat } from '@/composables/date/useDateFormatDayjs'
8
+ import { useDateInitialization, type DateValue, type DateInput } from '@/composables/date/useDateInitializationDayjs'
9
9
  import { useDatePickerAccessibility } from '@/composables/date/useDatePickerAccessibility'
10
+ import dayjs from 'dayjs'
11
+ import customParseFormat from 'dayjs/plugin/customParseFormat'
12
+
13
+ // Initialiser les plugins dayjs
14
+ dayjs.extend(customParseFormat)
10
15
 
11
16
  const { parseDate, formatDate } = useDateFormat()
12
17
  const { initializeSelectedDates } = useDateInitialization()
@@ -32,7 +37,7 @@
32
37
  noIcon?: boolean
33
38
  noCalendar?: boolean
34
39
  isOutlined?: boolean
35
- readOnly?: boolean
40
+ readonly?: boolean
36
41
  width?: string
37
42
  disableErrorHandling?: boolean
38
43
  showSuccessMessages?: boolean
@@ -55,7 +60,7 @@
55
60
  noIcon: false,
56
61
  noCalendar: false,
57
62
  isOutlined: true,
58
- readOnly: false,
63
+ readonly: false,
59
64
  width: '100%',
60
65
  disableErrorHandling: false,
61
66
  showSuccessMessages: true,
@@ -93,7 +98,7 @@
93
98
  // Variable pour éviter les mises à jour récursives
94
99
  const isUpdatingFromInternal = ref(false)
95
100
 
96
- // Déclaration de la fonction validateDates avant son utilisation
101
+ // Fonction pour valider les dates
97
102
  const validateDates = (forceValidation = false) => {
98
103
  if (props.noCalendar) {
99
104
  // En mode no-calendar, on délègue la validation au DateTextInput
@@ -320,6 +325,13 @@
320
325
  }
321
326
  })
322
327
 
328
+ // Fonction pour mettre à jour displayFormattedDate quand le VDatePicker change
329
+ const updateDisplayFormattedDate = () => {
330
+ if (displayFormattedDateComputed.value) {
331
+ displayFormattedDate.value = displayFormattedDateComputed.value
332
+ }
333
+ }
334
+
323
335
  const updateSelectedDates = (input: DateValue) => {
324
336
  if (Array.isArray(input)) {
325
337
  const dates = input
@@ -354,11 +366,7 @@
354
366
  }
355
367
 
356
368
  const todayInString = computed(() => {
357
- return (new Date().toLocaleDateString('fr-FR', {
358
- weekday: 'long',
359
- month: 'long',
360
- day: 'numeric',
361
- })).replace(/\b\w/g, l => l.toUpperCase())
369
+ return dayjs().locale('fr').format('dddd D MMMM').replace(/\b\w/g, l => l.toUpperCase())
362
370
  })
363
371
 
364
372
  onMounted(() => {
@@ -377,7 +385,9 @@
377
385
  document.removeEventListener('click', handleClickOutside)
378
386
  })
379
387
 
380
- const dateTextInputRef = ref()
388
+ const dateTextInputRef = ref<null | ComponentPublicInstance<typeof DateTextInput>>()
389
+ const dateCalendarTextInputRef = ref<null | ComponentPublicInstance<typeof SyTextField>>()
390
+ const datePickerRef = ref<null | ComponentPublicInstance<typeof VDatePicker>>()
381
391
 
382
392
  const validateOnSubmit = () => {
383
393
  if (props.noCalendar) {
@@ -389,19 +399,10 @@
389
399
  return errors.value.length === 0
390
400
  }
391
401
 
392
- const showDatePicker = () => {
393
- if (props.disabled || props.readOnly) return
394
-
395
- isDatePickerVisible.value = true
396
-
397
- // Mettre à jour l'accessibilité après l'ouverture du DatePicker
398
- nextTick(() => {
399
- updateAccessibility()
400
- })
401
- }
402
-
403
402
  const openDatePicker = () => {
404
- showDatePicker()
403
+ if (!isDatePickerVisible.value) {
404
+ toggleDatePicker()
405
+ }
405
406
  }
406
407
 
407
408
  type ViewMode = 'month' | 'year' | 'months' | undefined
@@ -409,6 +410,10 @@
409
410
  // Variable pour suivre le mode d'affichage actuel du DatePicker
410
411
  const currentViewMode = ref<ViewMode>(props.isBirthDate ? 'year' : 'month')
411
412
 
413
+ watch(() => props.isBirthDate, (newValue) => {
414
+ currentViewMode.value = newValue ? 'year' : 'month'
415
+ })
416
+
412
417
  // Fonction pour gérer le changement de mode d'affichage
413
418
  const handleViewModeUpdate = (newMode: ViewMode) => {
414
419
  currentViewMode.value = newMode
@@ -430,11 +435,38 @@
430
435
  }
431
436
  }
432
437
 
433
- watch(isDatePickerVisible, (isVisible) => {
438
+ const handleInputBlur = () => {
439
+ emit('blur')
440
+ validateDates(true)
441
+ }
442
+
443
+ watch(isDatePickerVisible, async (isVisible) => {
434
444
  if (!isVisible && props.isBirthDate) {
435
445
  // Réinitialiser le mode d'affichage au type birthdate
436
446
  currentViewMode.value = 'year'
437
447
  }
448
+
449
+ if (isVisible) {
450
+ // set the focus on the date picker
451
+ await nextTick()
452
+ const firstButton = datePickerRef.value?.$el.querySelector('button')
453
+ if (firstButton) {
454
+ firstButton.focus()
455
+ }
456
+ }
457
+ else {
458
+ // set the focus on the text input
459
+ // wait for VMenu to finish DOM updates & transition
460
+ setTimeout(() => {
461
+ requestAnimationFrame(() => {
462
+ const inputElement = dateCalendarTextInputRef.value?.$el?.querySelector('input')
463
+ if (inputElement) {
464
+ inputElement.focus()
465
+ isDatePickerVisible.value = false
466
+ }
467
+ })
468
+ }, 0)
469
+ }
438
470
  })
439
471
 
440
472
  const getIcon = () => {
@@ -502,6 +534,36 @@
502
534
  }
503
535
  }, { immediate: true })
504
536
 
537
+ const toggleDatePicker = () => {
538
+ if (props.disabled || props.readonly) return
539
+
540
+ isDatePickerVisible.value = !isDatePickerVisible.value
541
+
542
+ if (isDatePickerVisible.value) {
543
+ // Mettre à jour l'accessibilité après l'ouverture du DatePicker
544
+ nextTick(() => {
545
+ updateAccessibility()
546
+ })
547
+ }
548
+ else {
549
+ emit('closed')
550
+ validateDates()
551
+ }
552
+ }
553
+
554
+ const openDatePickerOnClick = () => {
555
+ openDatePicker()
556
+ }
557
+
558
+ const openDatePickerOnFocus = () => {
559
+ openDatePicker()
560
+ emit('focus')
561
+ }
562
+
563
+ const openDatePickerOnIconClick = () => {
564
+ toggleDatePicker()
565
+ }
566
+
505
567
  defineExpose({
506
568
  validateOnSubmit,
507
569
  isDatePickerVisible,
@@ -532,7 +594,7 @@
532
594
  :custom-rules="props.customRules"
533
595
  :custom-warning-rules="props.customWarningRules"
534
596
  :disabled="props.disabled"
535
- :read-only="props.readOnly"
597
+ :readonly="props.readonly"
536
598
  :is-outlined="props.isOutlined"
537
599
  :display-icon="props.displayIcon"
538
600
  :display-append-icon="props.displayAppendIcon"
@@ -547,32 +609,6 @@
547
609
  />
548
610
  </template>
549
611
  <template v-else>
550
- <SyTextField
551
- v-model="displayFormattedDate"
552
- :append-icon="displayIcon && displayAppendIcon ? 'calendar' : undefined"
553
- :append-inner-icon="getIcon()"
554
- :class="[getMessageClasses(), 'label-hidden-on-focus']"
555
- :error-messages="errorMessages"
556
- :warning-messages="warningMessages"
557
- :success-messages="props.showSuccessMessages ? successMessages : []"
558
- :disabled="props.disabled"
559
- :read-only="true"
560
- :label="props.placeholder"
561
- :no-icon="props.noIcon"
562
- :prepend-icon="displayIcon && !displayAppendIcon ? 'calendar' : undefined"
563
- :variant-style="props.isOutlined ? 'outlined' : 'underlined'"
564
- color="primary"
565
- :show-success-messages="props.showSuccessMessages"
566
- :bg-color="props.bgColor"
567
- is-clearable
568
- title="Date Picker"
569
- @focus="openDatePicker"
570
- @update:model-value="updateSelectedDates"
571
- @prepend-icon-click="openDatePicker"
572
- @append-icon-click="openDatePicker"
573
- />
574
- </template>
575
- <div>
576
612
  <VMenu
577
613
  v-if="!props.noCalendar"
578
614
  v-model="isDatePickerVisible"
@@ -586,32 +622,63 @@
586
622
  attach="body"
587
623
  :offset="[-20, 5]"
588
624
  >
589
- <transition name="fade">
590
- <VDatePicker
591
- v-if="isDatePickerVisible && !props.noCalendar"
592
- v-model="selectedDates"
625
+ <template #activator="{ props: menuProps }">
626
+ <SyTextField
627
+ v-bind="menuProps"
628
+ ref="dateCalendarTextInputRef"
629
+ v-model="displayFormattedDate"
630
+ :append-icon="displayIcon && displayAppendIcon ? 'calendar' : undefined"
631
+ :append-inner-icon="getIcon()"
632
+ :class="[getMessageClasses(), 'label-hidden-on-focus']"
633
+ :error-messages="errorMessages"
634
+ :warning-messages="warningMessages"
635
+ :success-messages="props.showSuccessMessages ? successMessages : []"
636
+ :disabled="props.disabled"
637
+ :disable-click-button="false"
638
+ :readonly="true"
639
+ :label="props.placeholder"
640
+ :no-icon="props.noIcon"
641
+ :prepend-icon="displayIcon && !displayAppendIcon ? 'calendar' : undefined"
642
+ :variant-style="props.isOutlined ? 'outlined' : 'underlined'"
593
643
  color="primary"
594
- :first-day-of-week="1"
595
- :multiple="props.displayRange ? 'range' : false"
596
- :show-adjacent-months="true"
597
- :show-week="props.showWeekNumber"
598
- :view-mode="currentViewMode"
599
- @update:view-mode="handleViewModeUpdate"
600
- @update:year="handleYearUpdate"
601
- @update:month="handleMonthUpdate"
602
- >
603
- <template #title>
604
- Sélectionnez une date
605
- </template>
606
- <template #header>
607
- <h3 class="mx-auto my-auto ml-5 mb-4">
608
- {{ todayInString }}
609
- </h3>
610
- </template>
611
- </VDatePicker>
612
- </transition>
644
+ :show-success-messages="props.showSuccessMessages"
645
+ :bg-color="props.bgColor"
646
+ is-clearable
647
+ title="Date Picker"
648
+ @click="openDatePickerOnClick"
649
+ @focus="openDatePickerOnFocus"
650
+ @blur="handleInputBlur"
651
+ @update:model-value="updateSelectedDates"
652
+ @prepend-icon-click="openDatePickerOnIconClick"
653
+ @append-icon-click="openDatePickerOnIconClick"
654
+ />
655
+ </template>
656
+ <VDatePicker
657
+ v-if="isDatePickerVisible && !props.noCalendar"
658
+ ref="datePickerRef"
659
+ v-model="selectedDates"
660
+ color="primary"
661
+ :first-day-of-week="1"
662
+ :multiple="props.displayRange ? 'range' : false"
663
+ :show-adjacent-months="true"
664
+ :show-week="props.showWeekNumber"
665
+ :view-mode="currentViewMode"
666
+ @update:view-mode="handleViewModeUpdate"
667
+ @update:year="handleYearUpdate"
668
+ @update:month="handleMonthUpdate"
669
+ @update:model-value="updateDisplayFormattedDate"
670
+ >
671
+ <template #title>
672
+ Sélectionnez une date
673
+ </template>
674
+ <template #header>
675
+ <h3 class="mx-auto my-auto ml-5 mb-4">
676
+ {{ todayInString }}
677
+ </h3>
678
+ </template>
679
+ </VDatePicker>
613
680
  </VMenu>
614
- </div>
681
+ </template>
615
682
  </div>
616
683
  </template>
617
684
 
@@ -0,0 +1,338 @@
1
+ import {Meta, Canvas, Controls, Source} from '@storybook/blocks';
2
+ import * as ValidationStories from './DatePickerValidation.stories.ts';
3
+
4
+ <Meta of={ValidationStories}/>
5
+
6
+ # Documentations des règles de validation du DatePicker
7
+
8
+ Le composant DatePicker prend en charge plusieurs types de règles de validation qui permettent de contrôler les dates saisies par l'utilisateur. Cette documentation décrit toutes les règles disponibles et comment les utiliser.
9
+
10
+ > Pour en savoir plus sur le système global de gestion de validation, consultez la page <a href="/?path=/docs/guide-du-dev-utiliser-le-syst%C3%A8me-de-validation--docs">Utiliser le système de validation</a>.
11
+
12
+ ## Exemples de validation
13
+
14
+ ## Structure d'une règle de validation
15
+
16
+ Les règles de validation sont définies avec la structure suivante :
17
+
18
+ <Source
19
+ dark code={`
20
+ {
21
+ type: string, // Type de la règle (ex: 'notAfterToday')
22
+ options: {
23
+ message?: string, // Message d'erreur personnalisé
24
+ successMessage?: string, // Message de succès personnalisé
25
+ warningMessage?: string, // Message d'avertissement personnalisé
26
+ fieldIdentifier?: string, // Identifiant du champ pour les messages
27
+ // Autres options spécifiques au type de règle
28
+ }
29
+ }
30
+ `}/>
31
+
32
+ Ces règles peuvent être passées au DatePicker via les props `customRules` (pour les erreurs) ou `customWarningRules` (pour les avertissements).
33
+
34
+ ## Types de règles disponibles
35
+
36
+ ### 1. `required`
37
+
38
+ Vérifie que la date est renseignée.
39
+
40
+ <Source
41
+ dark code={`
42
+ <DatePicker
43
+ v-model="date"
44
+ :custom-rules="[{
45
+ type: 'required',
46
+ options: {
47
+ message: 'Vous devez sélectionner une date'
48
+ }
49
+ }]"
50
+ />
51
+ `}/>
52
+
53
+ ### 2. `notWeekend`
54
+
55
+ Vérifie que la date sélectionnée n'est pas un jour de weekend (samedi ou dimanche).
56
+
57
+ <Source
58
+ dark code={`
59
+ <DatePicker
60
+ v-model="date"
61
+ :custom-rules="[{
62
+ type: 'notWeekend',
63
+ options: {
64
+ message: 'La date ne peut pas être un weekend'
65
+ }
66
+ }]"
67
+ />
68
+ `}/>
69
+
70
+ ### 3. `notBeforeToday`
71
+
72
+ Vérifie que la date sélectionnée n'est pas antérieure à la date du jour.
73
+
74
+ <Source
75
+ dark code={`
76
+ <DatePicker
77
+ v-model="date"
78
+ :custom-rules="[{
79
+ type: 'notBeforeToday',
80
+ options: {
81
+ message: 'La date ne peut pas être antérieure à aujourd\'hui'
82
+ }
83
+ }]"
84
+ />
85
+ `}/>
86
+
87
+ ### 4. `notAfterToday`
88
+
89
+ Vérifie que la date sélectionnée n'est pas postérieure à la date du jour.
90
+
91
+ <Source
92
+ dark code={`
93
+ <DatePicker
94
+ v-model="date"
95
+ :custom-rules="[{
96
+ type: 'notAfterToday',
97
+ options: {
98
+ message: 'La date ne peut pas être postérieure à aujourd\'hui'
99
+ }
100
+ }]"
101
+ />
102
+ `}/>
103
+
104
+ ### 5. `notBeforeDate`
105
+
106
+ Vérifie que la date sélectionnée n'est pas antérieure à une date de référence.
107
+
108
+ <Source
109
+ dark code={`
110
+ <DatePicker
111
+ v-model="date"
112
+ :custom-rules="[{
113
+ type: 'notBeforeDate',
114
+ options: {
115
+ message: 'La date ne peut pas être antérieure au 01/01/2023',
116
+ date: '01/01/2023' // Date de référence au format DD/MM/YYYY
117
+ }
118
+ }]"
119
+ />
120
+ `}/>
121
+
122
+ ### 6. `notAfterDate`
123
+
124
+ Vérifie que la date sélectionnée n'est pas postérieure à une date de référence.
125
+
126
+ <Source
127
+ dark code={`
128
+ <DatePicker
129
+ v-model="date"
130
+ :custom-rules="[{
131
+ type: 'notAfterDate',
132
+ options: {
133
+ message: 'La date ne peut pas être postérieure au 31/12/2023',
134
+ date: '31/12/2023' // Date de référence au format DD/MM/YYYY
135
+ }
136
+ }]"
137
+ />
138
+ `}/>
139
+
140
+ ### 7. `dateExact`
141
+
142
+ Vérifie que la date sélectionnée est exactement égale à une date de référence.
143
+
144
+ <Source
145
+ dark code={`
146
+ <DatePicker
147
+ v-model="date"
148
+ :custom-rules="[{
149
+ type: 'dateExact',
150
+ options: {
151
+ message: 'La date doit être le 25/12/2023',
152
+ date: '25/12/2023' // Date de référence au format DD/MM/YYYY
153
+ }
154
+ }]"
155
+ />
156
+ `}/>
157
+
158
+ ### 8. `custom`
159
+
160
+ Permet de créer une règle de validation personnalisée avec une fonction de validation.
161
+
162
+ <Source
163
+ dark code={`
164
+ <DatePicker
165
+ v-model="date"
166
+ :custom-rules="[{
167
+ type: 'custom',
168
+ options: {
169
+ validate: (value) => {
170
+ // Si pas de valeur, c'est valide
171
+ if (!value) return true
172
+ // Convertir en chaîne si ce n'est pas déjà le cas
173
+ const dateStr = value.toString()
174
+ // Vérifier si c'est une Date et extraire l'année
175
+ if (value instanceof Date) {
176
+ return value.getFullYear() !== 2024
177
+ }
178
+ // Fallback sur la vérification de chaîne
179
+ return !dateStr.includes('2024')
180
+ },
181
+ message: 'Les dates en 2024 ne sont pas autorisées',
182
+ successMessage: 'Date valide (hors 2024)',
183
+ fieldIdentifier: 'date'
184
+ }
185
+ }]"
186
+ />
187
+ `}/>
188
+
189
+ La fonction `validate` reçoit la valeur de la date (au format spécifié par la prop `format`) et doit retourner :
190
+ - `true` si la validation réussit
191
+ - `false` ou une chaîne (message d'erreur personnalisé) si la validation échoue
192
+
193
+ ## Utilisation des règles d'avertissement
194
+
195
+ Toutes les règles ci-dessus peuvent également être utilisées comme règles d'avertissement avec la prop `customWarningRules`. Les avertissements n'empêchent pas la soumission du formulaire mais affichent un message en orange.
196
+
197
+ <Source
198
+ dark code={`
199
+ <DatePicker
200
+ v-model="date"
201
+ :custom-warning-rules="[{
202
+ type: 'notBeforeDate',
203
+ options: {
204
+ warningMessage: 'Attention : la date est antérieure à la date de référence',
205
+ date: '01/01/2024',
206
+ isWarning: true
207
+ }
208
+ }]"
209
+ />
210
+ `}/>
211
+
212
+ ## Combinaison de plusieurs règles
213
+
214
+ Vous pouvez combiner plusieurs règles de validation :
215
+
216
+ <Source
217
+ dark code={`
218
+ <DatePicker
219
+ v-model="date"
220
+ :custom-rules="[
221
+ {
222
+ type: 'required',
223
+ options: { message: 'La date est requise' }
224
+ },
225
+ {
226
+ type: 'notWeekend',
227
+ options: { message: 'La date ne peut pas être un weekend' }
228
+ },
229
+ {
230
+ type: 'notAfterToday',
231
+ options: { message: 'La date ne peut pas être dans le futur' }
232
+ }
233
+ ]"
234
+ />
235
+ `}/>
236
+
237
+ ## Messages de succès
238
+
239
+ Vous pouvez personnaliser les messages de succès qui s'affichent lorsque la validation réussit :
240
+
241
+ <Source
242
+ dark code={`
243
+ <DatePicker
244
+ v-model="date"
245
+ :custom-rules="[{
246
+ type: 'notWeekend',
247
+ options: {
248
+ message: 'La date ne peut pas être un weekend',
249
+ successMessage: 'La date sélectionnée est valide (jour de semaine)'
250
+ }
251
+ }]"
252
+ :show-success-messages="true"
253
+ />
254
+ `}/>
255
+
256
+ Pour afficher les messages de succès, la prop `showSuccessMessages` doit être définie à `true`.
257
+
258
+ ## Désactivation de la gestion des erreurs
259
+
260
+ Si vous souhaitez effectuer la validation sans afficher les messages d'erreur, vous pouvez utiliser la prop `disableErrorHandling` :
261
+
262
+ <Source
263
+ dark code={`
264
+ <DatePicker
265
+ v-model="date"
266
+ :custom-rules="[{ type: 'required' }]"
267
+ :disable-error-handling="true"
268
+ />
269
+ `}/>
270
+
271
+ Cette option est utile lorsque vous gérez la validation à un niveau supérieur, par exemple dans un formulaire parent.
272
+
273
+ ## Règles présentes par défaut
274
+
275
+ Le composant DatePicker intègre certaines règles de validation par défaut, sans que vous ayez besoin de les spécifier via `customRules` :
276
+
277
+ ### Validation du champ requis
278
+
279
+ Lorsque la prop `required` est définie à `true`, le DatePicker effectue automatiquement une validation pour s'assurer qu'une date est sélectionnée. Si aucune date n'est sélectionnée, le message d'erreur "La date est requise." est affiché.
280
+
281
+ <Source
282
+ dark code={`
283
+ <DatePicker
284
+ v-model="date"
285
+ required
286
+ />
287
+ `}/>
288
+
289
+ ### Validation du format de date
290
+
291
+ Le DatePicker vérifie automatiquement que la date saisie respecte le format spécifié par la prop `format` (par défaut `DD/MM/YYYY`). Cette validation est effectuée lorsque l'utilisateur saisit manuellement une date dans le champ de texte.
292
+
293
+ <Source
294
+ dark code={`
295
+ <DatePicker
296
+ v-model="date"
297
+ format="MM/DD/YYYY" <!-- Format personnalisé -->
298
+ />
299
+ `}/>
300
+
301
+ ### Validation de la plage de dates
302
+
303
+ Lorsque `displayRange` est à `true`, le DatePicker valide automatiquement que la plage de dates est cohérente (date de début antérieure à date de fin) lorsque deux dates sont sélectionnées.
304
+
305
+ <Source
306
+ dark code={`<DatePicker
307
+ v-model="dateRange"
308
+ display-range
309
+ />
310
+ `}/>
311
+
312
+ ## Interaction entre règles personnalisées et validations par défaut
313
+
314
+ Lorsque vous utilisez des règles personnalisées via `customRules` en combinaison avec des validations par défaut (comme `required`), il est important de comprendre comment ces règles interagissent :
315
+
316
+ ### Ordre de priorité des validations
317
+
318
+ 1. Les validations par défaut (comme `required`) sont exécutées en premier.
319
+ 2. Si les validations par défaut réussissent, les règles personnalisées sont ensuite appliquées.
320
+ 3. Les règles d'avertissement (`customWarningRules`) ne sont exécutées que si aucune erreur n'est détectée dans les étapes précédentes.
321
+
322
+ ### Exemple d'interaction
323
+
324
+ <Source
325
+ dark code={`<DatePicker
326
+ v-model="date"
327
+ required
328
+ :custom-rules="[{
329
+ type: 'notAfterToday',
330
+ options: { message: 'La date ne peut pas être après aujourd\'hui' }
331
+ }]"
332
+ />
333
+ `}/>
334
+
335
+ Dans cet exemple :
336
+ - Si aucune date n'est sélectionnée, la validation `required` échoue et le message "La date est requise." s'affiche.
337
+ - Si une date est sélectionnée mais qu'elle est postérieure à aujourd'hui, la règle personnalisée `notAfterToday` échoue et son message d'erreur s'affiche.
338
+ - Si une date est sélectionnée et qu'elle est antérieure ou égale à aujourd'hui, toutes les validations réussissent.
@@ -0,0 +1,30 @@
1
+ import { type Meta, type StoryFn } from '@storybook/vue3'
2
+ import DatePickerValidationExamples from './docExamples/DatePickerValidationExamples.vue'
3
+ import DatePickerBidirectionalValidation from './docExamples/DatePickerBidirectionalValidation.vue'
4
+
5
+ export default {
6
+ title: 'Composants/Formulaires/DatePicker/Validation',
7
+ component: DatePickerValidationExamples,
8
+ argTypes: {},
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component: 'Exemples de validation pour le composant DatePicker.',
13
+ },
14
+ },
15
+ },
16
+ } as Meta
17
+
18
+ export const ValidationExamples: StoryFn = () => ({
19
+ components: {
20
+ DatePickerValidationExamples,
21
+ },
22
+ template: '<DatePickerValidationExamples />',
23
+ })
24
+
25
+ export const BidirectionalValidation: StoryFn = () => ({
26
+ components: {
27
+ DatePickerBidirectionalValidation,
28
+ },
29
+ template: '<DatePickerBidirectionalValidation />',
30
+ })