@cnamts/synapse 1.1.0 → 1.1.1

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 (202) hide show
  1. package/dist/{AutocompleteFilter-DXd4szWO.js → AutocompleteFilter-CGF33skz.js} +1 -1
  2. package/dist/{DateFilter-BD59Kgwf.js → DateFilter-D7-MsKtx.js} +1 -1
  3. package/dist/{NumberFilter-BSMZE7uw.js → NumberFilter-bjQPPfsj.js} +1 -1
  4. package/dist/{PeriodFilter-keUdSSk0.js → PeriodFilter-B3wJpK8-.js} +1 -1
  5. package/dist/{SelectFilter-Dhvvwazl.js → SelectFilter-BN6DbKAV.js} +1 -1
  6. package/dist/{TextFilter-CU8FpXz0.js → TextFilter-BffP0J2f.js} +1 -1
  7. package/dist/{apLightTheme2026-DbS7BPUf.js → apLightTheme2026-C4ygwMHC.js} +11 -11
  8. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +6 -6
  9. package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +6 -6
  10. package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +6 -6
  11. package/dist/components/Captcha/Captcha.d.ts +27 -16
  12. package/dist/components/Captcha/CaptchaForm.d.ts +29 -3
  13. package/dist/components/Captcha/types.d.ts +14 -0
  14. package/dist/components/Captcha/useCaptchaValidation.d.ts +37 -0
  15. package/dist/components/Customs/Selects/SelectBtnField/SelectBtnField.d.ts +33 -13
  16. package/dist/components/Customs/Selects/SelectBtnField/composables/useSelectBtnFieldValidation.d.ts +23 -0
  17. package/dist/components/Customs/Selects/SyAutocomplete/composables/useSyAutocompleteValidation.d.ts +2 -2
  18. package/dist/components/Customs/Selects/SySelect/composables/useSySelectValidation.d.ts +2 -2
  19. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +17 -48
  20. package/dist/components/Customs/SyCheckBoxGroup/composables/useSyCheckBoxGroupValidation.d.ts +29 -0
  21. package/dist/components/Customs/SyCheckBoxGroup/types.d.ts +46 -0
  22. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +16 -51
  23. package/dist/components/Customs/SyCheckbox/composables/useSyCheckboxValidation.d.ts +27 -0
  24. package/dist/components/Customs/SyCheckbox/types.d.ts +49 -0
  25. package/dist/components/Customs/SyTextField/FieldState.d.ts +5 -0
  26. package/dist/components/Customs/SyTextField/useSyTextFieldValidation.d.ts +3 -3
  27. package/dist/components/DialogBox/DialogBox.d.ts +2 -0
  28. package/dist/components/DialogBox/locales.d.ts +1 -0
  29. package/dist/components/FilterSideBar/FilterSideBar.d.ts +4 -0
  30. package/dist/components/LunarCalendar/LunarCalendar.d.ts +43 -14
  31. package/dist/components/LunarCalendar/types.d.ts +35 -0
  32. package/dist/components/LunarCalendar/useLunarCalendarValidation.d.ts +11 -12
  33. package/dist/components/MonthPicker/MonthPicker.d.ts +72 -1747
  34. package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +21 -1733
  35. package/dist/components/MonthPicker/MonthPickerText/useTextField.d.ts +5 -0
  36. package/dist/components/MonthPicker/locales.d.ts +1 -0
  37. package/dist/components/MonthPicker/types.d.ts +11 -0
  38. package/dist/components/MonthPicker/useMonthPickerValidation.d.ts +37 -24
  39. package/dist/components/NirField/NirField.d.ts +6 -4
  40. package/dist/components/NirField/useNirValidation.d.ts +7 -5
  41. package/dist/components/PageContainer/PageContainer.d.ts +8 -0
  42. package/dist/components/PasswordField/PasswordField.d.ts +2 -2
  43. package/dist/components/PasswordField/usePasswordFieldValidation.d.ts +2 -2
  44. package/dist/components/PhoneField/PhoneField.d.ts +960 -1938
  45. package/dist/components/PhoneField/indicatifs.d.ts +715 -8
  46. package/dist/components/PhoneField/locales.d.ts +7 -0
  47. package/dist/components/PhoneField/types.d.ts +29 -0
  48. package/dist/components/PhoneField/usePhoneFieldValidation.d.ts +45 -0
  49. package/dist/components/PhoneField/usePhoneIndicatifs.d.ts +947 -0
  50. package/dist/components/SyTextArea/composables/useSyTextAreaValidation.d.ts +2 -2
  51. package/dist/composables/unifyValidation/documentationValidationProps.d.ts +1 -1
  52. package/dist/composables/unifyValidation/useValidation.d.ts +4 -5
  53. package/dist/design-system-v3.js +2 -2
  54. package/dist/designTokens/tokens/amelipro/apLightTheme.d.ts +10 -10
  55. package/dist/designTokens/tokens/baseTokens.d.ts +18 -18
  56. package/dist/designTokens/tokens/cnam/cnamLightTheme.d.ts +10 -10
  57. package/dist/designTokens/tokens/pa/paLightTheme.d.ts +10 -10
  58. package/dist/designTokens/tokens/semanticTokens.d.ts +14 -14
  59. package/dist/{main-D8ryUoS5.js → main-C4wAktOs.js} +13718 -12991
  60. package/dist/synapse.css +1 -1
  61. package/dist/vuetifyConfig.js +1 -1
  62. package/package.json +7 -7
  63. package/src/assets/compat/_legacy-tokens.scss +91 -0
  64. package/src/assets/overrides/_utilities.scss +23 -0
  65. package/src/components/Accordion/Accordion.stories.ts +121 -1
  66. package/src/components/BackBtn/BackBtn.mdx +1 -1
  67. package/src/components/BackToTopBtn/BackToTopBtn.mdx +0 -1
  68. package/src/components/Captcha/Captcha.stories.ts +134 -31
  69. package/src/components/Captcha/Captcha.vue +95 -28
  70. package/src/components/Captcha/CaptchaForm.vue +51 -22
  71. package/src/components/Captcha/tests/Captcha.focus.spec.ts +214 -0
  72. package/src/components/Captcha/tests/Captcha.spec.ts +233 -24
  73. package/src/components/Captcha/tests/CaptchaForm.spec.ts +82 -0
  74. package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +16 -42
  75. package/src/components/Captcha/types.ts +15 -0
  76. package/src/components/Captcha/useCaptchaValidation.ts +87 -0
  77. package/src/components/Captcha/validation/validation.stories.ts +1194 -0
  78. package/src/components/ChipList/ChipList.mdx +0 -1
  79. package/src/components/CollapsibleList/CollapsibleList.mdx +0 -1
  80. package/src/components/CookieBanner/CookieBanner.mdx +0 -1
  81. package/src/components/CopyBtn/CopyBtn.mdx +0 -1
  82. package/src/components/Customs/Selects/SelectBtnField/SelectBtnField.stories.ts +123 -439
  83. package/src/components/Customs/Selects/SelectBtnField/SelectBtnField.vue +147 -41
  84. package/src/components/Customs/Selects/SelectBtnField/Validation/Validation.stories.ts +600 -0
  85. package/src/components/Customs/Selects/SelectBtnField/composables/useSelectBtnFieldValidation.ts +87 -0
  86. package/src/components/Customs/Selects/SelectBtnField/tests/SelectBtnField.spec.ts +402 -33
  87. package/src/components/Customs/Selects/SelectBtnField/tests/__snapshots__/SelectBtnField.spec.ts.snap +52 -38
  88. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.stories.ts +342 -162
  89. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +77 -129
  90. package/src/components/Customs/SyCheckBoxGroup/Validation/Validation.stories.ts +1008 -0
  91. package/src/components/Customs/SyCheckBoxGroup/composables/useSyCheckBoxGroupValidation.ts +107 -0
  92. package/src/components/Customs/SyCheckBoxGroup/tests/SyCheckBoxGroup.spec.ts +180 -7
  93. package/src/components/Customs/SyCheckBoxGroup/types.ts +49 -0
  94. package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +41 -161
  95. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +71 -148
  96. package/src/components/Customs/SyCheckbox/Validation/Validation.stories.ts +654 -0
  97. package/src/components/Customs/SyCheckbox/composables/useSyCheckboxValidation.ts +105 -0
  98. package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +106 -0
  99. package/src/components/Customs/SyCheckbox/tests/useSyCheckboxValidation.spec.ts +98 -0
  100. package/src/components/Customs/SyCheckbox/types.ts +51 -0
  101. package/src/components/Customs/SyTextField/FieldState.vue +50 -0
  102. package/src/components/Customs/SyTextField/SyTextField.vue +12 -9
  103. package/src/components/Customs/SyTextField/useSyTextFieldValidation.ts +2 -11
  104. package/src/components/DataList/DataList.mdx +0 -1
  105. package/src/components/DataListGroup/DataListGroup.mdx +0 -1
  106. package/src/components/DiacriticPicker/DiacriticPicker.mdx +0 -1
  107. package/src/components/DialogBox/DialogBox.mdx +0 -1
  108. package/src/components/DialogBox/DialogBox.stories.ts +399 -4
  109. package/src/components/DialogBox/DialogBox.vue +20 -0
  110. package/src/components/DialogBox/locales.ts +1 -0
  111. package/src/components/DialogBox/tests/DialogBox.spec.ts +73 -0
  112. package/src/components/DialogBox/tests/DialogBox.visual.cy.ts +24 -0
  113. package/src/components/ErrorPage/ErrorPage.mdx +1 -1
  114. package/src/components/ExternalLinks/ExternalLinks.mdx +0 -1
  115. package/src/components/FileList/FileList.mdx +0 -1
  116. package/src/components/FilterInline/FilterInline.mdx +0 -1
  117. package/src/components/FilterSideBar/FilterSideBar.mdx +8 -1
  118. package/src/components/FilterSideBar/FilterSideBar.stories.ts +133 -1
  119. package/src/components/FilterSideBar/FilterSideBar.vue +19 -2
  120. package/src/components/FilterSideBar/tests/FilterSideBar.spec.ts +55 -0
  121. package/src/components/FooterBar/FooterBar.mdx +0 -1
  122. package/src/components/FranceConnectBtn/FranceConnectBtn.mdx +0 -1
  123. package/src/components/HeaderBar/HeaderBar.mdx +0 -1
  124. package/src/components/HeaderLoading/HeaderLoading.mdx +0 -1
  125. package/src/components/LangBtn/LangBtn.mdx +0 -1
  126. package/src/components/Logo/Logo.mdx +1 -1
  127. package/src/components/LunarCalendar/LunarCalendar.mdx +6 -9
  128. package/src/components/LunarCalendar/LunarCalendar.stories.ts +243 -46
  129. package/src/components/LunarCalendar/LunarCalendar.vue +61 -26
  130. package/src/components/LunarCalendar/Validation/Validation.stories.ts +717 -0
  131. package/src/components/LunarCalendar/tests/LunarCalendar.a11y.spec.ts +1 -1
  132. package/src/components/LunarCalendar/tests/LunarCalendar.spec.ts +197 -6
  133. package/src/components/LunarCalendar/tests/useLunarCalendarValidation.spec.ts +287 -0
  134. package/src/components/LunarCalendar/types.ts +39 -0
  135. package/src/components/LunarCalendar/useLunarCalendarValidation.ts +115 -39
  136. package/src/components/MonthPicker/MonthPicker.stories.ts +38 -281
  137. package/src/components/MonthPicker/MonthPicker.vue +66 -17
  138. package/src/components/MonthPicker/MonthPickerText/MonthPickerInput.vue +44 -20
  139. package/src/components/MonthPicker/MonthPickerText/useTextField.ts +5 -0
  140. package/src/components/MonthPicker/Validation/Validation.stories.ts +1117 -0
  141. package/src/components/MonthPicker/locales.ts +1 -0
  142. package/src/components/MonthPicker/tests/MonthPicker.spec.ts +353 -2
  143. package/src/components/MonthPicker/tests/__snapshots__/MonthPicker.spec.ts.snap +12 -8
  144. package/src/components/MonthPicker/types.ts +16 -0
  145. package/src/components/MonthPicker/useMonthPickerValidation.ts +64 -27
  146. package/src/components/NirField/NirField.mdx +120 -66
  147. package/src/components/NirField/NirField.stories.ts +216 -0
  148. package/src/components/NirField/useNirValidation.ts +16 -17
  149. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +263 -245
  150. package/src/components/NotificationBar/NotificationBar.mdx +0 -1
  151. package/src/components/PageContainer/PageContainer.mdx +0 -1
  152. package/src/components/PageContainer/PageContainer.stories.ts +170 -2
  153. package/src/components/PageContainer/PageContainer.vue +63 -8
  154. package/src/components/PageContainer/tests/__snapshots__/PageContainer.spec.ts.snap +19 -11
  155. package/src/components/PaginatedTable/PaginatedTable.mdx +0 -1
  156. package/src/components/PeriodField/PeriodField.mdx +0 -1
  157. package/src/components/PhoneField/PhoneField.mdx +2 -3
  158. package/src/components/PhoneField/PhoneField.stories.ts +227 -410
  159. package/src/components/PhoneField/PhoneField.vue +204 -438
  160. package/src/components/PhoneField/indicatifs.ts +1 -1
  161. package/src/components/PhoneField/locales.ts +7 -0
  162. package/src/components/PhoneField/tests/PhoneField.a11y.spec.ts +0 -1
  163. package/src/components/PhoneField/tests/PhoneField.spec.ts +517 -220
  164. package/src/components/PhoneField/types.ts +30 -0
  165. package/src/components/PhoneField/usePhoneFieldValidation.ts +119 -0
  166. package/src/components/PhoneField/usePhoneIndicatifs.ts +89 -0
  167. package/src/components/PhoneField/validation/validation.stories.ts +717 -0
  168. package/src/components/RangeField/RangeField.mdx +0 -1
  169. package/src/components/RatingPicker/RatingPicker.mdx +0 -1
  170. package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +0 -1
  171. package/src/components/StatusPage/StatusPage.vue +1 -0
  172. package/src/components/StatusPage/tests/__snapshots__/StatusPage.spec.ts.snap +248 -230
  173. package/src/components/SubHeader/SubHeader.mdx +5 -6
  174. package/src/components/Tables/common/tests/SyTableFilter.spec.ts +11 -12
  175. package/src/components/UploadWorkflow/UploadWorkflow.mdx +0 -1
  176. package/src/components/UserMenuBtn/UserMenuBtn.mdx +0 -1
  177. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +177 -0
  178. package/src/composables/unifyValidation/documentationValidationProps.ts +1 -1
  179. package/src/composables/unifyValidation/tests/useValidation.spec.ts +13 -1
  180. package/src/composables/unifyValidation/useValidation.ts +37 -33
  181. package/src/composantsVuetify/VCard/VCard.mdx +4 -0
  182. package/src/composantsVuetify/VCard/v-card.stories.ts +93 -1
  183. package/src/composantsVuetify/VCarousel/VCarousel.mdx +74 -0
  184. package/src/composantsVuetify/VCarousel/v-carousel.stories.ts +531 -0
  185. package/src/composantsVuetify/VNavigationDrawer/VNavgationDrawer.mdx +53 -0
  186. package/src/composantsVuetify/VNavigationDrawer/v-navigation-drawer.stories.ts +310 -0
  187. package/src/composantsVuetify/VSlideGroup/VSlideGroup.mdx +105 -0
  188. package/src/composantsVuetify/VSlideGroup/v-slide-group.stories.ts +463 -0
  189. package/src/designTokens/tokens/baseColors.ts +1 -1
  190. package/src/designTokens/tokens/baseTokens.ts +18 -18
  191. package/src/stories/Components/Components.stories.ts +34 -1
  192. package/src/stories/Demarrer/Releases.stories.ts +16 -2
  193. package/src/stories/DesignTokens/Arrondis.mdx +1 -1
  194. package/src/stories/DesignTokens/Correspondances.mdx +219 -0
  195. package/src/stories/DesignTokens/UtiliserLesTokens.mdx +235 -0
  196. package/src/stories/DesignTokens/colors.stories.ts +569 -569
  197. package/src/stories/GuideDuDev/Amelipro.stories.ts +335 -267
  198. package/dist/components/LunarCalendar/useLunarCalendarRules.d.ts +0 -5
  199. package/dist/components/PhoneField/tests/types.d.ts +0 -18
  200. package/src/components/LunarCalendar/tests/useLunarCalendarRules.spec.ts +0 -184
  201. package/src/components/LunarCalendar/useLunarCalendarRules.ts +0 -96
  202. package/src/components/PhoneField/tests/types.d.ts +0 -19
