@cnamts/synapse 1.0.25 → 1.0.26

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 (211) hide show
  1. package/dist/{AutocompleteFilter-D7qBuCAP.js → AutocompleteFilter-BPR-a55G.js} +1 -1
  2. package/dist/{DateFilter-BitMWrMU.js → DateFilter-CknrJWs2.js} +2 -2
  3. package/dist/{NumberFilter-BTLUxw0a.js → NumberFilter-DJ-yNlzv.js} +1 -1
  4. package/dist/{PeriodFilter-B5rUIPAC.js → PeriodFilter-CiB5Oa9Z.js} +1 -1
  5. package/dist/{SelectFilter-l4QnRcuk.js → SelectFilter-EiafX97M.js} +1 -1
  6. package/dist/{TextFilter-C9hj6Qrp.js → TextFilter-BzOmpdxj.js} +1 -1
  7. package/dist/{apLightTheme-DnIM24Lv.js → apLightTheme-DS0Uy44H.js} +20 -16
  8. package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +4 -2
  9. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +60 -289
  10. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +1 -0
  11. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +1 -0
  12. package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +1 -0
  13. package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -4
  14. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +50 -49
  15. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +29 -28
  16. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +8 -8
  17. package/dist/components/DatePicker/composables/useDatePickerState.d.ts +3 -3
  18. package/dist/components/DatePicker/composables/useDateTextField.d.ts +2 -2
  19. package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +2 -2
  20. package/dist/components/DatePicker/types.d.ts +1 -2
  21. package/dist/components/LunarCalendar/useLunarCalendarValidation.d.ts +1 -0
  22. package/dist/components/MonthPicker/MonthPicker.d.ts +1 -1
  23. package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +1 -1
  24. package/dist/components/NirField/NirField.d.ts +8 -4
  25. package/dist/components/NirField/useNirValidation.d.ts +6 -2
  26. package/dist/components/PeriodField/PeriodField.d.ts +102 -102
  27. package/dist/components/PhoneField/PhoneField.d.ts +11 -1
  28. package/dist/components/RangeField/RangeSlider/RangeSlider.d.ts +0 -3
  29. package/dist/components/RatingPicker/EmotionPicker/EmotionPicker.d.ts +3 -1
  30. package/dist/components/RatingPicker/NumberPicker/NumberPicker.d.ts +4 -3
  31. package/dist/components/RatingPicker/RatingPicker.d.ts +18 -5
  32. package/dist/components/RatingPicker/StarsPicker/StarsPicker.d.ts +3 -1
  33. package/dist/components/RatingPicker/tests/RatingPicker.a11y.spect.d.ts +1 -0
  34. package/dist/components/RatingPicker/useRatingFocus.d.ts +18 -0
  35. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +4 -4
  36. package/dist/components/Tables/SyTable/SyTable.d.ts +4 -4
  37. package/dist/components/Tables/common/SyTablePagination.d.ts +152 -364
  38. package/dist/components/Tables/common/TableHeader.d.ts +1 -1
  39. package/dist/components/Tables/common/filters/DateFilter.d.ts +4 -4
  40. package/dist/composables/date/useDateInitializationDayjs.d.ts +3 -1
  41. package/dist/composables/unifyValidation/useCustomValidation.d.ts +3 -1
  42. package/dist/composables/unifyValidation/useValidation.d.ts +12 -6
  43. package/dist/composables/unifyValidation/useVuetifyValidation.d.ts +1 -1
  44. package/dist/composables/validation/useValidation.d.ts +1 -0
  45. package/dist/design-system-v3.js +2 -2
  46. package/dist/designTokens/tokens/amelipro/apLightTheme.d.ts +2 -0
  47. package/dist/designTokens/tokens/cnam/cnamLightTheme.d.ts +2 -0
  48. package/dist/{main-Cpx8Co6H.js → main-BsJ9ec3i.js} +9103 -9018
  49. package/dist/synapse.css +1 -1
  50. package/dist/vuetifyConfig.js +1 -1
  51. package/package.json +8 -7
  52. package/src/assets/overrides/_icons.scss +0 -13
  53. package/src/assets/overrides/_otp.scss +0 -1
  54. package/src/components/Accordion/Accordion.vue +2 -0
  55. package/src/components/CookiesSelection/CookiesInformation/CookiesInformation.vue +2 -1
  56. package/src/components/CookiesSelection/CookiesSelection.vue +2 -1
  57. package/src/components/CopyBtn/CopyBtn.vue +9 -0
  58. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +1 -1
  59. package/src/components/Customs/Selects/SySelect/SySelect.stories.ts +413 -96
  60. package/src/components/Customs/Selects/SySelect/SySelect.vue +270 -225
  61. package/src/components/Customs/Selects/SySelect/tests/SySelect.spec.ts +245 -6
  62. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +3 -3
  63. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +23 -2
  64. package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +23 -5
  65. package/src/components/Customs/SyTabs/SyTabs.stories.ts +5 -5
  66. package/src/components/Customs/SyTabs/config.ts +3 -3
  67. package/src/components/Customs/SyTextField/SyTextField.vue +31 -4
  68. package/src/components/DatePicker/CalendarMode/DatePicker.stories.ts +1 -1
  69. package/src/components/DatePicker/CalendarMode/DatePicker.vue +17 -14
  70. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +1 -1
  71. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +8 -7
  72. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +1 -1
  73. package/src/components/DatePicker/DatePickerValidationExample/DatePickerValidation.stories.ts +1 -1
  74. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +57 -23
  75. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +1 -1
  76. package/src/components/DatePicker/composables/useDatePickerState.ts +33 -14
  77. package/src/components/DatePicker/composables/useDateRangeInput.ts +2 -1
  78. package/src/components/DatePicker/composables/useDateSelection.ts +2 -1
  79. package/src/components/DatePicker/composables/useDateTextField.ts +2 -2
  80. package/src/components/DatePicker/composables/useInputBlurHandler.ts +2 -2
  81. package/src/components/DatePicker/types.ts +1 -2
  82. package/src/components/DialogBox/DialogBox.stories.ts +8 -8
  83. package/src/components/DialogBox/accessibilite/Accessibility.mdx +86 -22
  84. package/src/components/FilterSideBar/FilterSideBar.vue +2 -1
  85. package/src/components/LangBtn/LangBtn.vue +2 -1
  86. package/src/components/NotificationBar/Notification/Notification.vue +2 -2
  87. package/src/components/PaginatedTable/PaginatedTable.vue +1 -1
  88. package/src/components/PaginatedTable/Pagination.vue +1 -1
  89. package/src/components/PasswordField/PasswordField.vue +7 -3
  90. package/src/components/PhoneField/PhoneField.vue +4 -2
  91. package/src/components/RangeField/RangeSlider/RangeSlider.vue +11 -18
  92. package/src/components/RatingPicker/EmotionPicker/EmotionPicker.vue +32 -48
  93. package/src/components/RatingPicker/EmotionPicker/tests/__snapshots__/EmotionPicker.spec.ts.snap +5 -0
  94. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +48 -53
  95. package/src/components/RatingPicker/NumberPicker/tests/NumberPicker.spec.ts +2 -1
  96. package/src/components/RatingPicker/NumberPicker/tests/__snapshots__/NumberPicker.spec.ts.snap +40 -13
  97. package/src/components/RatingPicker/RatingPicker.stories.ts +65 -88
  98. package/src/components/RatingPicker/RatingPicker.vue +71 -15
  99. package/src/components/RatingPicker/StarsPicker/StarsPicker.vue +28 -37
  100. package/src/components/RatingPicker/StarsPicker/tests/StarsPicker.spec.ts +1 -1
  101. package/src/components/RatingPicker/StarsPicker/tests/__snapshots__/StarsPicker.spec.ts.snap +5 -0
  102. package/src/components/RatingPicker/accessibilite/Accessibility.mdx +137 -9
  103. package/src/components/RatingPicker/tests/RatingPicker.a11y.spect.ts +123 -0
  104. package/src/components/RatingPicker/tests/RatingPicker.spec.ts +3 -2
  105. package/src/components/RatingPicker/tests/__snapshots__/RatingPicker.spec.ts.snap +40 -11
  106. package/src/components/RatingPicker/useRatingFocus.ts +97 -0
  107. package/src/components/SyTextArea/SyTextArea.vue +32 -1
  108. package/src/components/Tables/SyServerTable/SyServerTable.vue +1 -1
  109. package/src/components/Tables/SyTable/SyTable.vue +1 -1
  110. package/src/components/Tables/common/SyTableFilter.vue +4 -4
  111. package/src/components/Tables/common/SyTablePagination.vue +1 -0
  112. package/src/components/Tables/common/TableHeader.vue +1 -1
  113. package/src/components/Tables/common/filters/DateFilter.vue +2 -2
  114. package/src/composables/date/tests/useDateFormatDayjs.spec.ts +81 -0
  115. package/src/composables/date/tests/{useDateInitialization.spec.ts → useDateInitializationDayjs.spec.ts} +39 -3
  116. package/src/composables/date/useDateInitializationDayjs.ts +4 -1
  117. package/src/composables/unifyValidation/documentationValidationProps.ts +7 -7
  118. package/src/composables/unifyValidation/tests/useCustomValidation.spec.ts +2 -1
  119. package/src/composables/unifyValidation/tests/useValidation.spec.ts +22 -0
  120. package/src/composables/unifyValidation/useCustomValidation.ts +16 -4
  121. package/src/composables/unifyValidation/useValidation.ts +46 -15
  122. package/src/composables/unifyValidation/useVuetifyValidation.ts +2 -2
  123. package/src/composables/useFormFieldErrorHandling.ts +4 -1
  124. package/src/composables/validation/tests/useValidation.spec.ts +2 -2
  125. package/src/composables/validation/useValidation.ts +15 -3
  126. package/src/composantsVuetify/VCard/VCard.mdx +59 -0
  127. package/src/composantsVuetify/VCard/v-card.stories.ts +279 -0
  128. package/src/designTokens/tokens/amelipro/apColors2026.ts +1 -1
  129. package/src/designTokens/tokens/amelipro/apLightTheme.ts +3 -0
  130. package/src/designTokens/tokens/cnam/cnamLightTheme.ts +3 -0
  131. package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +61 -91
  132. package/src/stories/Accessibilite/AuditDesignSystem.mdx +5 -8
  133. package/src/stories/Accessibilite/AuditEtContreAudit/Exemptions-derogations.mdx +1 -1
  134. package/src/stories/Accessibilite/AuditEtContreAudit/Introduction.mdx +11 -8
  135. package/src/stories/Accessibilite/AuditEtContreAudit/RGAA.mdx +6 -7
  136. package/src/stories/Accessibilite/Introduction.mdx +30 -30
  137. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +168 -78
  138. package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +13 -6
  139. package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +66 -45
  140. package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +23 -49
  141. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.stories.ts +6 -0
  142. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/Utilisation.mdx +7 -19
  143. package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +18 -20
  144. package/src/stories/Components/Components.stories.ts +52 -3
  145. package/dist/AutocompleteFilter-Df9i5mAl.cjs +0 -1
  146. package/dist/DateFilter-BJD6FMev.cjs +0 -1
  147. package/dist/NumberFilter-DGCzCXzI.cjs +0 -1
  148. package/dist/PeriodFilter-DO_ecTZW.cjs +0 -1
  149. package/dist/SelectFilter-CGwcKWLm.cjs +0 -1
  150. package/dist/TextFilter-B8nf7xoK.cjs +0 -1
  151. package/dist/apLightTheme-CEK4iY3f.cjs +0 -1
  152. package/dist/composables/date/useDateFormat.d.ts +0 -26
  153. package/dist/composables/date/useDateInitialization.d.ts +0 -18
  154. package/dist/design-system-v3.umd.cjs +0 -1
  155. package/dist/main-ByDPHpae.cjs +0 -1067
  156. package/dist/tooth-11-D3sLWv2n.cjs +0 -1
  157. package/dist/tooth-12-CXrLuH03.cjs +0 -1
  158. package/dist/tooth-13-BSfo5fpT.cjs +0 -1
  159. package/dist/tooth-14-DMzulx0h.cjs +0 -1
  160. package/dist/tooth-15-BKRFVi-9.cjs +0 -1
  161. package/dist/tooth-16-CpuxAbuM.cjs +0 -1
  162. package/dist/tooth-17-BPoahUdg.cjs +0 -1
  163. package/dist/tooth-18-DhHJz8sy.cjs +0 -1
  164. package/dist/tooth-21-Dgd5hn_X.cjs +0 -1
  165. package/dist/tooth-22-C2Tn19sB.cjs +0 -1
  166. package/dist/tooth-23-C9uaaSGb.cjs +0 -1
  167. package/dist/tooth-24-BrK9UGpf.cjs +0 -1
  168. package/dist/tooth-25-CE_EfGNp.cjs +0 -1
  169. package/dist/tooth-26-Ctv4i9Fy.cjs +0 -1
  170. package/dist/tooth-27-C5J7JkWM.cjs +0 -1
  171. package/dist/tooth-28-Z9oWqjo0.cjs +0 -1
  172. package/dist/tooth-31-BrYqmkTi.cjs +0 -1
  173. package/dist/tooth-32-BNNR0oCZ.cjs +0 -1
  174. package/dist/tooth-33-DuxvqO2J.cjs +0 -1
  175. package/dist/tooth-34-BCSCXMB6.cjs +0 -1
  176. package/dist/tooth-35-BLUXkX88.cjs +0 -1
  177. package/dist/tooth-36-IrKHYqlA.cjs +0 -1
  178. package/dist/tooth-37-BYqpdMwo.cjs +0 -1
  179. package/dist/tooth-38-B_eNXXdu.cjs +0 -1
  180. package/dist/tooth-41-Ddva4Ot8.cjs +0 -1
  181. package/dist/tooth-42-szcDqlM0.cjs +0 -1
  182. package/dist/tooth-43-B3ka6rQm.cjs +0 -1
  183. package/dist/tooth-44-CazyQucj.cjs +0 -1
  184. package/dist/tooth-45-B4HQtc8n.cjs +0 -1
  185. package/dist/tooth-46-BPM40gbG.cjs +0 -1
  186. package/dist/tooth-47-Dvr20dlh.cjs +0 -1
  187. package/dist/tooth-48-Bd8ljGsF.cjs +0 -1
  188. package/dist/tooth-51-OBpwCOF3.cjs +0 -1
  189. package/dist/tooth-52-aKxyHcmq.cjs +0 -1
  190. package/dist/tooth-53-vCwJjTOc.cjs +0 -1
  191. package/dist/tooth-54-DsWu2iFy.cjs +0 -1
  192. package/dist/tooth-55-BxC1X2Dn.cjs +0 -1
  193. package/dist/tooth-61-BbLvxMQi.cjs +0 -1
  194. package/dist/tooth-62-CmTkWczP.cjs +0 -1
  195. package/dist/tooth-63-DI7l_2qI.cjs +0 -1
  196. package/dist/tooth-64-B21sOsJh.cjs +0 -1
  197. package/dist/tooth-65-D2ZC2VEr.cjs +0 -1
  198. package/dist/tooth-71-D473PPO5.cjs +0 -1
  199. package/dist/tooth-72-Drh1wnNu.cjs +0 -1
  200. package/dist/tooth-73-DzlwYI23.cjs +0 -1
  201. package/dist/tooth-74-8aGvcZPg.cjs +0 -1
  202. package/dist/tooth-75-BFK7At_r.cjs +0 -1
  203. package/dist/tooth-81-BZmR-I0M.cjs +0 -1
  204. package/dist/tooth-82-euVfUUZV.cjs +0 -1
  205. package/dist/tooth-83-KV010j64.cjs +0 -1
  206. package/dist/tooth-84-BBg1RjhZ.cjs +0 -1
  207. package/dist/tooth-85-Cr-kc1wM.cjs +0 -1
  208. package/dist/vuetifyConfig.umd.cjs +0 -1
  209. package/src/composables/date/tests/useDateFormat.spec.ts +0 -67
  210. package/src/composables/date/useDateFormat.ts +0 -110
  211. package/src/composables/date/useDateInitialization.ts +0 -92
