@cnamts/synapse 1.0.1 → 1.0.2

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 (217) hide show
  1. package/README.md +1 -1
  2. package/dist/{DateFilter-BmRuzQ9Z.js → DateFilter-YWOTbfeL.js} +1 -1
  3. package/dist/{NumberFilter-CnIPDHqx.js → NumberFilter-DMmMgALM.js} +1 -1
  4. package/dist/{PeriodFilter-CZwZ8CnQ.js → PeriodFilter-Bok5BHcn.js} +1 -1
  5. package/dist/SelectFilter-BKud2WhN.js +136 -0
  6. package/dist/{TextFilter-DTxZHJwX.js → TextFilter-DvMf2thH.js} +1 -1
  7. package/dist/components/Accordion/Accordion.d.ts +2 -1
  8. package/dist/components/Accordion/composables/useAccordionGroupCommunication.d.ts +5 -0
  9. package/dist/components/Accordion/composables/useAccordionKeyboardNavigation.d.ts +12 -0
  10. package/dist/components/Accordion/composables/useAccordionState.d.ts +13 -0
  11. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +85 -0
  12. package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
  13. package/dist/components/Customs/SySelect/SySelect.d.ts +33 -13
  14. package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -2
  15. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +1585 -1452
  16. package/dist/components/DatePicker/DatePicker/DatePicker.d.ts +16 -2
  17. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +3 -1
  18. package/dist/components/DatePicker/composables/index.d.ts +2 -0
  19. package/dist/components/DatePicker/composables/useAsteriskDisplay.d.ts +14 -0
  20. package/dist/components/DatePicker/composables/useDateAutoClamp.d.ts +16 -0
  21. package/dist/components/DatePicker/composables/useDateRangeInput.d.ts +1 -1
  22. package/dist/components/DatePicker/composables/useDisplayedDateString.d.ts +3 -0
  23. package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +1 -0
  24. package/dist/components/DatePicker/composables/useMonthButtonCustomization.d.ts +5 -2
  25. package/dist/components/NirField/NirField.d.ts +7 -3
  26. package/dist/components/NirField/nirValidation.d.ts +1 -1
  27. package/dist/components/PasswordField/PasswordField.d.ts +2 -0
  28. package/dist/components/PeriodField/PeriodField.d.ts +52 -8
  29. package/dist/components/PhoneField/PhoneField.d.ts +2 -2
  30. package/dist/components/RangeField/RangeField.d.ts +2 -0
  31. package/dist/components/SearchListField/SearchListField.d.ts +9 -0
  32. package/dist/components/SyTextArea/SyTextArea.d.ts +2 -0
  33. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +14 -9
  34. package/dist/components/Tables/SyTable/SyTable.d.ts +12 -7
  35. package/dist/components/Tables/common/SyTablePagination.d.ts +1636 -0
  36. package/dist/components/Tables/common/TableHeader.d.ts +2 -20
  37. package/dist/components/Tables/common/filters/SelectFilter.d.ts +5 -5
  38. package/dist/components/Tables/common/filters/getFilterComponent.d.ts +1 -0
  39. package/dist/components/Tables/common/filters/locales.d.ts +4 -0
  40. package/dist/components/Tables/common/filters/logics/date.d.ts +1 -0
  41. package/dist/components/Tables/common/filters/logics/number.d.ts +1 -0
  42. package/dist/components/Tables/common/filters/logics/period.d.ts +1 -0
  43. package/dist/components/Tables/common/filters/logics/select.d.ts +1 -0
  44. package/dist/components/Tables/common/filters/logics/text.d.ts +1 -0
  45. package/dist/components/Tables/common/locales.d.ts +21 -0
  46. package/dist/components/Tables/common/organizeColumns/OrganizeColumns.d.ts +267 -0
  47. package/dist/components/Tables/common/organizeColumns/sortHeaders.d.ts +2 -0
  48. package/dist/components/Tables/common/tableFilterUtils.d.ts +1 -0
  49. package/dist/components/Tables/common/tableStorageUtils.d.ts +41 -1
  50. package/dist/components/Tables/common/tableUtils.d.ts +42 -5
  51. package/dist/components/Tables/common/types.d.ts +19 -8
  52. package/dist/components/Tables/common/usePagination.d.ts +22 -0
  53. package/dist/components/Tables/common/useTableCheckbox.d.ts +20 -0
  54. package/dist/components/Tables/common/useTableHeaders.d.ts +76 -0
  55. package/dist/components/Tables/common/useTableItems.d.ts +24 -0
  56. package/dist/components/Tables/common/useTableOptions.d.ts +18 -0
  57. package/dist/components/ToolbarContainer/ToolbarContainer.d.ts +11 -0
  58. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +9 -2
  59. package/dist/components/index.d.ts +8 -6
  60. package/dist/design-system-v3.js +58 -56
  61. package/dist/design-system-v3.umd.cjs +22 -22
  62. package/dist/main-Cx8qG7YR.js +16344 -0
  63. package/dist/stories/Accessibilite/Vuetify/VuetifyItems.d.ts +14 -2
  64. package/dist/stories/DesignTokens/StylesTypographiques.stories.new.d.ts +8 -0
  65. package/dist/stories/DesignTokens/TypographyDisplay.d.ts +28 -0
  66. package/dist/stories/DesignTokens/vue-shims.d.ts +6 -0
  67. package/dist/style.css +1 -1
  68. package/package.json +1 -1
  69. package/src/common/imgs/accessibility-svgrepo-com.svg +4 -0
  70. package/src/components/Accordion/Accessibilite/AccessibilityGuide.mdx +249 -0
  71. package/src/components/Accordion/Accordion.vue +48 -76
  72. package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +146 -0
  73. package/src/components/Accordion/composables/__tests__/useAccordionKeyboardNavigation.spec.ts +209 -0
  74. package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +144 -0
  75. package/src/components/Accordion/composables/useAccordionGroupCommunication.ts +52 -0
  76. package/src/components/Accordion/composables/useAccordionKeyboardNavigation.ts +111 -0
  77. package/src/components/Accordion/composables/useAccordionState.ts +59 -0
  78. package/src/components/Accordion/tests/__snapshots__/accordion.spec.ts.snap +3 -0
  79. package/src/components/Customs/SyCheckbox/Accessibilite.mdx +303 -0
  80. package/src/components/Customs/SyCheckbox/SyCheckbox.mdx +50 -0
  81. package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +630 -0
  82. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +326 -0
  83. package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +201 -0
  84. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +1 -0
  85. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +8 -1
  86. package/src/components/Customs/SySelect/SySelect.stories.ts +160 -0
  87. package/src/components/Customs/SySelect/SySelect.vue +291 -32
  88. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +230 -0
  89. package/src/components/Customs/SyTextField/SyTextField.stories.ts +3 -2
  90. package/src/components/Customs/SyTextField/SyTextField.vue +19 -8
  91. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +241 -31
  92. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +305 -57
  93. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.events.spec.ts +161 -0
  94. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +4 -2
  95. package/src/components/DatePicker/DatePicker/DatePicker.stories.ts +259 -137
  96. package/src/components/DatePicker/DatePicker/DatePicker.vue +153 -25
  97. package/src/components/DatePicker/DatePicker/tests/DatePicker.events.spec.ts +189 -0
  98. package/src/components/DatePicker/DatePicker/{DatePicker.spec.ts → tests/DatePicker.spec.ts} +1 -15
  99. package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +24 -14
  100. package/src/components/DatePicker/DateTextInput/DateTextInput.events.spec.ts +148 -0
  101. package/src/components/DatePicker/DateTextInput/DateTextInput.spec.ts +3 -1
  102. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +200 -5
  103. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +241 -31
  104. package/src/components/DatePicker/composables/index.ts +2 -0
  105. package/src/components/DatePicker/composables/tests/useDateAutoClamp.spec.ts +190 -0
  106. package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +182 -4
  107. package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +105 -80
  108. package/src/components/DatePicker/composables/useAsteriskDisplay.ts +31 -0
  109. package/src/components/DatePicker/composables/useDateAutoClamp.ts +136 -0
  110. package/src/components/DatePicker/composables/useDateRangeInput.ts +21 -18
  111. package/src/components/DatePicker/composables/useDisplayedDateString.ts +13 -1
  112. package/src/components/DatePicker/composables/useInputBlurHandler.ts +84 -20
  113. package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +149 -51
  114. package/src/components/DiacriticPicker/DiacriticPicker.stories.ts +10 -0
  115. package/src/components/ErrorPage/Accessibilite.stories.ts +8 -0
  116. package/src/components/ErrorPage/ErrorPage.vue +12 -6
  117. package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +4 -4
  118. package/src/components/NirField/NirField.mdx +22 -9
  119. package/src/components/NirField/NirField.stories.ts +26 -2
  120. package/src/components/NirField/NirField.vue +209 -22
  121. package/src/components/NirField/nirValidation.ts +17 -3
  122. package/src/components/NirField/tests/NirField.spec.ts +2 -2
  123. package/src/components/NotFoundPage/Accessibilite.stories.ts +8 -0
  124. package/src/components/NotFoundPage/NotFoundPage.vue +2 -1
  125. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +8 -6
  126. package/src/components/PaginatedTable/PaginatedTable.mdx +2 -0
  127. package/src/components/PasswordField/PasswordField.stories.ts +4 -0
  128. package/src/components/PasswordField/PasswordField.vue +3 -0
  129. package/src/components/PeriodField/PeriodField.vue +2 -0
  130. package/src/components/PhoneField/PhoneField.stories.ts +15 -15
  131. package/src/components/PhoneField/PhoneField.vue +1 -1
  132. package/src/components/RangeField/RangeField.stories.ts +9 -0
  133. package/src/components/RangeField/RangeField.vue +4 -0
  134. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +12 -0
  135. package/src/components/SearchListField/SearchListField.vue +5 -0
  136. package/src/components/SyTextArea/SyTextArea.vue +3 -0
  137. package/src/components/SyTextArea/tests/SyTextArea.spec.ts +0 -1
  138. package/src/components/Tables/SyServerTable/FilterRules.stories.ts +632 -15
  139. package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -5
  140. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +2844 -1377
  141. package/src/components/Tables/SyServerTable/SyServerTable.vue +155 -66
  142. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +256 -4
  143. package/src/components/Tables/SyTable/FilterRules.stories.ts +183 -0
  144. package/src/components/Tables/SyTable/SyTable.mdx +14 -4
  145. package/src/components/Tables/SyTable/SyTable.stories.ts +1265 -477
  146. package/src/components/Tables/SyTable/SyTable.vue +152 -72
  147. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +366 -4
  148. package/src/components/Tables/common/SyTableFilter.vue +3 -56
  149. package/src/components/Tables/common/SyTablePagination.vue +375 -0
  150. package/src/components/Tables/common/TableHeader.vue +10 -26
  151. package/src/components/Tables/common/filters/SelectFilter.vue +131 -22
  152. package/src/components/Tables/common/filters/getFilterComponent.ts +54 -0
  153. package/src/components/Tables/common/filters/locales.ts +4 -0
  154. package/src/components/Tables/common/filters/logics/date.ts +12 -0
  155. package/src/components/Tables/common/filters/logics/number.ts +48 -0
  156. package/src/components/Tables/common/filters/logics/period.ts +25 -0
  157. package/src/components/Tables/common/filters/logics/select.ts +27 -0
  158. package/src/components/Tables/common/filters/logics/tests/TextFilterLogic.spec.ts +177 -0
  159. package/src/components/Tables/common/filters/logics/text.ts +62 -0
  160. package/src/components/Tables/common/filters/tests/TextFilter.spec.ts +11 -11
  161. package/src/components/Tables/common/locales.ts +24 -0
  162. package/src/components/Tables/common/organizeColumns/OrganizeColumns.vue +269 -0
  163. package/src/components/Tables/common/organizeColumns/sortHeaders.ts +9 -0
  164. package/src/components/Tables/common/tableFilterUtils.ts +43 -295
  165. package/src/components/Tables/common/tableStorageUtils.ts +27 -2
  166. package/src/components/Tables/common/tableStyles.scss +26 -0
  167. package/src/components/Tables/common/tableUtils.ts +3 -16
  168. package/src/components/Tables/common/tests/SyTablePagination.spec.ts +170 -0
  169. package/src/components/Tables/common/tests/filterByRange.spec.ts +215 -0
  170. package/src/components/Tables/common/tests/tableFilterUtils.spec.ts +0 -14
  171. package/src/components/Tables/common/tests/tableUtils.spec.ts +7 -51
  172. package/src/components/Tables/common/types.ts +17 -6
  173. package/src/components/Tables/common/usePagination.ts +83 -0
  174. package/src/components/Tables/common/useTableCheckbox.ts +58 -0
  175. package/src/components/Tables/common/useTableHeaders.ts +88 -0
  176. package/src/components/Tables/common/useTableItems.ts +87 -0
  177. package/src/components/Tables/common/useTableOptions.ts +93 -0
  178. package/src/components/ToolbarContainer/ToolbarContainer.mdx +16 -0
  179. package/src/components/ToolbarContainer/ToolbarContainer.stories.ts +675 -0
  180. package/src/components/ToolbarContainer/ToolbarContainer.vue +128 -0
  181. package/src/components/ToolbarContainer/tests/ToolbarContainer.spec.ts +156 -0
  182. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +74 -0
  183. package/src/components/UserMenuBtn/UserMenuBtn.vue +19 -17
  184. package/src/components/index.ts +8 -6
  185. package/src/stories/Accessibilite/Aculturation/AuditDesignSystem.mdx +293 -20
  186. package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +448 -54
  187. package/src/stories/Accessibilite/Audit/RGAA.mdx +231 -23
  188. package/src/stories/Accessibilite/Avancement/Avancement.mdx +591 -7
  189. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +139 -38
  190. package/src/stories/Accessibilite/Introduction.mdx +258 -18
  191. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +221 -31
  192. package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +204 -22
  193. package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +537 -24
  194. package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +577 -70
  195. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru.mdx +382 -31
  196. package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +419 -81
  197. package/src/stories/Accessibilite/Vuetify/Vuetify.mdx +132 -6
  198. package/src/stories/Accessibilite/Vuetify/Vuetify.stories.ts +370 -146
  199. package/src/stories/Accessibilite/Vuetify/VuetifyItems.ts +35 -57
  200. package/src/stories/Demarrer/Accueil.stories.ts +20 -5
  201. package/src/stories/DesignTokens/StylesTypographiques.mdx +10 -9
  202. package/src/stories/DesignTokens/StylesTypographiques.stories.new.ts +397 -0
  203. package/src/stories/DesignTokens/StylesTypographiques.stories.ts +397 -0
  204. package/src/stories/DesignTokens/TypographyDisplay.vue +155 -0
  205. package/src/stories/DesignTokens/vue-shims.d.ts +6 -0
  206. package/src/stories/GuideDuDev/LesBreackingChanges.mdx +0 -2
  207. package/src/stories/GuideDuDev/MigrationDepuisBridge.mdx +1 -1
  208. package/src/stories/GuideDuDev/MigrationDepuisVue2.mdx +1 -1
  209. package/src/stories/GuideDuDev/PortailAgent.mdx +10 -0
  210. package/src/stories/GuideDuDev/PortailAgent.stories.ts +506 -0
  211. package/src/stories/GuideDuDev/Theme.mdx +41 -0
  212. package/dist/SelectFilter-Cj-GW2Cc.js +0 -97
  213. package/dist/main-WDqeoGM-.js +0 -14788
  214. package/src/components/PaginatedTable/tests/__snapshots__/PaginatedTable.spec.ts.snap +0 -886
  215. package/src/components/Tables/SyServerTable/tests/__snapshots__/SyServerTable.spec.ts.snap +0 -521
  216. package/src/components/Tables/SyTable/tests/__snapshots__/SyTable.spec.ts.snap +0 -521
  217. package/src/stories/DesignTokens/ThemePA.mdx +0 -35
