@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
@@ -53,10 +53,10 @@ describe('LunarCalendar', () => {
53
53
  },
54
54
  })
55
55
 
56
- const input = wrapper.find('input')
57
- await input.setValue('10/19/1995')
58
- await input.trigger('blur')
56
+ await (wrapper.vm.validateOnSubmit as () => Promise<boolean>)()
59
57
  await flushPromises()
58
+ await wrapper.vm.$nextTick()
59
+ await wrapper.vm.$nextTick()
60
60
 
61
61
  expect(wrapper.html()).toContain('L\'année doit être supérieure ou égale à 1996.')
62
62
  })
@@ -70,12 +70,203 @@ describe('LunarCalendar', () => {
70
70
  },
71
71
  })
72
72
 
73
- const input = wrapper.find('input')
74
- await input.setValue('10/19/1995')
75
- await input.trigger('blur')
73
+ await (wrapper.vm.validateOnSubmit as () => Promise<boolean>)()
76
74
  await flushPromises()
75
+ await wrapper.vm.$nextTick()
76
+ await wrapper.vm.$nextTick()
77
77
 
78
78
  expect(wrapper.html()).toContain('L\'année doit être inférieure ou égale à 1994.')
79
79
  })
80
+
81
+ it('displays success messages when showSuccessMessages is true', async () => {
82
+ const successRule = {
83
+ type: 'custom',
84
+ options: {
85
+ validate: (value: string) => {
86
+ const regex = /^\d{2}\/\d{2}\/\d{4}$/
87
+ return regex.test(value)
88
+ },
89
+ successMessage: 'Date format valide',
90
+ },
91
+ }
92
+
93
+ const wrapper = mount(LunarCalendar, {
94
+ props: {
95
+ label: 'Date de naissance',
96
+ modelValue: '10/19/1995',
97
+ showSuccessMessages: true,
98
+ customSuccessRules: [successRule],
99
+ },
100
+ })
101
+
102
+ await (wrapper.vm.validateOnSubmit as () => Promise<boolean>)()
103
+ await flushPromises()
104
+ await wrapper.vm.$nextTick()
105
+
106
+ expect(wrapper.html()).toContain('Date format valide')
107
+ })
108
+
109
+ it('displays success messages when showSuccessMessages is true', async () => {
110
+ const successRule = {
111
+ type: 'custom',
112
+ options: {
113
+ validate: (value: string) => {
114
+ const regex = /^\d{2}\/\d{2}\/\d{4}$/
115
+ return regex.test(value)
116
+ },
117
+ successMessage: 'Date format valide',
118
+ },
119
+ }
120
+
121
+ const wrapper = mount(LunarCalendar, {
122
+ props: {
123
+ label: 'Date de naissance',
124
+ modelValue: '10/19/1995',
125
+ showSuccessMessages: true,
126
+ customSuccessRules: [successRule],
127
+ },
128
+ })
129
+
130
+ await (wrapper.vm.validateOnSubmit as unknown as () => Promise<boolean>)()
131
+ await flushPromises()
132
+ await wrapper.vm.$nextTick()
133
+
134
+ expect(wrapper.html()).toContain('Date format valide')
135
+ })
136
+ })
137
+
138
+ describe('new props iso SyTextField', () => {
139
+ it('renders with helpText', () => {
140
+ const wrapper = mount(LunarCalendar, {
141
+ props: {
142
+ label: 'Date de naissance',
143
+ modelValue: '10/19/1995',
144
+ helpText: 'Format attendu : JJ/MM/AAAA',
145
+ },
146
+ })
147
+
148
+ expect(wrapper.html()).toContain('Format attendu : JJ/MM/AAAA')
149
+ })
150
+
151
+ it('renders with noIcon', () => {
152
+ const wrapper = mount(LunarCalendar, {
153
+ props: {
154
+ label: 'Date de naissance',
155
+ modelValue: '10/19/1995',
156
+ noIcon: true,
157
+ },
158
+ })
159
+
160
+ // Vérifie que l'icône n'est pas présente
161
+ expect(wrapper.findComponent({ name: 'SyIcon' }).exists()).toBe(false)
162
+ })
163
+
164
+ it('renders with displayAsterisk when required', () => {
165
+ const wrapper = mount(LunarCalendar, {
166
+ props: {
167
+ label: 'Date de naissance',
168
+ modelValue: '',
169
+ required: true,
170
+ displayAsterisk: true,
171
+ },
172
+ })
173
+
174
+ // Vérifie que l'astérisque est présent dans le label
175
+ expect(wrapper.html()).toContain('*')
176
+ })
177
+
178
+ it('renders with loading state', () => {
179
+ const wrapper = mount(LunarCalendar, {
180
+ props: {
181
+ label: 'Date de naissance',
182
+ modelValue: '10/19/1995',
183
+ loading: true,
184
+ },
185
+ })
186
+
187
+ // Vérifie que le champ a l'attribut loading ou la classe correspondante
188
+ expect(wrapper.findComponent({ name: 'SyTextField' }).props('loading')).toBe(true)
189
+ })
190
+
191
+ it('renders with disabled state', () => {
192
+ const wrapper = mount(LunarCalendar, {
193
+ props: {
194
+ label: 'Date de naissance',
195
+ modelValue: '10/19/1995',
196
+ disabled: true,
197
+ },
198
+ })
199
+
200
+ const input = wrapper.find('input')
201
+ expect(input.attributes('disabled')).toBeDefined()
202
+ })
203
+
204
+ it('renders with readonly state', () => {
205
+ const wrapper = mount(LunarCalendar, {
206
+ props: {
207
+ label: 'Date de naissance',
208
+ modelValue: '10/19/1995',
209
+ readonly: true,
210
+ },
211
+ })
212
+
213
+ const input = wrapper.find('input')
214
+ expect(input.attributes('readonly')).toBeDefined()
215
+ })
216
+
217
+ it('renders with custom variantStyle', () => {
218
+ const wrapper = mount(LunarCalendar, {
219
+ props: {
220
+ label: 'Date de naissance',
221
+ modelValue: '10/19/1995',
222
+ variantStyle: 'filled',
223
+ },
224
+ })
225
+
226
+ expect(wrapper.findComponent({ name: 'SyTextField' }).props('variantStyle')).toBe('filled')
227
+ })
228
+
229
+ it('renders with custom color', () => {
230
+ const wrapper = mount(LunarCalendar, {
231
+ props: {
232
+ label: 'Date de naissance',
233
+ modelValue: '10/19/1995',
234
+ color: 'secondary',
235
+ },
236
+ })
237
+
238
+ expect(wrapper.findComponent({ name: 'SyTextField' }).props('color')).toBe('secondary')
239
+ })
240
+
241
+ it('renders with custom density', () => {
242
+ const wrapper = mount(LunarCalendar, {
243
+ props: {
244
+ label: 'Date de naissance',
245
+ modelValue: '10/19/1995',
246
+ density: 'compact',
247
+ },
248
+ })
249
+
250
+ expect(wrapper.findComponent({ name: 'SyTextField' }).props('density')).toBe('compact')
251
+ })
252
+
253
+ it('renders with hint when focused', async () => {
254
+ const wrapper = mount(LunarCalendar, {
255
+ props: {
256
+ label: 'Date de naissance',
257
+ modelValue: '10/19/1995',
258
+ hint: 'Ceci est un hint',
259
+ },
260
+ })
261
+
262
+ // Le hint s'affiche quand le champ est focus
263
+ await wrapper.find('input').trigger('focus')
264
+ await flushPromises()
265
+ await wrapper.vm.$nextTick()
266
+ await wrapper.vm.$nextTick()
267
+ await wrapper.vm.$nextTick()
268
+
269
+ expect(wrapper.html()).toContain('Ceci est un hint')
270
+ })
80
271
  })