@@ -0,0 +1,107 @@
1
+ import { computed, ref, toRef, type ComputedRef, type Ref } from 'vue'
2
+ import { useValidation, type ValidationRule } from '@/composables/unifyValidation/useValidation'
3
+ import type { SyCheckBoxGroupValidationProps } from '../types'
4
+
5
+ export interface UseSyCheckBoxGroupValidationReturn {
6
+ validate: () => Promise<boolean>
7
+ validateOnSubmit: () => Promise<boolean>
8
+ clearValidation: () => void
9
+ errors: Ref<string[]>
10
+ warnings: Ref<string[]>
11
+ successes: Ref<string[]>
12
+ hasError: ComputedRef<boolean | undefined>
13
+ hasWarning: ComputedRef<boolean | undefined>
14
+ hasSuccess: ComputedRef<boolean | undefined>
15
+ defaultRules: ComputedRef<ValidationRule[]>
16
+ focused: Ref<boolean>
17
+ }
18
+
19
+ /**
20
+ * Composable pour gérer la validation du composant SyCheckBoxGroup
21
+ *
22
+ * Ce composable encapsule toute la logique de validation spécifique aux groupes de checkboxes :
23
+ * - Validation required avec message personnalisé (supporte les modes single et multiple)
24
+ * - Support des customRules, customWarningRules, customSuccessRules
25
+ * - Désactivation automatique des messages de succès en mode Vuetify
26
+ * - Intégration avec useValidation du design system
27
+ *
28
+ * @example
29
+ * const { validate, errors, hasError, defaultRules } = useSyCheckBoxGroupValidation(props, model)
30
+ */
31
+ export function useSyCheckBoxGroupValidation(
32
+ props: SyCheckBoxGroupValidationProps,
33
+ model: Ref<(string | number) | (string | number)[] | null>,
34
+ focused?: Ref<boolean>,
35
+ ): UseSyCheckBoxGroupValidationReturn {
36
+ // Utiliser la variable focused passée en paramètre, sinon en créer une locale
37
+ const focusedRef = focused !== undefined ? focused : ref(false)
38
+
39
+ // Construction des règles de validation par défaut (required)
40
+ const defaultRules = computed<ValidationRule[]>(() =>
41
+ props.required
42
+ ? [{
43
+ type: 'required',
44
+ options: {
45
+ message: `Le champ ${props.fieldIdentifier || props.label || 'ce champ'} est requis.`,
46
+ fieldIdentifier: props.label,
47
+ },
48
+ }]
49
+ : [],
50
+ )
51
+
52
+ // Vuetify ne gère pas les messages de succès, on désactive automatiquement en mode Vuetify
53
+ const effectiveShowSuccessMessages = computed(() =>
54
+ props.useVuetifyValidation ? false : (props.showSuccessMessages ?? false),
55
+ )
56
+
57
+ const {
58
+ validate,
59
+ clearValidation,
60
+ errors,
61
+ warnings,
62
+ successes,
63
+ hasError,
64
+ hasWarning,
65
+ hasSuccess,
66
+ } = useValidation({
67
+ modelValue: model,
68
+ readonly: toRef(() => props.readonly ?? false),
69
+ disabled: toRef(() => props.disabled ?? false),
70
+ required: toRef(() => props.required ?? false),
71
+ isValidateOnBlur: toRef(() => props.isValidateOnBlur ?? false),
72
+ showSuccessMessages: effectiveShowSuccessMessages,
73
+ disableErrorHandling: toRef(() => props.disableErrorHandling ?? false),
74
+ useVuetifyValidation: toRef(() => props.useVuetifyValidation ?? false),
75
+ label: toRef(() => props.label ?? ''),
76
+ rules: toRef(() => props.rules),
77
+ customRules: computed(() => [...defaultRules.value, ...(props.customRules || [])]),
78
+ customWarningRules: toRef(() => props.customWarningRules ?? []),
79
+ customSuccessRules: toRef(() => props.customSuccessRules ?? []),
80
+ errorMessages: toRef(() => props.errorMessages ?? null),
81
+ warningMessages: toRef(() => props.warningMessages ?? null),
82
+ successMessages: toRef(() => props.successMessages ?? null),
83
+ hasErrorProp: toRef(() => props.hasError ?? false),
84
+ hasWarningProp: toRef(() => props.hasWarning ?? false),
85
+ hasSuccessProp: toRef(() => props.hasSuccess ?? false),
86
+ maxErrors: toRef(() => props.maxErrors ?? 1),
87
+ focused: focusedRef,
88
+ })
89
+
90
+ const validateOnSubmit = async (): Promise<boolean> => {
91
+ return await validate()
92
+ }
93
+
94
+ return {
95
+ validate,
96
+ validateOnSubmit,
97
+ clearValidation,
98
+ errors,
99
+ warnings,
100
+ successes,
101
+ hasError,
102
+ hasWarning,
103
+ hasSuccess,
104
+ defaultRules,
105
+ focused: focusedRef,
106
+ }
107
+ }
@@ -3,6 +3,7 @@ import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue'
3
3
  import { mount } from '@vue/test-utils'