@@ -1,6 +1,7 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest'
2
2
  import { ref } from 'vue'
3
3
  import { useInputBlurHandler } from '../useInputBlurHandler'
4
+ import { DATE_PICKER_MESSAGES } from '../../constants/messages'
4
5
 
5
6
  describe('useInputBlurHandler', () => {
6
7
  // Mocks et setup
@@ -15,6 +16,7 @@ describe('useInputBlurHandler', () => {
15
16
  const isManualInputActive = ref(true)
16
17
  const isUpdatingFromInternal = ref(false)
17
18
  const selectedDates = ref<Date | Date[] | null>(null)
19
+ const errors = ref<string[]>([])
18
20
 
19
21
  beforeEach(() => {
20
22
  // Réinitialiser les mocks et les refs avant chaque test
@@ -29,6 +31,7 @@ describe('useInputBlurHandler', () => {
29
31
  isManualInputActive.value = true
30
32
  isUpdatingFromInternal.value = false
31
33
  selectedDates.value = null
34
+ errors.value = []
32
35
 
33
36
  // Configuration par défaut des mocks
34
37
  mockValidateDateFormat.mockReturnValue({ isValid: true, message: '' })
@@ -229,8 +232,15 @@ describe('useInputBlurHandler', () => {
229
232
  expect(mockUpdateModel).not.toHaveBeenCalled()
230
233
  })
231
234
 
232
- it('devrait appeler validateManualInput avec la valeur actuelle', () => {
235
+ it('devrait valider la date et mettre à jour le modèle avec la valeur formatée', () => {
233
236
  displayFormattedDate.value = '01/01/2023'
237
+ // Simuler une date valide
238
+ mockValidateDateFormat.mockReturnValue({ isValid: true, message: '' })
239
+ const parsedDate = new Date('2023-01-01')
240
+ mockParseDate.mockReturnValue(parsedDate)
241
+ // Simuler le formatage de la date
242
+ const formattedDate = '01/01/2023'
243
+ mockFormatDate.mockReturnValue(formattedDate)
234
244
 
235
245
  const { handleInputBlur } = useInputBlurHandler({
236
246
  format: 'DD/MM/YYYY',
@@ -239,6 +249,7 @@ describe('useInputBlurHandler', () => {
239
249
  isManualInputActive,
240
250
  isUpdatingFromInternal,
241
251
  selectedDates,
252
+ errors,
242
253
  validateDateFormat: mockValidateDateFormat,
243
254
  parseDate: mockParseDate,
244
255
  formatDate: mockFormatDate,
@@ -249,10 +260,13 @@ describe('useInputBlurHandler', () => {
249
260
 
250
261
  handleInputBlur()
251
262
 
252
- expect(mockValidateManualInput).toHaveBeenCalledWith('01/01/2023')
263
+ // Avec nos modifications, on valide d'abord le format de la date
264
+ expect(mockValidateDateFormat).toHaveBeenCalledWith('01/01/2023')
265
+ // Puis on met à jour le modèle avec la date formatée (pas l'objet Date)
266
+ expect(mockUpdateModel).toHaveBeenCalledWith(formattedDate)
253
267
  })
254
268
 
255
- it('devrait appeler validateManualInput avec une chaîne vide si displayFormattedDate est vide', () => {
269
+ it('devrait mettre à jour le modèle avec null si displayFormattedDate est vide', () => {
256
270
  displayFormattedDate.value = ''
257
271
 
258
272
  const { handleInputBlur } = useInputBlurHandler({
@@ -262,6 +276,168 @@ describe('useInputBlurHandler', () => {
262
276
  isManualInputActive,
263
277
  isUpdatingFromInternal,
264
278
  selectedDates,
279
+ errors,
280
+ validateDateFormat: mockValidateDateFormat,
281
+ parseDate: mockParseDate,
282
+ formatDate: mockFormatDate,
283
+ updateModel: mockUpdateModel,
284
+ validateManualInput: mockValidateManualInput,
285
+ emitBlur: mockEmitBlur,
286
+ })
287
+
288
+ handleInputBlur()
289
+
290
+ // Avec nos modifications, on met à jour directement le modèle avec null
291
+ // au lieu d'appeler validateManualInput
292
+ expect(mockUpdateModel).toHaveBeenCalledWith(null)
293
+ })
294
+ })
295
+
296
+ // Nouveaux tests pour les plages de dates
297
+ describe('handleInputBlur avec plages de dates', () => {
298
+ it('devrait mettre à jour le modèle avec un tableau de dates si la plage est valide', () => {
299
+ displayFormattedDate.value = '01/01/2023 - 10/01/2023'
300
+ const startDate = new Date('2023-01-01')
301
+ const endDate = new Date('2023-01-10')
302
+
303
+ mockValidateDateFormat
304
+ .mockReturnValueOnce({ isValid: true, message: '' }) // Pour la date de début
305
+ .mockReturnValueOnce({ isValid: true, message: '' }) // Pour la date de fin
306
+
307
+ mockParseDate
308
+ .mockReturnValueOnce(startDate) // Pour la date de début
309
+ .mockReturnValueOnce(endDate) // Pour la date de fin
310
+
311
+ mockFormatDate
312
+ .mockReturnValueOnce('01/01/2023') // Pour la date de début
313
+ .mockReturnValueOnce('10/01/2023') // Pour la date de fin
314
+
315
+ const { handleInputBlur } = useInputBlurHandler({
316
+ format: 'DD/MM/YYYY',
317
+ displayFormattedDate,
318
+ hasInteracted,
319
+ isManualInputActive,
320
+ isUpdatingFromInternal,
321
+ selectedDates,
322
+ errors,
323
+ validateDateFormat: mockValidateDateFormat,
324
+ parseDate: mockParseDate,
325
+ formatDate: mockFormatDate,
326
+ updateModel: mockUpdateModel,
327
+ validateManualInput: mockValidateManualInput,
328
+ emitBlur: mockEmitBlur,
329
+ })
330
+
331
+ handleInputBlur()
332
+
333
+ expect(mockValidateDateFormat).toHaveBeenCalledWith('01/01/2023')
334
+ expect(mockValidateDateFormat).toHaveBeenCalledWith('10/01/2023')
335
+ expect(mockParseDate).toHaveBeenCalledWith('01/01/2023', 'DD/MM/YYYY')
336
+ expect(mockParseDate).toHaveBeenCalledWith('10/01/2023', 'DD/MM/YYYY')
337
+ expect(mockFormatDate).toHaveBeenCalledWith(startDate, 'DD/MM/YYYY')
338
+ expect(mockFormatDate).toHaveBeenCalledWith(endDate, 'DD/MM/YYYY')
339
+ expect(selectedDates.value).toEqual([startDate, endDate])
340
+ expect(mockUpdateModel).toHaveBeenCalledWith(['01/01/2023', '10/01/2023'])
341
+ expect(isUpdatingFromInternal.value).toBe(true) // Sera réinitialisé par le setTimeout
342
+ })
343
+
344
+ it('devrait utiliser le format de retour pour les plages de dates si spécifié', () => {
345
+ displayFormattedDate.value = '01/01/2023 - 10/01/2023'
346
+ const startDate = new Date('2023-01-01')
347
+ const endDate = new Date('2023-01-10')
348
+
349
+ mockValidateDateFormat
350
+ .mockReturnValueOnce({ isValid: true, message: '' }) // Pour la date de début
351
+ .mockReturnValueOnce({ isValid: true, message: '' }) // Pour la date de fin
352
+
353
+ mockParseDate
354
+ .mockReturnValueOnce(startDate) // Pour la date de début
355
+ .mockReturnValueOnce(endDate) // Pour la date de fin
356
+
357
+ mockFormatDate
358
+ .mockReturnValueOnce('2023-01-01') // Pour la date de début avec format de retour
359
+ .mockReturnValueOnce('2023-01-10') // Pour la date de fin avec format de retour
360
+
361
+ const { handleInputBlur } = useInputBlurHandler({
362
+ format: 'DD/MM/YYYY',
363
+ dateFormatReturn: 'YYYY-MM-DD',
364
+ displayFormattedDate,
365
+ hasInteracted,
366
+ isManualInputActive,
367
+ isUpdatingFromInternal,
368
+ selectedDates,
369
+ errors,
370
+ validateDateFormat: mockValidateDateFormat,
371
+ parseDate: mockParseDate,
372
+ formatDate: mockFormatDate,
373
+ updateModel: mockUpdateModel,
374
+ validateManualInput: mockValidateManualInput,
375
+ emitBlur: mockEmitBlur,
376
+ })
377
+
378
+ handleInputBlur()
379
+
380
+ expect(mockFormatDate).toHaveBeenCalledWith(startDate, 'YYYY-MM-DD')
381
+ expect(mockFormatDate).toHaveBeenCalledWith(endDate, 'YYYY-MM-DD')
382
+ expect(mockUpdateModel).toHaveBeenCalledWith(['2023-01-01', '2023-01-10'])
383
+ })
384
+
385
+ it('devrait ajouter une erreur si la date de fin est antérieure à la date de début', () => {
386
+ displayFormattedDate.value = '10/01/2023 - 01/01/2023' // Date de fin avant date de début
387
+ const startDate = new Date('2023-01-10')
388
+ const endDate = new Date('2023-01-01')
389
+
390
+ mockValidateDateFormat
391
+ .mockReturnValueOnce({ isValid: true, message: '' }) // Pour la date de début
392
+ .mockReturnValueOnce({ isValid: true, message: '' }) // Pour la date de fin
393
+
394
+ mockParseDate
395
+ .mockReturnValueOnce(startDate) // Pour la date de début
396
+ .mockReturnValueOnce(endDate) // Pour la date de fin
397
+
398
+ // Utiliser la constante importée au début du fichier
399
+
400
+ const { handleInputBlur } = useInputBlurHandler({
401
+ format: 'DD/MM/YYYY',
402
+ displayFormattedDate,
403
+ hasInteracted,
404
+ isManualInputActive,
405
+ isUpdatingFromInternal,
406
+ selectedDates,
407
+ errors,
408
+ validateDateFormat: mockValidateDateFormat,
409
+ parseDate: mockParseDate,
410
+ formatDate: mockFormatDate,
411
+ updateModel: mockUpdateModel,
412
+ validateManualInput: mockValidateManualInput,
413
+ emitBlur: mockEmitBlur,
414
+ })
415
+
416
+ handleInputBlur()
417
+
418
+ expect(mockValidateDateFormat).toHaveBeenCalledWith('10/01/2023')
419
+ expect(mockValidateDateFormat).toHaveBeenCalledWith('01/01/2023')
420
+ expect(mockParseDate).toHaveBeenCalledWith('10/01/2023', 'DD/MM/YYYY')
421
+ expect(mockParseDate).toHaveBeenCalledWith('01/01/2023', 'DD/MM/YYYY')
422
+ expect(errors.value).toContain(DATE_PICKER_MESSAGES.ERROR_END_BEFORE_START)
423
+ expect(mockUpdateModel).not.toHaveBeenCalled()
424
+ })
425
+
426
+ it('ne devrait pas mettre à jour le modèle si une des dates de la plage est invalide', () => {
427
+ displayFormattedDate.value = '01/01/2023 - 32/01/2023' // Date de fin invalide
428
+
429
+ mockValidateDateFormat
430
+ .mockReturnValueOnce({ isValid: true, message: '' }) // Pour la date de début
431
+ .mockReturnValueOnce({ isValid: false, message: 'Date invalide' }) // Pour la date de fin
432
+
433
+ const { handleInputBlur } = useInputBlurHandler({
434
+ format: 'DD/MM/YYYY',
435
+ displayFormattedDate,
436
+ hasInteracted,
437
+ isManualInputActive,
438
+ isUpdatingFromInternal,
439
+ selectedDates,
440
+ errors,
265
441
  validateDateFormat: mockValidateDateFormat,
266
442
  parseDate: mockParseDate,
267
443
  formatDate: mockFormatDate,
@@ -272,7 +448,9 @@ describe('useInputBlurHandler', () => {
272
448
 
273
449
  handleInputBlur()
274
450
 
275
- expect(mockValidateManualInput).toHaveBeenCalledWith('')
451
+ expect(mockValidateDateFormat).toHaveBeenCalledWith('01/01/2023')
452
+ expect(mockValidateDateFormat).toHaveBeenCalledWith('32/01/2023')
453
+ expect(mockUpdateModel).not.toHaveBeenCalled()
276
454
  })
277
455
  })
278
456
  })
@@ -1,100 +1,125 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest'
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
2
+ import { ref, nextTick, type Ref } from 'vue'
2
3
  import { useMonthButtonCustomization } from '../useMonthButtonCustomization'
3
- import { nextTick } from 'vue'
4
-
5
- // Mock pour nextTick
6
- vi.mock('vue', async () => {
7
- const actual = await vi.importActual('vue')
8
- return {
9
- ...actual as object,
10
- nextTick: vi.fn((callback) => {
11
- if (callback) callback()
12
- return Promise.resolve()
13
- }),
14
- }
15
- })
16
4
 
17
5
  describe('useMonthButtonCustomization', () => {
18
- // Mock pour document.querySelector
19
- const mockMonthBtn = {
20
- textContent: 'Janvier 2025',
21
- innerHTML: '',
22
- }
23
-
24
- const mockYearBtn = {
25
- innerHTML: '',
26
- }
6
+ let isPickerVisibleGetter: () => boolean
7
+ // Définir explicitement le type pour éviter les erreurs de compatibilité
8
+ let monthName: Ref<string | null>
9
+ let yearName: Ref<string | null>
27
10
 
28
11
  beforeEach(() => {
29
- vi.clearAllMocks()
30
-
31
- // Réinitialiser les mocks pour chaque test
32
- mockMonthBtn.textContent = 'Janvier 2025'
33
- mockMonthBtn.innerHTML = ''
34
- mockYearBtn.innerHTML = ''
35
- // Mock pour document.querySelector
36
- document.querySelector = vi.fn((selector) => {
37
- if (selector === '.v-date-picker-controls__month-btn') {
38
- return mockMonthBtn
39
- }
40
- if (selector === '.v-date-picker-controls__mode-btn') {
41
- return mockYearBtn
42
- }
43
- if (selector === '.v-date-picker-controls') {
44
- return { childList: true, subtree: true }
45
- }
46
- return null
47
- })
48
-
49
- // Mock pour MutationObserver
50
- global.MutationObserver = vi.fn().mockImplementation(function (this: { observe: () => void, disconnect: () => void, callback: (mutations: MutationRecord[], observer: MutationObserver) => void }, callback) {
51
- this.observe = vi.fn()
52
- this.disconnect = vi.fn()
53
- // Stocker le callback pour pouvoir le déclencher dans les tests
54
- this.callback = callback
55
- })
12
+ // Réinitialiser les refs pour chaque test avec le type exact attendu par le composable
13
+ monthName = ref<string | null>(null)
14
+ yearName = ref<string | null>(null)
15
+
16
+ document.body.innerHTML = `
17
+ <div class="v-date-picker-controls">
18
+ <button class="v-date-picker-controls__month-btn">janvier 2023</button>
19
+ <button class="v-date-picker-controls__mode-btn">2023</button>
20
+ </div>
21
+ `
22
+ isPickerVisibleGetter = () => true
56
23
  })
57
24
 
58
- it('devrait initialiser correctement', () => {
59
- const isPickerVisible = () => true
60
- const { customizeMonthButton, setupMonthButtonObserver } = useMonthButtonCustomization(isPickerVisible)
61
- expect(customizeMonthButton).toBeDefined()
62
- expect(setupMonthButtonObserver).toBeDefined()
25
+ afterEach(() => {
26
+ document.body.innerHTML = ''
63
27
  })
64
28
 
65
- it('ne devrait pas appeler nextTick si le picker n\'est pas visible', () => {
66
- const isPickerVisible = () => false
67
- const { customizeMonthButton } = useMonthButtonCustomization(isPickerVisible)
68
- customizeMonthButton()
69
- expect(nextTick).not.toHaveBeenCalled()
29
+ // Test de l'affichage des mois personnalisés via les noms de mois fournis
30
+ it('personnalise correctement les noms de mois (janvier -> Janv.)', async () => {
31
+ monthName.value = 'janvier'
32
+ const { customizeMonthButton } = useMonthButtonCustomization(
33
+ isPickerVisibleGetter,
34
+ monthName,
35
+ )
36
+
37
+ await customizeMonthButton()
38
+ await nextTick()
39
+
40
+ const monthBtn = document.querySelector('.v-date-picker-controls__month-btn')!
41
+ expect(monthBtn.textContent).toContain('Janv.')
70
42
  })
71
43
 
72
- it('devrait personnaliser le bouton du mois quand le picker est visible', () => {
73
- const isPickerVisible = () => true
74
- const { customizeMonthButton } = useMonthButtonCustomization(isPickerVisible)
44
+ it('personnalise correctement les noms de mois (février -> Févr.)', async () => {
45
+ monthName.value = 'février'
46
+ const { customizeMonthButton } = useMonthButtonCustomization(
47
+ isPickerVisibleGetter,
48
+ monthName,
49
+ )
50
+
51
+ await customizeMonthButton()
52
+ await nextTick()
75
53
 
76
- customizeMonthButton()
77
- expect(nextTick).toHaveBeenCalled()
78
- // Vérifier que le contenu du bouton a été modifié
79
- expect(mockMonthBtn.innerHTML).not.toBe('')
80
- expect(mockMonthBtn.innerHTML).toContain('Janvier')
54
+ const monthBtn = document.querySelector('.v-date-picker-controls__month-btn')!
55
+ expect(monthBtn.textContent).toContain('Févr.')
81
56
  })
82
57
 
83
- it('devrait configurer un observateur pour le bouton du mois', () => {
84
- const isPickerVisible = () => true
85
- const { setupMonthButtonObserver } = useMonthButtonCustomization(isPickerVisible)
58
+ it('capitalise le premier caractère si le mois n\'est pas reconnu', async () => {
59
+ monthName.value = 'pluviose'
60
+ const { customizeMonthButton } = useMonthButtonCustomization(
61
+ isPickerVisibleGetter,
62
+ monthName,
63
+ )
86
64
 
87
- setupMonthButtonObserver()
88
- expect(nextTick).toHaveBeenCalled()
89
- // Vérifier que MutationObserver a été appelé
90
- expect(global.MutationObserver).toHaveBeenCalled()
65
+ await customizeMonthButton()
66
+ await nextTick()
67
+
68
+ const monthBtn = document.querySelector('.v-date-picker-controls__month-btn')!
69
+ expect(monthBtn.textContent).toContain('Pluviose')
91
70
  })
92
71
 
93
- it('devrait extraire correctement le mois et l\'année du texte du bouton', () => {
94
- const isPickerVisible = () => true
95
- const { monthButtonText, customizeMonthButton } = useMonthButtonCustomization(isPickerVisible)
72
+ it('customise les boutons du mois et de lannée', async () => {
73
+ // S'assurer que monthName est null pour ce test
74
+ monthName.value = null
75
+
76
+ const { customizeMonthButton, monthButtonText } = useMonthButtonCustomization(
77
+ isPickerVisibleGetter,
78
+ monthName,
79
+ yearName,
80
+ )
81
+
82
+ await customizeMonthButton()
83
+ await nextTick()
84
+
85
+ const monthBtn = document.querySelector('.v-date-picker-controls__month-btn')!
86
+ const yearBtn = document.querySelector('.v-date-picker-controls__mode-btn')!
87
+
88
+ expect(monthBtn.innerHTML).toContain('<svg') // icône ajoutée
89
+ expect(monthBtn.textContent).toContain('Janv.') // mois transformé
90
+ expect(monthButtonText.value).toBe('janvier 2023')
91
+
92
+ expect(yearBtn.innerHTML).toContain('2023')
93
+ expect(yearBtn.innerHTML).toContain('<svg')
94
+ })
95
+
96
+ it('utilise monthName et yearName si fournis', async () => {
97
+ monthName.value = 'mars'
98
+ yearName.value = '2030'
99
+
100
+ const { customizeMonthButton } = useMonthButtonCustomization(
101
+ isPickerVisibleGetter,
102
+ monthName,
103
+ yearName,
104
+ )
105
+
106
+ await customizeMonthButton()
107
+ await nextTick()
108
+
109
+ const monthBtn = document.querySelector('.v-date-picker-controls__month-btn')!
110
+ const yearBtn = document.querySelector('.v-date-picker-controls__mode-btn')!
111
+
112
+ expect(monthBtn.textContent).toContain('Mars')
113
+ expect(yearBtn.textContent).toContain('2030')
114
+ })
115
+
116
+ it('observe les changements du DOM et personnalise automatiquement', async () => {
117
+ const { setupMonthButtonObserver } = useMonthButtonCustomization(() => true)
118
+ const spy = vi.spyOn(document, 'querySelectorAll')
119
+
120
+ setupMonthButtonObserver()
121
+ await nextTick()
96
122
 
97
- customizeMonthButton()
98
- expect(monthButtonText.value).toBe('Janvier 2025')
123
+ expect(spy).toHaveBeenCalledWith('.v-date-picker-controls')
99
124
  })
100
125
  })
@@ -0,0 +1,31 @@
1
+ import { computed } from 'vue'
2
+
3
+ /**
4
+ * Composable pour gérer l'affichage d'un astérisque à côté du label
5
+ * @param props - Les propriétés du composant contenant displayAsterisk et required
6
+ * @param labelProp - Le nom de la propriété contenant le label (par défaut: 'label')
7
+ * @returns Un objet contenant isShouldDisplayAsterisk et labelWithAsterisk
8
+ */
9
+ export const useAsteriskDisplay = (
10
+ props: { displayAsterisk?: boolean, required?: boolean, [key: string]: unknown },
11
+ labelProp = 'label',
12
+ ) => {
13
+ // Détermine si l'astérisque doit être affiché
14
+ const isShouldDisplayAsterisk = computed(() => {
15
+ return props.displayAsterisk && props.required
16
+ })
17
+
18
+ // Ajoute l'astérisque au label si nécessaire
19
+ const labelWithAsterisk = computed(() => {
20
+ // Assertion de type pour indiquer que props[labelProp] est de type string | undefined
21
+ const label = props[labelProp] as string | undefined
22
+ return isShouldDisplayAsterisk.value && label
23
+ ? `${label} *`
24
+ : label
25
+ })
26
+
27
+ return {
28
+ isShouldDisplayAsterisk,
29
+ labelWithAsterisk,
30
+ }
31
+ }
@@ -0,0 +1,136 @@
1
+ import dayjs from 'dayjs'
2
+ import customParseFormat from 'dayjs/plugin/customParseFormat'
3
+
4
+ // Initialiser les plugins dayjs
5
+ dayjs.extend(customParseFormat)
6
+
7
+ /**
8
+ * Composable pour gérer l'auto-clamping des dates invalides
9
+ * Cette fonctionnalité permet de ramener automatiquement les dates invalides
10
+ * (comme le 29/02 sur une année non bissextile ou 33/12) au dernier jour valide du mois
11
+ */
12
+ export const useDateAutoClamp = () => {
13
+ /**
14
+ * Ajuste une date pour qu'elle soit valide en ramenant les jours invalides
15
+ * au dernier jour du mois correspondant
16
+ *
17
+ * @param day - Le jour à ajuster
18
+ * @param month - Le mois (0-11)
19
+ * @param year - L'année
20
+ * @returns Un objet contenant le jour ajusté et un booléen indiquant si un ajustement a été fait
21
+ */
22
+ const clampDayToValidDate = (day: number, month: number, year: number): { day: number, adjusted: boolean } => {
23
+ // Vérifier si le jour est valide pour ce mois et cette année
24
+ // Créer une date pour le premier jour du mois et obtenir le nombre de jours dans ce mois
25
+ const dateObj = dayjs(`${year}-${month + 1}-01`)
26
+ const daysInMonth = dateObj.daysInMonth()
27
+
28
+ // Si le jour est supérieur au nombre de jours dans le mois, le ramener au dernier jour du mois
29
+ if (day > daysInMonth) {
30
+ return { day: daysInMonth, adjusted: true }
31
+ }
32
+
33
+ return { day, adjusted: false }
34
+ }
35
+
36
+ /**
37
+ * Ajuste une date complète pour qu'elle soit valide
38
+ *
39
+ * @param dateStr - La chaîne de date à ajuster
40
+ * @param format - Le format de la date (ex: 'DD/MM/YYYY')
41
+ * @returns Un objet contenant la date ajustée et un booléen indiquant si un ajustement a été fait
42
+ */
43
+ const autoClampDate = (dateStr: string, format: string): { clampedDate: string, adjusted: boolean } => {
44
+ // Si la chaîne est vide, retourner telle quelle
45
+ if (!dateStr) {
46
+ return { clampedDate: dateStr, adjusted: false }
47
+ }
48
+
49
+ // Déterminer le séparateur utilisé dans le format
50
+ const separator = format.match(/[^DMY]/)?.[0] || '/'
51
+
52
+ // Extraire les parties du format pour déterminer l'ordre (jour, mois, année)
53
+ const formatParts = format.split(separator)
54
+ const dateParts = dateStr.split(separator)
55
+
56
+ // Si le nombre de parties ne correspond pas, retourner la chaîne originale
57
+ if (formatParts.length !== dateParts.length) {
58
+ return { clampedDate: dateStr, adjusted: false }
59
+ }
60
+
61
+ let day = -1
62
+ let month = -1
63
+ let year = -1
64
+
65
+ // Extraire les valeurs de jour, mois et année selon le format
66
+ for (let i = 0; i < formatParts.length; i++) {
67
+ const formatPart = formatParts[i].toUpperCase()
68
+ const value = parseInt(dateParts[i], 10)
69
+
70
+ if (isNaN(value)) {
71
+ return { clampedDate: dateStr, adjusted: false }
72
+ }
73
+
74
+ if (formatPart.startsWith('D')) {
75
+ day = value
76
+ }
77
+ else if (formatPart.startsWith('M')) {
78
+ month = value - 1 // Convertir en index de mois (0-11)
79
+ }
80
+ else if (formatPart.startsWith('Y')) {
81
+ year = value
82
+ }
83
+ }
84
+
85
+ // Vérifier si toutes les parties nécessaires ont été trouvées
86
+ if (day === -1 || month === -1 || year === -1) {
87
+ return { clampedDate: dateStr, adjusted: false }
88
+ }
89
+
90
+ // Vérifier si nous avons une date valide
91
+ if (month < 0 || month > 11 || year < 0 || day < 1) {
92
+ return { clampedDate: dateStr, adjusted: false }
93
+ }
94
+
95
+ // Calculer directement le nombre de jours dans le mois
96
+ const daysInMonth = dayjs(new Date(year, month, 1)).daysInMonth()
97
+
98
+ // Ajuster le jour si nécessaire
99
+ let adjusted = false
100
+ let clampedDay = day
101
+
102
+ if (day > daysInMonth) {
103
+ clampedDay = daysInMonth
104
+ adjusted = true
105
+ }
106
+
107
+ // Si aucun ajustement n'a été fait, retourner la chaîne originale
108
+ if (!adjusted) {
109
+ return { clampedDate: dateStr, adjusted: false }
110
+ }
111
+
112
+ // Reconstruire la chaîne de date avec le jour ajusté
113
+ const newDateParts = [...dateParts]
114
+ for (let i = 0; i < formatParts.length; i++) {
115
+ const formatPart = formatParts[i].toUpperCase()
116
+ if (formatPart.startsWith('D')) {
117
+ // Formater le jour avec le bon nombre de chiffres (01 ou 1 selon le format)
118
+ newDateParts[i] = formatPart.length > 1
119
+ ? clampedDay.toString().padStart(2, '0')
120
+ : clampedDay.toString()
121
+ }
122
+ }
123
+
124
+ return {
125
+ clampedDate: newDateParts.join(separator),
126
+ adjusted: true,
127
+ }
128
+ }
129
+
130
+ return {
131
+ autoClampDate,
132
+ clampDayToValidDate,
133
+ }
134
+ }
135
+
136
+ export default useDateAutoClamp