@@ -1,6 +1,6 @@
1
1
  import { useValidation, type ValidationRule } from '@/composables/validation/useValidation'
2
2
  import { useValidatable } from '@/composables/validation/useValidatable'
3
- import { watch } from 'vue'
3
+ import { ref, watch } from 'vue'
4
4
  import type { Ref } from 'vue'
5
5
 
6
6
  /**
@@ -15,13 +15,15 @@ export function useCustomValidation(
15
15
  warnings: Ref<string[]>,
16
16
  successes: Ref<string[]>,
17
17
  showSuccessMessages: Ref<boolean>,
18
- label: Ref<string>,
18
+ label: Ref<string | undefined>,
19
19
  focused: Ref<boolean>,
20
20
  isValidateOnBlur: Ref<boolean>,
21
21
  disableErrorHandling: Ref<boolean>,
22
22
  readonly?: Ref<boolean>,
23
23
  disabled?: Ref<boolean>,
24
24
  ) {
25
+ const hasSuccess = ref(false)
26
+
25
27
  let validator = useValidation({
26
28
  showSuccessMessages: showSuccessMessages.value,
27
29
  fieldIdentifier: label.value,
@@ -37,7 +39,7 @@ export function useCustomValidation(
37
39
  disableErrorHandling: disableErrorHandling.value,
38
40
  })
39
41
 
40
- const isDirty = errors.value.length > 0 || warnings.value.length > 0 || successes.value.length > 0
42
+ const isDirty = errors.value.length > 0 || warnings.value.length > 0 || successes.value.length > 0 || hasSuccess.value
41
43
  if (isDirty) {
42
44
  validate()
43
45
  }
@@ -50,6 +52,7 @@ export function useCustomValidation(
50
52
  errors.value = []
51
53
  warnings.value = []
52
54
  successes.value = []
55
+ hasSuccess.value = false
53
56
  return { hasError: false, hasWarning: false, hasSuccess: false, state: { errors: [] as string[], warnings: [] as string[], successes: [] as string[] } }
54
57
  }
55
58
 
@@ -63,6 +66,7 @@ export function useCustomValidation(
63
66
  errors.value = result.state.errors
64
67
  warnings.value = result.state.warnings
65
68
  successes.value = result.state.successes
69
+ hasSuccess.value = result.hasSuccess
66
70
 
67
71
  return result
68
72
  }
@@ -75,6 +79,7 @@ export function useCustomValidation(
75
79
  errors.value = []
76
80
  warnings.value = []
77
81
  successes.value = []
82
+ hasSuccess.value = false
78
83
  },
79
84
  () => modelValue.value = undefined,
80
85
  )
@@ -91,5 +96,12 @@ export function useCustomValidation(
91
96
  }
92
97
  })
93
98
 
94
- return { validate }
99
+ function clearValidation() {
100
+ errors.value = []
101
+ warnings.value = []
102
+ successes.value = []
103
+ hasSuccess.value = false
104
+ }
105
+
106
+ return { validate, hasSuccess, clearValidation }
95
107
  }
@@ -12,15 +12,21 @@ export interface FieldValidationProps {
12
12
  isValidateOnBlur?: boolean
13
13
  showSuccessMessages?: boolean
14
14
  disableErrorHandling?: boolean
15
- // When true (Vuetify native mode), the controller should not handle errors/successes
15
+ // Quand cette prop vaut true (mode natif Vuetify), c'est Vuetify qui gère les erreurs, avertissements et succès
16
16
  useVuetifyValidation?: boolean
17
- label: string
17
+ label?: string
18
18
  rules?: VuetifyValidationRule[]
19
+ // Règles de validation personnalisées d'erreur (bloquantes), évaluées à partir de la valeur du champ
19
20
  customRules?: SyValidationRule[]
21
+ // Règles de validation personnalisées d'avertissement (non bloquantes), évaluées à partir de la valeur du champ
20
22
  customWarningRules?: SyValidationRule[]
23
+ // Règles de validation personnalisées de succès, évaluées à partir de la valeur du champ
21
24
  customSuccessRules?: SyValidationRule[]
25
+ // Messages d'erreur injectés par le parent ; ils n'exécutent aucune logique de validation
22
26
  errorMessages?: string[] | null
27
+ // Messages d'avertissement injectés par le parent ; ils n'exécutent aucune logique de validation
23
28
  warningMessages?: string[] | null
29
+ // Messages de succès injectés par le parent ; ils n'exécutent aucune logique de validation
24
30
  successMessages?: string[] | null
25
31
  hasError?: boolean
26
32
  hasWarning?: boolean
@@ -29,9 +35,13 @@ export interface FieldValidationProps {
29
35
  }
30
36
 
31
37
  /**
32
- * Entrypoint to handle validation in fields components.
33
- * It handles both Vuetify native validation (if useVuetifyValidation is true) and Synapse custom validation (if customRules are provided).
34
- * It also provides a unified interface to handle errors, warnings and successes, and to trigger validation on demand.
38
+ * Point d'entrée de la validation pour les composants de champ.
39
+ * Gère à la fois la validation native Vuetify (si useVuetifyValidation vaut true)
40
+ * et la validation custom Synapse (si customRules/customWarningRules/customSuccessRules sont fournis).
41
+ * customRules correspond aux règles d'erreur bloquantes.
42
+ * errorMessages/warningMessages/successMessages sont des messages externes injectés par le parent
43
+ * et ne déclenchent aucun calcul de validation.
44
+ * Expose aussi une interface unifiée pour les erreurs, avertissements, succès et la validation à la demande.
35
45
  */