81
272
  })
@@ -0,0 +1,287 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { ref, nextTick } from 'vue'
3
+ import { useLunarCalendarValidation } from '../useLunarCalendarValidation'
4
+ import type { LunarCalendarProps } from '../types'
5
+
6
+ function createProps(overrides: Partial<LunarCalendarProps> = {}): LunarCalendarProps {
7
+ return {
8
+ label: 'Date de naissance',
9
+ placeholder: undefined,
10
+ isClearable: false,
11
+ displayPrependIcon: true,
12
+ displayAppendIcon: false,
13
+ minYear: undefined,
14
+ maxYear: undefined,
15
+ // FieldValidationProps defaults
16
+ required: false,
17
+ errorMessages: null,
18
+ warningMessages: null,
19
+ successMessages: null,
20
+ readonly: false,
21
+ disabled: false,
22
+ customRules: [],
23
+ customWarningRules: [],
24
+ customSuccessRules: [],
25
+ showSuccessMessages: false,
26
+ isValidateOnBlur: true,
27
+ ...overrides,
28
+ }
29
+ }
30
+
31
+ describe('useLunarCalendarValidation', () => {
32
+ describe('règle de format DD/MM/YYYY', () => {
33
+ it('ne retourne pas d\'erreur si la valeur est vide', async () => {
34
+ const modelValue = ref('')
35
+ const props = createProps()
36
+ const validation = useLunarCalendarValidation(modelValue, props)
37
+
38
+ await validation.validate()
39
+ await nextTick()
40
+
41
+ expect(validation.errors.value).toHaveLength(0)
42
+ })
43
+
44
+ it('accepte une date au format DD/MM/YYYY', async () => {
45
+ const modelValue = ref('25/12/2000')
46
+ const props = createProps()
47
+ const validation = useLunarCalendarValidation(modelValue, props)
48
+
49
+ await validation.validate()
50
+ await nextTick()
51
+
52
+ expect(validation.errors.value).toHaveLength(0)
53
+ })
54
+
55
+ it('retourne une erreur si le format est invalide', async () => {
56
+ const modelValue = ref('25122000')
57
+ const props = createProps()
58
+ const validation = useLunarCalendarValidation(modelValue, props)
59
+
60
+ await validation.validate()
61
+ await nextTick()
62
+
63
+ expect(validation.errors.value).toContain('La date est invalide.')
64
+ expect(validation.hasError.value).toBe(true)
65
+ })
66
+
67
+ it('retourne une erreur si la date est incomplète', async () => {
68
+ const modelValue = ref('25/12/200')
69
+ const props = createProps()
70
+ const validation = useLunarCalendarValidation(modelValue, props)
71
+
72
+ await validation.validate()
73
+ await nextTick()
74
+
75
+ expect(validation.errors.value).toContain('La date est invalide.')
76
+ })
77
+ })
78
+
79
+ describe('règle required', () => {
80
+ it('ne retourne pas d\'erreur si non requis et vide', async () => {
81
+ const modelValue = ref('')
82
+ const props = createProps({ required: false })
83
+ const validation = useLunarCalendarValidation(modelValue, props)
84
+
85
+ await validation.validate()
86
+ await nextTick()
87
+
88
+ expect(validation.errors.value).toHaveLength(0)
89
+ })
90
+
91
+ it('retourne une erreur si requis et vide', async () => {
92
+ const modelValue = ref('')
93
+ const props = createProps({ required: true, label: 'Date' })
94
+ const validation = useLunarCalendarValidation(modelValue, props)
95
+
96
+ await validation.validate()
97
+ await nextTick()
98
+
99
+ expect(validation.errors.value).toContain('Le champ Date est requis.')
100
+ expect(validation.hasError.value).toBe(true)
101
+ })
102
+
103
+ it('utilise le label dans le message d\'erreur', async () => {
104
+ const modelValue = ref('')
105
+ const props = createProps({ required: true, label: 'Date de naissance' })
106
+ const validation = useLunarCalendarValidation(modelValue, props)
107
+
108
+ await validation.validate()
109
+ await nextTick()
110
+
111
+ expect(validation.errors.value).toContain('Le champ Date de naissance est requis.')
112
+ })
113
+ })
114
+
115
+ describe('règle minYear', () => {
116
+ it('retourne une erreur si l\'année est inférieure à minYear', async () => {
117
+ const modelValue = ref('25/12/1999')
118
+ const props = createProps({ minYear: 2000 })
119
+ const validation = useLunarCalendarValidation(modelValue, props)
120
+
121
+ await validation.validate()
122
+ await nextTick()
123
+
124
+ expect(validation.errors.value).toContain('L\'année doit être supérieure ou égale à 2000.')
125
+ expect(validation.hasError.value).toBe(true)
126
+ })
127
+
128
+ it('accepte l\'année égale à minYear', async () => {
129
+ const modelValue = ref('25/12/2000')
130
+ const props = createProps({ minYear: 2000 })
131
+ const validation = useLunarCalendarValidation(modelValue, props)
132
+
133
+ await validation.validate()
134
+ await nextTick()
135
+
136
+ expect(validation.errors.value).toHaveLength(0)
137
+ })
138
+
139
+ it('accepte l\'année supérieure à minYear', async () => {
140
+ const modelValue = ref('25/12/2020')
141
+ const props = createProps({ minYear: 2000 })
142
+ const validation = useLunarCalendarValidation(modelValue, props)
143
+
144
+ await validation.validate()
145
+ await nextTick()
146
+
147
+ expect(validation.errors.value).toHaveLength(0)
148
+ })
149
+
150
+ it('ignore minYear si le format est invalide', async () => {
151
+ const modelValue = ref('invalid')
152
+ const props = createProps({ minYear: 2000 })
153
+ const validation = useLunarCalendarValidation(modelValue, props)
154
+
155
+ await validation.validate()
156
+ await nextTick()
157
+
158
+ // L'erreur de format est présente mais pas celle de minYear
159
+ expect(validation.errors.value).toContain('La date est invalide.')
160
+ expect(validation.errors.value).not.toContain('L\'année doit être supérieure ou égale à 2000.')
161
+ })
162
+ })
163
+
164
+ describe('règle maxYear', () => {
165
+ it('retourne une erreur si l\'année est supérieure à maxYear', async () => {
166
+ const modelValue = ref('25/12/2021')
167
+ const props = createProps({ maxYear: 2020 })
168
+ const validation = useLunarCalendarValidation(modelValue, props)
169
+
170
+ await validation.validate()
171
+ await nextTick()
172
+
173
+ expect(validation.errors.value).toContain('L\'année doit être inférieure ou égale à 2020.')
174
+ expect(validation.hasError.value).toBe(true)
175
+ })
176
+
177
+ it('accepte l\'année égale à maxYear', async () => {
178
+ const modelValue = ref('25/12/2020')
179
+ const props = createProps({ maxYear: 2020 })
180
+ const validation = useLunarCalendarValidation(modelValue, props)
181
+
182
+ await validation.validate()
183
+ await nextTick()
184
+
185
+ expect(validation.errors.value).toHaveLength(0)
186
+ })
187
+
188
+ it('accepte l\'année inférieure à maxYear', async () => {
189
+ const modelValue = ref('25/12/2010')
190
+ const props = createProps({ maxYear: 2020 })
191
+ const validation = useLunarCalendarValidation(modelValue, props)
192
+
193
+ await validation.validate()
194
+ await nextTick()
195
+
196
+ expect(validation.errors.value).toHaveLength(0)
197
+ })
198
+ })
199
+
200
+ describe('règles minYear ET maxYear combinées', () => {
201
+ it('retourne une erreur si l\'année est hors plage (inférieure)', async () => {
202
+ const modelValue = ref('25/12/1999')
203
+ const props = createProps({ minYear: 2000, maxYear: 2020 })
204
+ const validation = useLunarCalendarValidation(modelValue, props)
205
+
206
+ await validation.validate()
207
+ await nextTick()
208
+
209
+ expect(validation.errors.value).toContain('L\'année doit être comprise entre 2000 et 2020.')
210
+ expect(validation.hasError.value).toBe(true)
211
+ })
212
+
213
+ it('retourne une erreur si l\'année est hors plage (supérieure)', async () => {
214
+ const modelValue = ref('25/12/2021')
215
+ const props = createProps({ minYear: 2000, maxYear: 2020 })
216
+ const validation = useLunarCalendarValidation(modelValue, props)
217
+
218
+ await validation.validate()
219
+ await nextTick()
220
+
221
+ expect(validation.errors.value).toContain('L\'année doit être comprise entre 2000 et 2020.')
222
+ expect(validation.hasError.value).toBe(true)
223
+ })
224
+
225
+ it('accepte une date dans la plage', async () => {
226
+ const modelValue = ref('25/12/2010')
227
+ const props = createProps({ minYear: 2000, maxYear: 2020 })
228
+ const validation = useLunarCalendarValidation(modelValue, props)
229
+
230
+ await validation.validate()
231
+ await nextTick()
232
+
233
+ expect(validation.errors.value).toHaveLength(0)
234
+ })
235
+ })
236
+
237
+ describe('clearValidation', () => {
238
+ it('efface les erreurs après clearValidation', async () => {
239
+ const modelValue = ref('invalid')
240
+ const props = createProps()
241
+ const validation = useLunarCalendarValidation(modelValue, props)
242
+
243
+ await validation.validate()
244
+ await nextTick()
245
+ expect(validation.errors.value.length).toBeGreaterThan(0)
246
+
247
+ validation.clearValidation()
248
+ await nextTick()
249
+
250
+ expect(validation.errors.value).toHaveLength(0)
251
+ expect(validation.hasError.value).toBe(false)
252
+ })
253
+ })
254
+
255
+ describe('validate return value', () => {
256
+ it('retourne true si la validation réussit', async () => {
257
+ const modelValue = ref('25/12/2000')
258
+ const props = createProps()
259
+ const validation = useLunarCalendarValidation(modelValue, props)
260
+
261
+ const result = await validation.validate()
262
+
263
+ expect(result).toBe(true)
264
+ })
265
+
266
+ it('retourne false si la validation échoue', async () => {
267
+ const modelValue = ref('invalid')
268
+ const props = createProps()
269
+ const validation = useLunarCalendarValidation(modelValue, props)
270
+
271
+ const result = await validation.validate()
272
+
273
+ expect(result).toBe(false)
274
+ })
275
+ })
276
+
277
+ describe('focused ref', () => {
278
+ it('exposed focused ref', () => {
279
+ const modelValue = ref('')
280
+ const props = createProps()
281
+ const validation = useLunarCalendarValidation(modelValue, props)
282
+
283
+ expect(validation.focused).toBeDefined()
284
+ expect(validation.focused.value).toBe(false)
285
+ })
286
+ })
287
+ })
@@ -0,0 +1,39 @@
1
+ import type { FieldValidationProps } from '@/composables/unifyValidation/useValidation'
2
+
3
+ export type IconType = 'info' | 'success' | 'warning' | 'error' | 'close' | 'calendar' | undefined
4
+ export type VariantStyle = 'outlined' | 'plain' | 'underlined' | 'filled' | 'solo' | 'solo-inverted' | 'solo-filled'
5
+ export type ColorType = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error'
6
+ export type DensityType = 'default' | 'comfortable' | 'compact'
7
+
8
+ // On extrait modelValue car on utilise defineModel
9
+ export type LunarCalendarProps = {
10
+ label: string
11
+ placeholder?: string
12
+ isClearable?: boolean
13
+ displayPrependIcon?: boolean
14
+ displayAppendIcon?: boolean
15
+ minYear?: number
16
+ maxYear?: number
17
+ // Props iso avec SyTextField
18
+ helpText?: string
19
+ noIcon?: boolean
20
+ displayAsterisk?: boolean
21
+ prependTooltip?: string
22
+ appendTooltip?: string
23
+ tooltipLocation?: 'top' | 'bottom' | 'start' | 'end'
24
+ variantStyle?: VariantStyle
25
+ color?: ColorType
26
+ density?: DensityType
27
+ loading?: boolean | string
28
+ hint?: string
29
+ bgColor?: string
30
+ baseColor?: string
31
+ counter?: string | number | boolean
32
+ id?: string
33
+ name?: string
34
+ autocomplete?: string
35
+ disabled?: boolean
36
+ readonly?: boolean
37
+ required?: boolean
38
+ hideDetails?: boolean | 'auto'
39
+ } & Omit<FieldValidationProps, 'modelValue'>
@@ -1,46 +1,122 @@
1
- import { useValidatable } from '@/composables/validation/useValidatable'
2
- import { useValidation } from '@/composables/validation/useValidation'
3
- import type { MaybeRefOrGetter } from 'vue'
4
- import { toValue, type ComputedRef } from 'vue'
5
- import { useLunarCalendarRules } from './useLunarCalendarRules'
6
-
7
- export function useLunarCalendarValidation(
8
- modelValue: ComputedRef<string | undefined>,
9
- label: MaybeRefOrGetter<string | undefined>,
10
- successMessage: MaybeRefOrGetter<string | undefined>,
11
- required: MaybeRefOrGetter<boolean | undefined>,
12
- minYear: MaybeRefOrGetter<number | undefined>,
13
- maxYear: MaybeRefOrGetter<number | undefined>,
14
- ) {
15
- const { rules } = useLunarCalendarRules(
16
- successMessage,
17
- required,
18
- minYear,
19
- maxYear,
20
- )
1
+ import { computed, ref, toValue, type Ref } from 'vue'
2
+ import { useValidation, type ValidationRule } from '@/composables/unifyValidation/useValidation'
3
+ import type { LunarCalendarProps } from './types'
21
4
 
22
- const validation = useValidation({
23
- showSuccessMessages: successMessage !== undefined,
24
- fieldIdentifier: toValue(label),
25
- })
5
+ function getYearFromModel(model: string): number | null {
6
+ const parts = model.split('/')
7
+ if (parts.length !== 3 || parts[2]?.length !== 4 || isNaN(Number(parts[2]))) {
8
+ return null
9
+ }
10
+ return Number(parts[2])
11
+ }
26
12
 
27
- async function validateOnSubmit() {
28
- const result = await validation.validateField(
29
- modelValue.value,
30
- rules.value,
31
- )
13
+ export function useLunarCalendarValidation(modelValue: Ref<string | undefined>, props: LunarCalendarProps) {
14
+ const focused = ref(false)
32
15
 
33
- return !result.hasError
34
- }
16
+ const customRules = computed<ValidationRule[]>(() => {
17
+ const rules: ValidationRule[] = []
35
18
 
36
- useValidatable(validateOnSubmit, validation.clearValidation)
19
+ rules.push({
20
+ type: 'custom',
21
+ options: {
22
+ validate: (value: string) => {
23
+ if (!value) return true
24
+ const regex = /^\d{2}\/\d{2}\/\d{4}$/
25
+ return regex.test(value)
26
+ },
27
+ message: 'La date est invalide.',
28
+ },
29
+ })
37
30
 
38
- async function validate() {
39
- return await validation.validateField(
40
- modelValue.value,
41
- rules.value,
42
- )
43
- }
31
+ const minYear = toValue(props.minYear)
32
+ const maxYear = toValue(props.maxYear)
33
+
34
+ if (minYear !== undefined && maxYear !== undefined) {
35
+ rules.push({
36
+ type: 'custom',
37
+ options: {
38
+ validate: (value: string) => {
39
+ const year = getYearFromModel(value)
40
+ if (year === null) return true
41
+ return year >= minYear && year <= maxYear
42
+ },
43
+ message: `L'année doit être comprise entre ${minYear} et ${maxYear}.`,
44
+ },
45
+ })
46
+ }
47
+ else if (minYear !== undefined) {
48
+ rules.push({
49
+ type: 'custom',
50
+ options: {
51
+ validate: (value: string) => {
52
+ const year = getYearFromModel(value)
53
+ if (year === null) return true
54
+ return year >= minYear
55
+ },
56
+ message: `L'année doit être supérieure ou égale à ${minYear}.`,
57
+ },
58
+ })
59
+ }
60
+ else if (maxYear !== undefined) {
61
+ rules.push({
62
+ type: 'custom',
63
+ options: {
64
+ validate: (value: string) => {
65
+ const year = getYearFromModel(value)
66
+ if (year === null) return true
67
+ return year <= maxYear
68
+ },
69
+ message: `L'année doit être inférieure ou égale à ${maxYear}.`,
70
+ },
71
+ })
72
+ }
44
73
 
45
- return { ...validation, validate }
74
+ return rules
75
+ })
76
+
77
+ const defaultRules = computed<ValidationRule[]>(() => props.required
78
+ ? [{
79
+ type: 'required',
80
+ options: {
81
+ message: `Le champ ${props.label || 'ce champ'} est requis.`,
82
+ fieldIdentifier: props.label,
83
+ },
84
+ }]
85
+ : [],
86
+ )
87
+
88
+ const { validate, clearValidation, errors, warnings, successes, hasError, hasWarning, hasSuccess } = useValidation({
89
+ modelValue,
90
+ readonly: computed(() => props.readonly ?? false),
91
+ disabled: computed(() => props.disabled ?? false),
92
+ required: computed(() => props.required ?? false),
93
+ isValidateOnBlur: computed(() => props.isValidateOnBlur ?? true),
94
+ showSuccessMessages: computed(() => props.showSuccessMessages ?? false),
95
+ disableErrorHandling: computed(() => props.disableErrorHandling ?? false),
96
+ useVuetifyValidation: false,
97
+ label: computed(() => props.label),
98
+ customRules: computed(() => [...defaultRules.value, ...customRules.value]),
99
+ customWarningRules: computed(() => props.customWarningRules ?? []),
100
+ customSuccessRules: computed(() => props.customSuccessRules ?? []),
101
+ errorMessages: computed(() => props.errorMessages ?? []),
102
+ warningMessages: computed(() => props.warningMessages ?? []),
103
+ successMessages: computed(() => props.successMessages ?? []),
104
+ hasErrorProp: computed(() => props.hasError ?? false),
105
+ hasWarningProp: computed(() => props.hasWarning ?? false),
106
+ hasSuccessProp: computed(() => props.hasSuccess ?? false),
107
+ maxErrors: computed(() => props.maxErrors ?? 1),
108
+ focused,
109
+ })
110
+
111
+ return {
112
+ focused,
113
+ validate,
114
+ clearValidation,
115
+ errors,
116
+ warnings,
117
+ successes,
118
+ hasError,
119
+ hasWarning,
120
+ hasSuccess,
121
+ }
46
122
  }