4
4
  import { describe, it, expect } from 'vitest'
5
5
  import { nextTick } from 'vue'
6
+ import type { ValidationRule } from '@/composables/unifyValidation/useValidation'
6
7
 
7
8
  describe('SyCheckBoxGroup', () => {
8
9
  it('should render correctly', () => {
@@ -82,17 +83,17 @@ describe('SyCheckBoxGroup', () => {
82
83
  },
83
84
  })
84
85
 
85
- await wrapper.vm.validateOnSubmit()
86
+ const isValidInitial = await wrapper.vm.validateOnSubmit()
86
87
  await nextTick()
87
- expect(wrapper.vm.validation.hasError.value).toBe(true)
88
- expect(wrapper.vm.validation.errors.value[0]).toContain('est requis')
88
+ expect(isValidInitial).toBe(false)
89
+ expect(wrapper.text()).toContain('est requis')
89
90
 
90
91
  await wrapper.find('input').setValue(true)
91
92
 
92
- await wrapper.vm.validateOnSubmit()
93
+ const isValidAfterSelection = await wrapper.vm.validateOnSubmit()
93
94
  await nextTick()
94
95
 
95
- expect(wrapper.vm.validation.hasError.value).toBe(false)
96
+ expect(isValidAfterSelection).toBe(true)
96
97
  expect(wrapper.props('modelValue')).toBe('X')
97
98
  })
98
99
 
@@ -141,12 +142,184 @@ describe('SyCheckBoxGroup', () => {
141
142
 
142
143
  const isValidInitial = await wrapper.vm.validateOnSubmit()
143
144
  expect(isValidInitial).toBe(false)
144
- expect(wrapper.vm.validation.errors.value).toContain('Vous devez sélectionner une option.')
145
+ // Vérifier que le message d'erreur de la règle required ou custom est affiché
146
+ expect(wrapper.text()).toContain('requis') // Le message required par défaut
145
147
 
146
148
  await wrapper.setProps({ modelValue: 'OK' })
147
149
 
148
150
  const isValidCorrect = await wrapper.vm.validateOnSubmit()
149
151
  expect(isValidCorrect).toBe(true)
150
- expect(wrapper.vm.validation.errors.value).toHaveLength(0)
152
+ // Vérifier que le message d'erreur n'est plus présent
153
+ expect(wrapper.text()).not.toContain('requis')
154
+ })
155
+
156
+ it('should display asterisk when displayAsterisk is true and required', () => {
157
+ const wrapper = mount(SyCheckBoxGroup, {
158
+ props: {
159
+ label: 'Required Field',
160
+ required: true,
161
+ displayAsterisk: true,
162
+ options: [{ label: 'X', value: 'X', id: 'opt-x' }],
163
+ },
164
+ })
165
+
166
+ expect(wrapper.text()).toContain('Required Field *')
167
+ })
168
+
169
+ it('should not display asterisk when displayAsterisk is false', () => {
170
+ const wrapper = mount(SyCheckBoxGroup, {
171
+ props: {
172
+ label: 'Required Field',
173
+ required: true,
174
+ displayAsterisk: false,
175
+ options: [{ label: 'X', value: 'X', id: 'opt-x' }],
176
+ },
177
+ })
178
+
179
+ expect(wrapper.text()).not.toContain('Required Field *')
180
+ })
181
+
182
+ it('should handle external error messages', async () => {
183
+ const wrapper = mount(SyCheckBoxGroup, {
184
+ props: {
185
+ label: 'CheckBox Group',
186
+ options: [{ label: 'X', value: 'X', id: 'opt-x' }],
187
+ errorMessages: ['Erreur externe'],
188
+ },
189
+ })
190
+
191
+ await nextTick()
192
+
193
+ const errorMessages = wrapper.findAll('.v-messages__message')
194
+ expect(errorMessages.length).toBeGreaterThan(0)
195
+ expect(errorMessages[0]?.text()).toContain('Erreur externe')
196
+ })
197
+
198
+ it('should handle warning and success rules', async () => {
199
+ const warningRule: ValidationRule = {
200
+ type: 'custom',
201
+ options: {
202
+ validate: (value: unknown) => {
203
+ if (value !== 'A') {
204
+ return 'Vous devez sélectionner l\'option A'
205
+ }
206
+ return true
207
+ },
208
+ },
209
+ }
210
+
211
+ const successRule: ValidationRule = {
212
+ type: 'custom',
213
+ options: {
214
+ validate: (value: unknown) => value === 'A',
215
+ successMessage: 'Option A sélectionnée',
216
+ },
217
+ }
218
+
219
+ const wrapper = mount(SyCheckBoxGroup, {
220
+ props: {
221
+ 'modelValue': null,
222
+ 'customWarningRules': [warningRule],
223
+ 'customSuccessRules': [successRule],
224
+ 'showSuccessMessages': true,
225
+ 'isValidateOnBlur': false,
226
+ 'options': [
227
+ { label: 'Option A', value: 'A', id: 'opt-a' },
228
+ { label: 'Option B', value: 'B', id: 'opt-b' },
229
+ ],
230
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
231
+ },
232
+ })
233
+
234
+ // Sélectionner B devrait afficher un warning
235
+ await wrapper.setProps({ modelValue: 'B' })
236
+ await wrapper.vm.validateOnSubmit()
237
+ await nextTick()
238
+
239
+ expect(wrapper.text()).toContain('Vous devez sélectionner l\'option A')
240
+
241
+ // Sélectionner A devrait afficher un succès
242
+ await wrapper.setProps({ modelValue: 'A' })
243
+ await wrapper.vm.validateOnSubmit()
244
+ await nextTick()
245
+
246
+ expect(wrapper.text()).toContain('Option A sélectionnée')
247
+
248
+ const isValid = await wrapper.vm.validateOnSubmit()
249
+ expect(isValid).toBe(true)
250
+ })
251
+
252
+ it('should validate on selection change when isValidateOnBlur is false', async () => {
253
+ const wrapper = mount(SyCheckBoxGroup, {
254
+ props: {
255
+ 'modelValue': null,
256
+ 'required': true,
257
+ 'isValidateOnBlur': false,
258
+ 'options': [
259
+ { label: 'Option A', value: 'A', id: 'opt-a' },
260
+ { label: 'Option B', value: 'B', id: 'opt-b' },
261
+ ],
262
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
263
+ },
264
+ })
265
+
266
+ // Pas d'erreur au montage car pas de validation forcée
267
+ await nextTick()
268
+
269
+ // Sélectionner une option valide
270
+ await wrapper.setProps({ modelValue: 'A' })
271
+ await nextTick()
272
+
273
+ const isValid = await wrapper.vm.validateOnSubmit()
274
+ expect(isValid).toBe(true)
275
+ })
276
+
277
+ it('should handle useVuetifyValidation mode', async () => {
278
+ const wrapper = mount(SyCheckBoxGroup, {
279
+ props: {
280
+ 'modelValue': null,
281
+ 'required': true,
282
+ 'useVuetifyValidation': true,
283
+ 'rules': [(v: unknown) => !!v || 'Champ requis'],
284
+ 'options': [
285
+ { label: 'Option A', value: 'A', id: 'opt-a' },
286
+ ],
287
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
288
+ },
289
+ })
290
+
291
+ // Vérifier que la validation Vuetify est active
292
+ await nextTick()
293
+ const isValidInitial = await wrapper.vm.validateOnSubmit()
294
+ expect(isValidInitial).toBe(false)
295
+ expect(wrapper.text()).toContain('Champ requis')
296
+
297
+ // Sélectionner une option
298
+ await wrapper.setProps({ modelValue: 'A' })
299
+ const isValidAfter = await wrapper.vm.validateOnSubmit()
300
+ expect(isValidAfter).toBe(true)
301
+ })
302
+
303
+ it('should expose checkErrorOnBlur method', async () => {
304
+ const wrapper = mount(SyCheckBoxGroup, {
305
+ props: {
306
+ modelValue: null,
307
+ required: true,
308
+ isValidateOnBlur: true,
309
+ options: [
310
+ { label: 'Option A', value: 'A', id: 'opt-a' },
311
+ ],
312
+ },
313
+ })
314
+
315
+ // Vérifier que la méthode est exposée
316
+ expect(typeof wrapper.vm.checkErrorOnBlur).toBe('function')
317
+
318
+ // Appeler la méthode (simule le blur)
319
+ await wrapper.vm.checkErrorOnBlur()
320
+ await nextTick()
321
+
322
+ // Devrait afficher l'erreur car champ vide
323
+ expect(wrapper.text()).toContain('requis')
151
324
  })
152
325
  })