36
46
  export const validationPropsDefaults = {
37
47
  readonly: false,
@@ -61,7 +71,7 @@ export function useValidation(params: {
61
71
  isValidateOnBlur: Ref<boolean>
62
72
  showSuccessMessages: Ref<boolean>
63
73
  disableErrorHandling: Ref<boolean>
64
- label: Ref<string>
74
+ label: Ref<string | undefined>
65
75
  focused: Ref<boolean>
66
76
  errorMessages?: Ref<string[] | null | undefined>
67
77
  warningMessages?: Ref<string[] | null | undefined>
@@ -95,13 +105,15 @@ export function useValidation(params: {
95
105
  errors: ref<string[]>([]),
96
106
  warnings: ref<string[]>([]),
97
107
  successes: ref<string[]>([]),
98
- hasError: computed(() => false),
99
- hasWarning: computed(() => false),
100
- hasSuccess: computed(() => false),
108
+ hasError: computed(() => params.hasErrorProp?.value ?? false),
109
+ hasWarning: computed(() => params.hasWarningProp?.value ?? false),
110
+ hasSuccess: computed(() => params.hasSuccessProp?.value ?? false),
101
111
  validate: async () => true,
112
+ clearValidation: () => {},
102
113
  }
103
114
  }
104
- const innerErrors = ref<string[]>([])
115
+ const vuetifyErrors = ref<string[]>([])
116
+ const customErrors = ref<string[]>([])
105
117
  const innerWarnings = ref<string[]>([])
106
118
  const innerSuccesses = ref<string[]>([])
107
119
 
@@ -112,7 +124,7 @@ export function useValidation(params: {
112
124
  params.modelValue,
113
125
  params.rules,
114
126
  params.disabled,
115
- innerErrors,
127
+ vuetifyErrors,
116
128
  params.hasErrorProp || ref(false),
117
129
  computed(() => params.errorMessages?.value || []),
118
130
  params.focused,
@@ -129,7 +141,7 @@ export function useValidation(params: {
129
141
  params.customRules,
130
142
  params.customWarningRules,
131
143
  params.customSuccessRules,
132
- innerErrors,
144
+ customErrors,
133
145
  innerWarnings,
134
146
  innerSuccesses,
135
147
  params.showSuccessMessages,
@@ -143,7 +155,8 @@ export function useValidation(params: {
143
155
 
144
156
  async function validate(): Promise<boolean> {
145
157
  if (params.readonly.value || params.disabled.value || params.disableErrorHandling.value) {
146
- innerErrors.value = []
158
+ vuetifyErrors.value = []
159
+ customErrors.value = []
147
160
  innerWarnings.value = []
148
161
  innerSuccesses.value = []
149
162
 
@@ -162,7 +175,8 @@ export function useValidation(params: {
162
175
  }
163
176
 
164
177
  const errors = computed(() => [...new Set([
165
- ...innerErrors.value,
178
+ ...vuetifyErrors.value,
179
+ ...customErrors.value,
166
180
  ...(params.errorMessages?.value || []),
167
181
  ])])
168
182
  const warnings = computed(() => [...new Set([
@@ -173,10 +187,26 @@ export function useValidation(params: {
173
187
  ...(params.showSuccessMessages.value ? innerSuccesses.value : []),
174
188
  ...(params.successMessages?.value || []),
175
189
  ])])
190
+ const internalHasSuccess = computed(() => customValidator.hasSuccess.value)
176
191
 
177
192
  const hasError = computed(() => errors.value.length > 0 || params.hasErrorProp?.value)
178
193
  const hasWarning = computed(() => warnings.value.length > 0 || params.hasWarningProp?.value)
179
- const hasSuccess = computed(() => (successes.value.length > 0 && !hasError.value && !hasWarning.value) || params.hasSuccessProp?.value)
194
+ // TODO: vérifier si c'est la meilleure approche pour supprimer le succès en mode Vuetify
195
+ const hasSuccess = computed(() => {
196
+ if (toValue(params.useVuetifyValidation)) {
197
+ return params.hasSuccessProp?.value ?? false
198
+ }
199
+ return (
200
+ (internalHasSuccess.value || (params.successMessages?.value?.length ?? 0) > 0)
201
+ && !hasError.value
202
+ && !hasWarning.value
203
+ ) || (params.hasSuccessProp?.value ?? false)
204
+ })
205
+
206
+ function clearValidation() {
207
+ vuetifyErrors.value = []
208
+ customValidator.clearValidation()
209
+ }
180
210
 
181
211
  return {
182
212
  errors,
@@ -186,5 +216,6 @@ export function useValidation(params: {
186
216
  hasWarning,
187
217
  hasSuccess,
188
218
  validate,
219
+ clearValidation,
189
220
  }
190
221
  }
@@ -12,8 +12,8 @@ export function useVuetifyValidation(
12
12
  errorMessages: Ref<string[]>,
13
13
  focused: Ref<boolean>,
14
14
  maxErrors: Ref<number> | undefined,
15
- name: Ref<string>,
16
- label: Ref<string>,
15
+ name: Ref<string | undefined>,
16
+ label: Ref<string | undefined>,
17
17
  readonly: Ref<boolean>,
18
18
  validateOn: Ref<'input' | 'blur' | 'submit'>,
19
19
  ) {
@@ -123,7 +123,10 @@ export const useFormFieldErrorHandling = (
123
123
 
124
124
  const hasError = computed(() => validation.hasError.value || (props.hasError ?? false))
125
125
  const hasWarning = computed(() => validation.hasWarning.value || (props.hasWarning ?? false))
126
- const hasSuccess = computed(() => ((validation.hasSuccess.value && !hasError.value && !hasWarning.value) || (props.hasSuccess ?? false)) && (props.showSuccessMessages ?? true))
126
+ const hasSuccess = computed(() =>
127
+ (validation.hasSuccess.value && !hasError.value && !hasWarning.value)
128
+ || (props.hasSuccess ?? false),
129
+ )
127
130
 
128
131
  const errors = computed(() => [...validation.errors.value, ...(props.errorMessages || [])])
129
132
  const warnings = computed(() => validation.warnings.value)
@@ -90,7 +90,7 @@ describe('useValidation', () => {
90
90
  expect(validResult.hasSuccess).toBe(true)
91
91
  })
92
92
 
93
- it('should respect showSuccessMessages option', async () => {
93
+ it('keeps the success state when showSuccessMessages is false while hiding messages', async () => {
94
94
  const validation = useValidation({ showSuccessMessages: false })
95
95
  const rules = [{
96
96
  type: 'required',
@@ -101,7 +101,7 @@ describe('useValidation', () => {
101
101
  }]
102
102
 
103
103
  const result = await validation.validateField('test', rules)
104
- expect(result.hasSuccess).toBe(false)
104
+ expect(result.hasSuccess).toBe(true)
105
105
  expect(result.state.successes).toEqual([])
106
106
  })
107
107
 
@@ -59,6 +59,7 @@ export function useValidation(options: ValidationOptions = { showSuccessMessages
59
59
  const errors = ref<string[]>([])
60
60
  const warnings = ref<string[]>([])
61
61
  const successes = ref<string[]>([])
62
+ const successState = ref(false)
62
63
 
63
64
  let currentValidationToken = 0
64
65
 
@@ -67,13 +68,17 @@ export function useValidation(options: ValidationOptions = { showSuccessMessages
67
68
  const hasError = computed(() => errors.value.length > 0)
68
69
  const hasWarning = computed(() => warnings.value.length > 0)
69
70
  const hasSuccess = computed(() =>
70
- successes.value.length > 0 && !hasError.value && !hasWarning.value,
71
+ successState.value && !hasError.value && !hasWarning.value,
72
+ )
73
+ const displaySuccesses = computed(() =>
74
+ options.showSuccessMessages !== false ? successes.value : [],
71
75
  )
72
76
 
73
77
  const clearValidation = () => {
74
78
  errors.value = []
75
79
  warnings.value = []
76
80
  successes.value = []
81
+ successState.value = false
77
82
  }
78
83
 
79
84
  /**
@@ -176,8 +181,12 @@ export function useValidation(options: ValidationOptions = { showSuccessMessages
176
181
  }
177
182
  }
178
183
 
179
- if (!hasValidationError && value && options.showSuccessMessages !== false && successRules.length === 0) {
180
- addDefaultSuccessMessage(rules)
184
+ const isValueFilled = Array.isArray(value) ? value.length > 0 : !!value
185
+ if (!hasValidationError && isValueFilled && successRules.length === 0) {
186
+ successState.value = true
187
+ if (options.showSuccessMessages !== false) {
188
+ addDefaultSuccessMessage(rules)
189
+ }
181
190
  }
182
191
 
183
192
  if (!hasValidationError && warningRules.length > 0) {
@@ -206,6 +215,8 @@ export function useValidation(options: ValidationOptions = { showSuccessMessages
206
215
  const successResolved = executeRules(successRules, value, { isSuccess: true })
207
216
 
208
217
  return thenOrSync(successResolved, token, (successResults) => {
218
+ successState.value = successResults.some(result => Boolean(result.success))
219
+
209
220
  for (const r of successResults) {
210
221
  if (r.success && options.showSuccessMessages !== false) {
211
222
  successes.value.push(r.success)
@@ -223,6 +234,7 @@ export function useValidation(options: ValidationOptions = { showSuccessMessages
223
234
  errors,
224
235
  warnings,
225
236
  successes,
237
+ displaySuccesses,
226
238
  hasError,
227
239
  hasWarning,
228
240
  hasSuccess,
@@ -0,0 +1,59 @@
1
+ import { Meta, Canvas } from '@storybook/blocks'
2
+ import * as VCardStories from './v-card.stories'
3
+
4
+ <Meta title="Composants/Composants Vuetify/VCard" />
5
+
6
+ <div className="header">
7
+ <h1>VCard</h1>
8
+ Ce composant utilise directement le composant natif `v-card` de Vuetify avec les couleurs du thème actif du design system.
9
+ Pour l'API complète du composant, consulter la [documentation Vuetify](https://vuetifyjs.com/en/api/v-card/#props).
10
+ </div>
11
+
12
+ ### Composants associés
13
+
14
+ - `v-card-title` : Titre de la carte
15
+ - `v-card-subtitle` : Sous-titre de la carte
16
+ - `v-card-text` : Contenu textuel de la carte
17
+ - `v-card-actions` : Zone pour les boutons d'action
18
+
19
+ ## Variantes
20
+
21
+ Le composant `v-card` propose plusieurs variantes de style :
22
+
23
+ - **elevated** : Carte avec une ombre (par défaut)
24
+ - **flat** : Carte sans ombre
25
+ - **outlined** : Carte avec une bordure
26
+ - **tonal** : Carte avec un fond coloré léger
27
+ - **text** : Carte sans fond ni bordure
28
+ - **plain** : Carte sans style
29
+
30
+ ### Primary
31
+
32
+ <Canvas of={VCardStories.Primary} />
33
+
34
+ ### Primary - Elevated
35
+
36
+ <Canvas of={VCardStories.PrimaryElevated} />
37
+
38
+ ### Primary - Outlined
39
+
40
+ <Canvas of={VCardStories.PrimaryOutlined} />
41
+
42
+ ### Primary - Tonal
43
+
44
+ <Canvas of={VCardStories.PrimaryTonal} />
45
+
46
+ ### En chargement
47
+
48
+ <Canvas of={VCardStories.Loading} />
49
+
50
+ ### Désactivée
51
+
52
+ <Canvas of={VCardStories.Disabled} />
53
+
54
+ ## Accessibilité
55
+
56
+ - Utilisez des titres descriptifs pour les cartes
57
+ - Assurez-vous que les images ont un attribut `alt` approprié
58
+ - Les actions dans la carte doivent être accessibles au clavier
59
+ - Utilisez des couleurs avec un contraste suffisant
@@ -0,0 +1,279 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import { VCard, VCardTitle, VCardText, VCardActions } from 'vuetify/components'
3
+ import { VBtn } from 'vuetify/components'
4
+
5
+ const meta: Meta<typeof VCard> = {
6
+ title: 'Composants/Composants Vuetify/VCard',
7
+ tags: ['!dev'],
8
+ component: VCard,
9
+ parameters: {
10
+ docs: {
11
+ source: {
12
+ transform: (src: string) => {
13
+ // Extract only the template part
14
+ const templateMatch = src.match(/template:\s*`([\s\S]*?)`/)
15
+ if (templateMatch && templateMatch[1]) {
16
+ return templateMatch[1]
17
+ .trim()
18
+ .replace(/<VCard/g, '<v-card')
19
+ .replace(/<\/VCard>/g, '</v-card>')
20
+ .replace(/<VCardTitle/g, '<v-card-title')
21
+ .replace(/<\/VCardTitle>/g, '</v-card-title>')
22
+ .replace(/<VCardText/g, '<v-card-text')
23
+ .replace(/<\/VCardText>/g, '</v-card-text>')
24
+ .replace(/<VCardActions/g, '<v-card-actions')
25
+ .replace(/<\/VCardActions>/g, '</v-card-actions>')
26
+ .replace(/<VBtn/g, '<v-btn')
27
+ .replace(/<\/VBtn>/g, '</v-btn>')
28
+ }
29
+ return src
30
+ },
31
+ },
32
+ },
33
+ },
34
+ argTypes: {
35
+ color: {
36
+ control: { type: 'text' },
37
+ description: 'Couleur de la carte',
38
+ },
39
+ variant: {
40
+ control: { type: 'select' },
41
+ options: ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain'],
42
+ description: 'Variante de style de la carte',
43
+ },
44
+ elevation: {
45
+ control: { type: 'number' },
46
+ description: 'Élévation de la carte (ombre)',
47
+ },
48
+ disabled: {
49
+ control: { type: 'boolean' },
50
+ description: 'Désactive la carte',
51
+ },
52
+ loading: {
53
+ control: { type: 'boolean' },
54
+ description: 'Affiche un état de chargement',
55
+ },
56
+ rounded: {
57
+ control: { type: 'select' },
58
+ options: ['0', 'sm', 'md', 'lg', 'xl', 'pill', 'circle'],
59
+ description: 'Arrondi des coins de la carte',
60
+ },
61
+ },
62
+ }
63
+
64
+ export default meta
65
+
66
+ type Story = StoryObj<typeof VCard>
67
+
68
+ export const Primary: Story = {
69
+ render: args => ({
70
+ components: { VCard, VCardTitle, VCardText },
71
+ setup() {
72
+ return { args }
73
+ },
74
+ template: `
75
+ <VCard v-bind="args" style="max-width: 400px;">
76
+ <VCardTitle>Carte Primary</VCardTitle>
77
+ <VCardText>
78
+ Cette carte utilise la couleur "primary".
79
+ </VCardText>
80
+ </VCard>
81
+ `,
82
+ }),
83
+ args: {
84
+ color: 'primary',
85
+ },
86
+ parameters: {
87
+ docs: {
88
+ source: {
89
+ code: `<v-card color="primary" style="max-width: 400px;">
90
+ <v-card-title>Carte Primary</v-card-title>
91
+ <v-card-text>
92
+ Cette carte utilise la couleur "primary".
93
+ </v-card-text>
94
+ </v-card>`,
95
+ },
96
+ },
97
+ },
98
+ }
99
+
100
+ export const PrimaryTonal: Story = {
101
+ render: args => ({
102
+ components: { VCard, VCardTitle, VCardText },
103
+ setup() {
104
+ return { args }
105
+ },
106
+ template: `
107
+ <VCard v-bind="args" style="max-width: 400px;">
108
+ <VCardTitle>Carte Primary Tonal</VCardTitle>
109
+ <VCardText>
110
+ Cette carte utilise la couleur "primary" et la variant "tonal".
111
+ </VCardText>
112
+ </VCard>
113
+ `,
114
+ }),
115
+ args: {
116
+ color: 'primary',
117
+ variant: 'tonal',
118
+ },
119
+ parameters: {
120
+ docs: {
121
+ source: {
122
+ code: `<v-card color="primary" variant="tonal" style="max-width: 400px;">
123
+ <v-card-title>Carte Primary Tonal</v-card-title>
124
+ <v-card-text>
125
+ Cette carte utilise la couleur "primary" et la variant "tonal".
126
+ </v-card-text>
127
+ </v-card>`,
128
+ },
129
+ },
130
+ },
131
+ }
132
+
133
+ export const PrimaryElevated: Story = {
134
+ render: args => ({
135
+ components: { VCard, VCardTitle, VCardText },
136
+ setup() {
137
+ return { args }
138
+ },
139
+ template: `
140
+ <VCard v-bind="args" style="max-width: 400px;">
141
+ <VCardTitle>Carte Primary Elevated</VCardTitle>
142
+ <VCardText>
143
+ Cette carte utilise la couleur "primary" et la variant "elevated".
144
+ </VCardText>
145
+ </VCard>
146
+ `,
147
+ }),
148
+ args: {
149
+ color: 'primary',
150
+ variant: 'elevated',
151
+ elevation: 4,
152
+ },
153
+ parameters: {
154
+ docs: {
155
+ source: {
156
+ code: `<v-card color="primary" variant="elevated" :elevation="4" style="max-width: 400px;">
157
+ <v-card-title>Carte Primary Elevated</v-card-title>
158
+ <v-card-text>
159
+ Cette carte utilise la couleur "primary" et la variant "elevated".
160
+ </v-card-text>
161
+ </v-card>`,
162
+ },
163
+ },
164
+ },
165
+ }
166
+
167
+ export const PrimaryOutlined: Story = {
168
+ render: args => ({
169
+ components: { VCard, VCardTitle, VCardText, VCardActions, VBtn },
170
+ setup() {
171
+ return { args }
172
+ },
173
+ template: `
174
+ <VCard v-bind="args" style="max-width: 400px;">
175
+ <VCardTitle>Carte Primary Outlined</VCardTitle>
176
+ <VCardText>
177
+ Cette carte utilise la couleur "primary" et la variant "outlined". Elle contient également des boutons d'action.
178
+ </VCardText>
179
+ <VCardActions class="justify-end">
180
+ <VBtn variant="text" color="primary">Annuler</VBtn>
181
+ <VBtn variant="tonal" color="primary">Confirmer</VBtn>
182
+ </VCardActions>
183
+ </VCard>
184
+ `,
185
+ }),
186
+ args: {
187
+ color: 'primary',
188
+ variant: 'outlined',
189
+ },
190
+ parameters: {
191
+ docs: {
192
+ source: {
193
+ code: `<v-card color="primary" variant="outlined" style="max-width: 400px;">
194
+ <v-card-title>Carte Primary Outlined</v-card-title>
195
+ <v-card-text>
196
+ Cette carte utilise la couleur "primary" et la variant "outlined". Elle contient également des boutons d'action.
197
+ </v-card-text>
198
+ <v-card-actions class="justify-end">
199
+ <v-btn variant="text" color="primary">Annuler</v-btn>
200
+ <v-btn variant="tonal" color="primary">Confirmer</v-btn>
201
+ </v-card-actions>
202
+ </v-card>`,
203
+ },
204
+ },
205
+ },
206
+ }
207
+
208
+ // États
209
+
210
+ export const Loading: Story = {
211
+ render: args => ({
212
+ components: { VCard, VCardTitle, VCardText },
213
+ setup() {
214
+ return { args }
215
+ },
216
+ template: `
217
+ <VCard v-bind="args" style="max-width: 400px;">
218
+ <VCardTitle>Carte Primary en chargement</VCardTitle>
219
+ <VCardText>
220
+ Cette carte utilise la couleur "primary" et affiche un état de chargement.
221
+ </VCardText>
222
+ </VCard>
223
+ `,
224
+ }),
225
+ args: {
226
+ loading: true,
227
+ color: 'primary',
228
+ },
229
+ parameters: {
230
+ docs: {
231
+ source: {
232
+ code: `<v-card :loading="true" color="primary" style="max-width: 400px;">
233
+ <v-card-title>Carte Primary en chargement</v-card-title>
234
+ <v-card-text>
235
+ Cette carte utilise la couleur "primary" et affiche un état de chargement.
236
+ </v-card-text>
237
+ </v-card>`,
238
+ },
239
+ },
240
+ },
241
+ }
242
+
243
+ export const Disabled: Story = {
244
+ render: args => ({
245
+ components: { VCard, VCardTitle, VCardText, VCardActions, VBtn },
246
+ setup() {
247
+ return { args }
248
+ },
249
+ template: `
250
+ <VCard v-bind="args" style="max-width: 400px;">
251
+ <VCardTitle>Carte désactivée</VCardTitle>
252
+ <VCardText>
253
+ Cette carte est désactivée.
254
+ </VCardText>
255
+ <VCardActions class="justify-end">
256
+ <VBtn>Action</VBtn>
257
+ </VCardActions>
258
+ </VCard>
259
+ `,
260
+ }),
261
+ args: {
262
+ disabled: true,
263
+ },
264
+ parameters: {
265
+ docs: {
266
+ source: {
267
+ code: `<v-card :disabled="true" style="max-width: 400px;">
268
+ <v-card-title>Carte désactivée</v-card-title>
269
+ <v-card-text>
270
+ Cette carte est désactivée.
271
+ </v-card-text>
272
+ <v-card-actions class="justify-end">
273
+ <v-btn>Action</v-btn>
274
+ </v-card-actions>
275
+ </v-card>`,
276
+ },
277
+ },
278
+ },
279
+ }
@@ -1,4 +1,4 @@
1
- import type { IndexedObject } from '@/components/Amelipro/types.ts'
1
+ import type { IndexedObject } from '../../../components/Amelipro/types.ts'
2
2
  import { buildColorClassMap } from '../../utils/buildColorClassMap'
3
3
 
4
4
  export const apColorsTokens2026 = {
@@ -1,5 +1,6 @@
1
1
  import { apSemanticTokens } from './apSemantic'
2
2
  import { apColorsTokens } from './apColors'
3
+ import { baseColors } from '../baseColors'
3
4
 
4
5
  export const apLightTheme = {
5
6
  primary: apColorsTokens.cyan.darken20,
@@ -100,4 +101,6 @@ export const apLightTheme = {
100
101
  iconOnDark: apSemanticTokens.colors.icon.onDark,
101
102
  iconDisabled: apSemanticTokens.colors.icon.disabled,
102
103
  iconDisabledOnDark: apSemanticTokens.colors.icon.disabledOnDark,
104
+ feedbackOnSuccess: baseColors.white.base,
105
+ colorPrimary: baseColors.cyan.base,
103
106
  }
@@ -1,3 +1,4 @@
1
+ import { baseColors } from '../baseColors'
1
2
  import { cnamColorsTokens } from './cnamColors'
2
3
  import { cnamSemanticTokens } from './cnamSemantic'
3
4
 
@@ -101,4 +102,6 @@ export const cnamLightTheme = {
101
102
  iconOnDark: cnamSemanticTokens.colors.icon.onDark,
102
103
  iconDisabled: cnamSemanticTokens.colors.icon.disabled,
103
104
  iconDisabledOnDark: cnamSemanticTokens.colors.icon.disabledOnDark,
105
+ feedbackOnSuccess: baseColors.grey.darken60,
106
+ colorPrimary: baseColors.blue.base,
104
107
  }