@@ -1,3 +1,5 @@
1
+ import type { FieldValidationProps, ValidationRule, VuetifyValidationRule } from '@/composables/unifyValidation/useValidation'
2
+
1
3
  export type Option = {
2
4
  label: string
3
5
  value: string | number
@@ -8,3 +10,50 @@ export type Option = {
8
10
  ariaLabel?: string
9
11
  title?: string
10
12
  }
13
+
14
+ /**
15
+ * Props du composant SyCheckBoxGroup
16
+ */
17
+ export interface SyCheckBoxGroupProps extends FieldValidationProps {
18
+ ariaLabel?: string
19
+ ariaLabelledby?: string
20
+ color?: string
21
+ density?: 'default' | 'comfortable' | 'compact'
22
+ displayAsterisk?: boolean
23
+ helpText?: string
24
+ hideDetails?: boolean | 'auto'
25
+ id?: string
26
+ label?: string
27
+ modelValue?: (string | number) | (string | number)[] | null
28
+ multiple?: boolean
29
+ name?: string
30
+ options?: Option[]
31
+ title?: string
32
+ }
33
+
34
+ /**
35
+ * Props de validation étendant FieldValidationProps du système unifié
36
+ */
37
+ export interface SyCheckBoxGroupValidationProps extends FieldValidationProps {
38
+ modelValue?: (string | number) | (string | number)[] | null
39
+ multiple?: boolean
40
+ required?: boolean
41
+ readonly?: boolean
42
+ disabled?: boolean
43
+ customRules?: ValidationRule[]
44
+ customWarningRules?: ValidationRule[]
45
+ customSuccessRules?: ValidationRule[]
46
+ isValidateOnBlur?: boolean
47
+ showSuccessMessages?: boolean
48
+ useVuetifyValidation?: boolean
49
+ rules?: VuetifyValidationRule[]
50
+ errorMessages?: string[] | null
51
+ warningMessages?: string[] | null
52
+ successMessages?: string[] | null
53
+ hasError?: boolean
54
+ hasWarning?: boolean
55
+ hasSuccess?: boolean
56
+ maxErrors?: number
57
+ disableErrorHandling?: boolean
58
+ fieldIdentifier?: string
59
+ }
@@ -2,11 +2,7 @@ import type { Meta, StoryObj } from '@storybook/vue3'
2
2
  import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue'
3
3
  import { ref, watch } from 'vue'
4
4
  import { fn } from '@storybook/test'
5
-
6
- // Interface pour typer correctement le composant SyCheckbox avec sa méthode validateOnSubmit
7
- interface SyCheckboxInstance {
8
- validateOnSubmit: () => Promise<boolean>
9
- }
5
+ import { getValidationDocumentation } from '@/composables/unifyValidation/documentationValidationProps'
10
6
 
11
7
  const meta = {
12
8
  title: 'Composants/Formulaires/SyCheckbox',
@@ -26,11 +22,16 @@ const meta = {
26
22
  },
27
23
  },
28
24
  argTypes: {
25
+ ...getValidationDocumentation(),
29
26
  modelValue: { control: 'boolean' },
30
27
  label: {
31
28
  description: 'Texte affiché comme label de la case à cocher',
32
29
  control: 'text',
33
30
  },
31
+ helpText: {
32
+ description: 'Texte d\'aide affiché sous la case (masqué quand un message de validation est présent)',
33
+ control: 'text',
34
+ },
34
35
  color: {
35
36
  control: 'select',
36
37
  options: ['primary', 'success', 'error', 'warning'],
@@ -202,6 +203,41 @@ Cette case à cocher est dans un état indéterminé, généralement utilisé lo
202
203
  },
203
204
  }
204
205
 
206
+ export const HelpText: Story = {
207
+ args: {
208
+ ...Default.args,
209
+ helpText: 'Cochez cette case pour accepter les conditions générales.',
210
+ },
211
+ render: args => ({
212
+ components: { SyCheckbox },
213
+ setup() {
214
+ const checked = ref(false)
215
+ return { args, checked }
216
+ },
217
+ template: `<SyCheckbox v-model="checked" v-bind="args" label="Case à cocher" />`,
218
+ }),
219
+ parameters: {
220
+ sourceCode: [
221
+ {
222
+ name: 'Template',
223
+ code: `<SyCheckbox
224
+ v-model="checked"
225
+ label="Case à cocher"
226
+ help-text="Cochez cette case pour accepter les conditions générales."
227
+ />`,
228
+ },
229
+ ],
230
+ docs: {
231
+ description: {
232
+ story: `
233
+ ### Case à cocher avec texte d'aide
234
+ Un texte d'aide (\`helpText\`) s'affiche sous la case pour guider l'utilisateur, tant qu'aucun message de validation (erreur, avertissement, succès) n'est présent.
235
+ `,
236
+ },
237
+ },
238
+ },
239
+ }
240
+
205
241
  export const WithControlsIds: Story = {
206
242
  parameters: {
207
243
  sourceCode: [
@@ -640,159 +676,3 @@ Le composant SyCheckbox peut être personnalisé avec différentes couleurs pour
640
676
  `,
641
677
  }),
642
678
  }
643
-
644
- export const FormValidation: Story = {
645
- parameters: {
646
- sourceCode: [
647
- {
648
- name: 'Template',
649
- code: `
650
- <template>
651
- <form @submit.prevent="validateForm">
652
- <h3>Validation avec règles personnalisées</h3>
653
- <SyCheckbox
654
- ref="checkbox"
655
- v-model="checked"
656
- label="J'accepte les conditions générales d'utilisation"
657
- :custom-rules="rules"
658
- validate-on-submit
659
- />
660
- <h3>Validation avec la prop required</h3>
661
- <SyCheckbox
662
- ref="checkbox2"
663
- v-model="checked2"
664
- label="J'accepte les conditions générales d'utilisation"
665
- display-asterisk
666
- required
667
- />
668
- <VBtn
669
- type="submit"
670
- color="primary"
671
- class="mt-4"
672
- >
673
- Soumettre
674
- </VBtn>
675
- <p v-if="formSubmitted" style="margin-top: 16px; color: var(--v-success-base);">Formulaire soumis avec succès!</p>
676
- </form>
677
- </template>
678
-
679
- <script setup lang="ts">
680
- import { ref, watch } from 'vue'
681
-
682
- const checkbox = ref<SyCheckboxInstance | null>(null)
683
- const checkbox2 = ref<SyCheckboxInstance | null>(null)
684
- const checked = ref(false)
685
- const checked2 = ref(false)
686
- const formSubmitted = ref(false)
687
- const hasError = ref(false)
688
-
689
- const rules = [
690
- {
691
- type: 'custom',
692
- options: {
693
- message: 'Cette case doit être cochée pour continuer.',
694
- validate: (value: boolean) => value === true,
695
- },
696
- },
697
- ]
698
-
699
- const validateForm = async (): Promise<void> => {
700
- if (!checkbox.value || !checkbox2.value) return
701
- hasError.value = true
702
- const isValid = await checkbox.value.validateOnSubmit()
703
- const isValid2 = await checkbox2.value.validateOnSubmit()
704
- if (isValid && isValid2) {
705
- formSubmitted.value = true
706
- hasError.value = false
707
- }
708
- }
709
- </script>`,
710
- },
711
- ],
712
- docs: {
713
- description: {
714
- story: `
715
- ### Case à cocher avec validation au moment de la soumission
716
- Cette case à cocher utilise des règles de validation personnalisées et valide le formulaire lors de la soumission grâce à la propriété \`validateOnSubmit\`. Le bouton de soumission déclenche la validation et affiche un message de succès si la case est cochée.
717
- `,
718
- },
719
- },
720
- },
721
- render: args => ({
722
- components: { SyCheckbox },
723
- setup() {
724
- const checkbox = ref<SyCheckboxInstance | null>(null)
725
- const checkbox2 = ref<SyCheckboxInstance | null>(null)
726
- const checked = ref(false)
727
- const checked2 = ref(false)
728
- const formSubmitted = ref(false)
729
- const hasError = ref(false)
730
-
731
- // Revalider quand les valeurs changent
732
- watch([checked, checked2], async () => {
733
- if (hasError.value && checkbox.value && checkbox2.value) {
734
- await checkbox.value.validateOnSubmit()
735
- await checkbox2.value.validateOnSubmit()
736
- }
737
- })
738
-
739
- const validateForm = async (): Promise<void> => {
740
- if (!checkbox.value || !checkbox2.value) return
741
- hasError.value = true
742
- const isValid = await checkbox.value.validateOnSubmit()
743
- const isValid2 = await checkbox2.value.validateOnSubmit()
744
- if (isValid && isValid2) {
745
- formSubmitted.value = true
746
- hasError.value = false
747
- }
748
- }
749
-
750
- return {
751
- args,
752
- checkbox,
753
- checked,
754
- checkbox2,
755
- checked2,
756
- formSubmitted,
757
- hasError,
758
- rules: [
759
- {
760
- type: 'custom',
761
- options: {
762
- message: 'Cette case doit être cochée pour continuer.',
763
- validate: (value: boolean) => value === true,
764
- },
765
- },
766
- ],
767
- validateForm,
768
- }
769
- },
770
- template: `
771
- <form @submit.prevent="validateForm">
772
- <h3>Validation avec règles personnalisées</h3>
773
- <SyCheckbox
774
- ref="checkbox"
775
- v-model="checked"
776
- label="J'accepte les conditions générales d'utilisation"
777
- :custom-rules="rules"
778
- />
779
- <h3>Validation avec la prop required et display-asterisk</h3>
780
- <SyCheckbox
781
- ref="checkbox2"
782
- v-model="checked2"
783
- label="J'accepte les conditions générales d'utilisation"
784
- required
785
- display-asterisk
786
- />
787
- <VBtn
788
- type="submit"
789
- color="primary"
790
- class="mt-4"
791
- >
792
- Soumettre
793
- </VBtn>
794
- <p v-if="formSubmitted" style="margin-top: 16px; color: var(--v-success-base);">Formulaire soumis avec succès!</p>
795
- </form>
796
- `,
797
- }),
798
- }