@cnamts/synapse 1.0.26 → 1.0.27

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 (253) hide show
  1. package/dist/{AutocompleteFilter-BPR-a55G.js → AutocompleteFilter-C9eLKyW8.js} +3 -3
  2. package/dist/{DateFilter-CknrJWs2.js → DateFilter-y-GLkAkn.js} +8 -8
  3. package/dist/{NumberFilter-DJ-yNlzv.js → NumberFilter-DN6hIBS7.js} +1 -1
  4. package/dist/{PeriodFilter-CiB5Oa9Z.js → PeriodFilter-MoUUp9qS.js} +1 -1
  5. package/dist/{SelectFilter-EiafX97M.js → SelectFilter-bCbrdLmu.js} +1 -1
  6. package/dist/{TextFilter-BzOmpdxj.js → TextFilter-CvjgEaoM.js} +4 -4
  7. package/dist/apLightTheme2026-ug4Y23ns.js +611 -0
  8. package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +2369 -353
  9. package/dist/components/Customs/Selects/SyAutocomplete/composables/useSyAutocompleteValidation.d.ts +18 -0
  10. package/dist/components/Customs/Selects/SyAutocomplete/utils/ariaManager.d.ts +1 -1
  11. package/dist/components/Customs/Selects/SyAutocomplete/utils/useKeyboardHandler.d.ts +3 -1
  12. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +9 -10
  13. package/dist/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.d.ts +1 -0
  14. package/dist/components/Customs/Selects/SySelect/composables/useSySelectValidation.d.ts +15 -0
  15. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +3 -3
  16. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +3 -3
  17. package/dist/components/Customs/SyIconButton/SyIconButton.d.ts +18 -0
  18. package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +20 -38
  19. package/dist/components/Customs/SyRadioGroup/composables/useSyRadioGroupValidation.d.ts +50 -0
  20. package/dist/components/Customs/SyTextField/SyTextField.d.ts +6 -6
  21. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +147 -136
  22. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +62 -54
  23. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +27 -24
  24. package/dist/components/DatePicker/composables/index.d.ts +1 -0
  25. package/dist/components/DatePicker/composables/useDatePickerValidationBridge.d.ts +51 -0
  26. package/dist/components/MonthPicker/MonthPicker.d.ts +23 -23
  27. package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +23 -23
  28. package/dist/components/NirField/NirField.d.ts +56 -56
  29. package/dist/components/PasswordField/PasswordField.d.ts +3 -3
  30. package/dist/components/PeriodField/PeriodField.d.ts +236 -212
  31. package/dist/components/PhoneField/PhoneField.d.ts +23 -23
  32. package/dist/components/SyTextArea/SyTextArea.d.ts +25 -15
  33. package/dist/components/SyTextArea/composables/useSyTextAreaValidation.d.ts +20 -0
  34. package/dist/components/SyTextArea/locales.d.ts +1 -0
  35. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +1 -0
  36. package/dist/components/Tables/SyTable/SyTable.d.ts +1 -0
  37. package/dist/components/Tables/common/SyTablePagination.d.ts +25 -25
  38. package/dist/components/Tables/common/types.d.ts +2 -0
  39. package/dist/components/index.d.ts +1 -0
  40. package/dist/composables/unifyValidation/documentationValidationProps.d.ts +160 -160
  41. package/dist/composables/unifyValidation/useValidation.d.ts +16 -14
  42. package/dist/design-system-v3.js +81 -80
  43. package/dist/designTokens/tokens/amelipro/apContextual.d.ts +6 -6
  44. package/dist/designTokens/tokens/amelipro/apDarkTheme.d.ts +3 -1
  45. package/dist/designTokens/tokens/amelipro/apLightTheme.d.ts +53 -100
  46. package/dist/designTokens/tokens/baseContextualTokens.d.ts +0 -6
  47. package/dist/designTokens/tokens/baseTokens.d.ts +232 -0
  48. package/dist/designTokens/tokens/cnam/cnamContextual.d.ts +6 -6
  49. package/dist/designTokens/tokens/cnam/cnamDarkTheme.d.ts +1 -1
  50. package/dist/designTokens/tokens/cnam/cnamLightTheme.d.ts +57 -101
  51. package/dist/designTokens/tokens/pa/paContextual.d.ts +0 -6
  52. package/dist/designTokens/tokens/pa/paDarkTheme.d.ts +1 -1
  53. package/dist/designTokens/tokens/pa/paLightTheme.d.ts +53 -97
  54. package/dist/designTokens/tokens/pa/paSemantic.d.ts +1 -0
  55. package/dist/designTokens/tokens/semanticTokens.d.ts +112 -0
  56. package/dist/main-CI6Q9nmO.js +39234 -0
  57. package/dist/synapse.css +1 -1
  58. package/dist/vuetifyConfig.js +208 -72
  59. package/package.json +4 -2
  60. package/src/assets/overrides/_icons.scss +5 -4
  61. package/src/assets/overrides/_otp.scss +4 -4
  62. package/src/assets/overrides/_typography.scss +2 -1
  63. package/src/assets/overrides/_utilities.scss +1 -42
  64. package/src/components/ChipList/ChipList.vue +30 -18
  65. package/src/components/ChipList/tests/chipList.spec.ts +4 -4
  66. package/src/components/CopyBtn/CopyBtn.vue +2 -2
  67. package/src/components/Customs/Selects/SelectBtnField/SelectBtnField.stories.ts +4 -0
  68. package/src/components/Customs/Selects/SelectBtnField/SelectBtnField.vue +7 -6
  69. package/src/components/Customs/Selects/SelectBtnField/tests/SelectBtnField.spec.ts +223 -0
  70. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.stories.ts +283 -351
  71. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +182 -218
  72. package/src/components/Customs/Selects/SyAutocomplete/composables/useSyAutocompleteValidation.ts +101 -0
  73. package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.spec.ts +761 -1
  74. package/src/components/Customs/Selects/SyAutocomplete/utils/ariaManager.ts +3 -1
  75. package/src/components/Customs/Selects/SyAutocomplete/utils/useKeyboardHandler.ts +79 -5
  76. package/src/components/Customs/Selects/SyAutocomplete/validation/Validation.stories.ts +1029 -0
  77. package/src/components/Customs/Selects/SySelect/SySelect.stories.ts +9 -491
  78. package/src/components/Customs/Selects/SySelect/SySelect.vue +46 -79
  79. package/src/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.ts +3 -0
  80. package/src/components/Customs/Selects/SySelect/composables/useSySelectValidation.ts +64 -0
  81. package/src/components/Customs/Selects/SySelect/tests/SySelect.spec.ts +196 -0
  82. package/src/components/Customs/Selects/SySelect/validation/Validation.stories.ts +1026 -0
  83. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.stories.ts +18 -7
  84. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +2 -2
  85. package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +8 -8
  86. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +8 -8
  87. package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +1 -1
  88. package/src/components/Customs/SyIcon/accessibilite/Accessibility.mdx +0 -6
  89. package/src/components/Customs/SyIcon/utils/tests/iconUtils.spec.ts +107 -0
  90. package/src/components/Customs/SyRadioGroup/SyRadioGroup.mdx +2 -2
  91. package/src/components/Customs/SyRadioGroup/SyRadioGroup.stories.ts +395 -200
  92. package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +82 -127
  93. package/src/components/Customs/SyRadioGroup/composables/useSyRadioGroupValidation.ts +127 -0
  94. package/src/components/Customs/SyRadioGroup/tests/SyRadioGroup.a11y.spec.ts +93 -1
  95. package/src/components/Customs/SyRadioGroup/tests/SyRadioGroup.spec.ts +146 -9
  96. package/src/components/Customs/SyRadioGroup/tests/SyRadioGroup.visual.cy.ts +165 -0
  97. package/src/components/Customs/SyRadioGroup/validation/Validation.stories.ts +773 -0
  98. package/src/components/Customs/SyTabs/config.ts +3 -3
  99. package/src/components/Customs/SyTabs/tests/SyTabs.spec.ts +265 -0
  100. package/src/components/Customs/SyTabs/tests/useTabTransition.spec.ts +188 -0
  101. package/src/components/Customs/SyTextField/SyTextField.stories.ts +10 -29
  102. package/src/components/Customs/SyTextField/SyTextField.vue +23 -15
  103. package/src/components/DataList/DataList.stories.ts +1 -1
  104. package/src/components/DataListItem/tests/DataListItem.spec.ts +3 -1
  105. package/src/components/DatePicker/CalendarMode/DatePicker.vue +37 -142
  106. package/src/components/DatePicker/CalendarMode/tests/DatePicker.coverage.spec.ts +156 -0
  107. package/src/components/DatePicker/CalendarMode/tests/DatePicker.spec.ts +495 -4
  108. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +47 -66
  109. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +206 -0
  110. package/src/components/DatePicker/ComplexDatePicker/tests/bridge-integration.regression.spec.ts +210 -0
  111. package/src/components/DatePicker/ComplexDatePicker/tests/calendar-navigation.regression.spec.ts +214 -0
  112. package/src/components/DatePicker/ComplexDatePicker/tests/validation-cross.regression.spec.ts +194 -0
  113. package/src/components/DatePicker/ComplexDatePicker/tests/validation-success-messages.regression.spec.ts +83 -0
  114. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +129 -54
  115. package/src/components/DatePicker/DateTextInput/tests/DateTextInput.spec.ts +320 -0
  116. package/src/components/DatePicker/composables/index.ts +1 -0
  117. package/src/components/DatePicker/composables/tests/useCalendarKeyboardNavigation.spec.ts +360 -0
  118. package/src/components/DatePicker/composables/tests/useDatePickerValidationBridge.spec.ts +129 -0
  119. package/src/components/DatePicker/composables/useDatePickerValidationBridge.ts +205 -0
  120. package/src/components/DatePicker/docExamples/BidirectionalComplexValidation.vue +1 -1
  121. package/src/components/DatePicker/docExamples/DatePickerBidirectionalValidation.vue +1 -1
  122. package/src/components/DatePicker/tests/exposed-methods.coverage.spec.ts +75 -0
  123. package/src/components/DialogBox/DialogBox.vue +1 -1
  124. package/src/components/FileList/UploadItem/UploadItem.vue +4 -4
  125. package/src/components/FileUpload/FileUpload.vue +2 -2
  126. package/src/components/FileUpload/FileUploadContent.vue +1 -1
  127. package/src/components/FilterInline/FilterInline.mdx +2 -2
  128. package/src/components/FilterSideBar/FilterSideBar.stories.ts +1 -1
  129. package/src/components/FilterSideBar/FilterSideBar.vue +2 -2
  130. package/src/components/FooterBar/FooterBar.vue +7 -7
  131. package/src/components/FranceConnectBtn/FranceConnectBtn.vue +1 -1
  132. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +2 -2
  133. package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +7 -7
  134. package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +2 -2
  135. package/src/components/HeaderLoading/tests/HeaderLoading.spec.ts +87 -8
  136. package/src/components/HeaderNavigationBar/HorizontalNavbar/HorizontalNavbar.vue +3 -3
  137. package/src/components/HeaderNavigationBar/HorizontalNavbar/tests/HorizontalNavbar.spec.ts +589 -0
  138. package/src/components/HeaderToolbar/tests/HeaderToolBar.spec.ts +153 -1
  139. package/src/components/HeaderToolbar/tests/useMobileRightMenu.spec.ts +258 -0
  140. package/src/components/LogoBrandSection/tests/LogoBrandSection.spec.ts +2 -2
  141. package/src/components/LogoBrandSection/tests/__snapshots__/LogoBrandSection.spec.ts.snap +1 -1
  142. package/src/components/LunarCalendar/tests/useLunarCalendarRules.spec.ts +184 -0
  143. package/src/components/MonthPicker/MonthPickerVisual/MonthSelector.vue +3 -3
  144. package/src/components/MonthPicker/MonthPickerVisual/VisualPickerFooter.vue +1 -1
  145. package/src/components/MonthPicker/MonthPickerVisual/VisualPickerHeader.vue +2 -2
  146. package/src/components/MonthPicker/MonthPickerVisual/YearSelector.vue +1 -1
  147. package/src/components/NirField/NirField.vue +3 -3
  148. package/src/components/NotificationBar/Notification/Notification.vue +12 -12
  149. package/src/components/NotificationBar/NotificationBar.stories.ts +8 -8
  150. package/src/components/PaginatedTable/Pagination.vue +2 -2
  151. package/src/components/PasswordField/PasswordField.vue +8 -8
  152. package/src/components/PasswordField/tests/PasswordField.spec.ts +3 -3
  153. package/src/components/RangeField/RangeSlider/RangeSlider.vue +2 -2
  154. package/src/components/RangeField/RangeSlider/Tooltip/Tooltip.vue +1 -1
  155. package/src/components/StatusPage/tests/StatusPage.spec.ts +149 -0
  156. package/src/components/SubHeader/SubHeader.vue +1 -1
  157. package/src/components/SyAlert/SyAlert.vue +23 -23
  158. package/src/components/SyTextArea/SyTextArea.stories.ts +177 -131
  159. package/src/components/SyTextArea/SyTextArea.vue +235 -83
  160. package/src/components/SyTextArea/composables/useSyTextAreaValidation.ts +81 -0
  161. package/src/components/SyTextArea/locales.ts +1 -0
  162. package/src/components/SyTextArea/tests/SyTextArea.spec.ts +449 -1
  163. package/src/components/SyTextArea/useDefaultValidationRules.ts +2 -7
  164. package/src/components/SyTextArea/validation/Validation.stories.ts +856 -0
  165. package/src/components/TableToolbar/TableToolbar.vue +6 -6
  166. package/src/components/TableToolbar/accessibilite/Accessibility.mdx +81 -7
  167. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +163 -0
  168. package/src/components/Tables/SyServerTable/SyServerTable.vue +2 -1
  169. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +67 -0
  170. package/src/components/Tables/SyTable/SyTable.stories.ts +94 -0
  171. package/src/components/Tables/SyTable/SyTable.vue +2 -1
  172. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +64 -0
  173. package/src/components/Tables/common/TableHeader.vue +2 -2
  174. package/src/components/Tables/common/filters/logics/tests/NumberFilterLogic.spec.ts +176 -0
  175. package/src/components/Tables/common/filters/logics/tests/SelectFilterLogic.spec.ts +111 -0
  176. package/src/components/Tables/common/tableStyles.scss +6 -6
  177. package/src/components/Tables/common/types.ts +2 -0
  178. package/src/components/UploadWorkflow/tests/UploadWorkflow.spec.ts +2 -0
  179. package/src/components/index.ts +1 -0
  180. package/src/composables/date/tests/useDateFormatDayjs.spec.ts +31 -0
  181. package/src/composables/date/tests/useHolidayDay.spec.ts +109 -0
  182. package/src/composables/rules/tests/useFieldValidation.spec.ts +374 -0
  183. package/src/composables/tests/useError.spec.ts +30 -0
  184. package/src/composables/tests/useFormFieldErrorHandling.spec.ts +234 -0
  185. package/src/composables/unifyValidation/documentationValidationProps.ts +5 -5
  186. package/src/composables/unifyValidation/tests/documentationValidationProps.spec.ts +177 -0
  187. package/src/composables/unifyValidation/tests/useCustomValidation.spec.ts +30 -0
  188. package/src/composables/unifyValidation/tests/useValidation.spec.ts +6 -2
  189. package/src/composables/unifyValidation/useCustomValidation.ts +19 -9
  190. package/src/composables/unifyValidation/useValidation.ts +18 -21
  191. package/src/composables/useFilterable/useFilterable.spec.ts +42 -0
  192. package/src/composables/useFilterable/useFilterable.ts +11 -7
  193. package/src/composables/useFormFieldErrorHandling.ts +2 -2
  194. package/src/composantsVuetify/VBtn/VBtn.mdx +9 -39
  195. package/src/composantsVuetify/VBtn/v-btn.stories.ts +26 -86
  196. package/src/designTokens/tokens/amelipro/apContextual.ts +6 -0
  197. package/src/designTokens/tokens/amelipro/apDarkTheme.ts +2 -2
  198. package/src/designTokens/tokens/amelipro/apLightTheme.ts +72 -103
  199. package/src/designTokens/tokens/amelipro/apSemantic.ts +1 -1
  200. package/src/designTokens/tokens/baseContextualTokens.ts +1 -6
  201. package/src/designTokens/tokens/baseTokens.ts +232 -0
  202. package/src/designTokens/tokens/cnam/cnamContextual.ts +6 -0
  203. package/src/designTokens/tokens/cnam/cnamDarkTheme.ts +2 -2
  204. package/src/designTokens/tokens/cnam/cnamLightTheme.ts +76 -104
  205. package/src/designTokens/tokens/pa/paDarkTheme.ts +2 -2
  206. package/src/designTokens/tokens/pa/paLightTheme.ts +73 -99
  207. package/src/designTokens/tokens/pa/paSemantic.ts +2 -0
  208. package/src/designTokens/tokens/semanticTokens.ts +114 -0
  209. package/src/stories/Components/Components.stories.ts +7 -3
  210. package/src/stories/DesignTokens/ColorIntegrationExample.vue +2 -3
  211. package/src/stories/DesignTokens/Colors.mdx +6 -8
  212. package/src/stories/DesignTokens/colors.stories.ts +244 -1081
  213. package/src/utils/amelipro/toKebabCase/tests/toKebabCase.spec.ts +52 -0
  214. package/src/utils/formatNir/tests/formatNir.spec.ts +34 -0
  215. package/src/utils/tests/insertAt.spec.ts +44 -0
  216. package/dist/apLightTheme-DS0Uy44H.js +0 -954
  217. package/dist/components/RatingPicker/tests/RatingPicker.a11y.spect.d.ts +0 -1
  218. package/dist/main-BsJ9ec3i.js +0 -38954
  219. package/src/components/BackBtn/tests/__snapshots__/back-btn-custom-bg.snap.png +0 -0
  220. package/src/components/BackBtn/tests/__snapshots__/back-btn-dark-mode.snap.png +0 -0
  221. package/src/components/BackBtn/tests/__snapshots__/back-btn-default.snap.png +0 -0
  222. package/src/components/BackBtn/tests/__snapshots__/back-btn-no-icon.snap.png +0 -0
  223. package/src/components/DatePicker/CalendarMode/tests/DatePicker.events.spec.ts +0 -178
  224. package/src/components/DialogBox/tests/__snapshots__/dialog-box-custom-texts.snap.png +0 -0
  225. package/src/components/DialogBox/tests/__snapshots__/dialog-box-default.snap.png +0 -0
  226. package/src/components/DialogBox/tests/__snapshots__/dialog-box-no-actions.snap.png +0 -0
  227. package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/header-burger-menu-generated-submenu-open.snap.png +0 -0
  228. package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/header-burger-menu-generated.snap.png +0 -0
  229. package/src/components/HeaderBar/tests/__snapshots__/header-bar-custom-width.snap.png +0 -0
  230. package/src/components/HeaderBar/tests/__snapshots__/header-bar-default.snap.png +0 -0
  231. package/src/components/HeaderBar/tests/__snapshots__/header-bar-no-sticky.snap.png +0 -0
  232. package/src/components/HeaderBar/tests/__snapshots__/header-bar-with-prepend.snap.png +0 -0
  233. package/src/components/HeaderBar/tests/__snapshots__/header-bar-with-side.snap.png +0 -0
  234. package/src/components/HeaderBar/tests/__snapshots__/header-bar-with-subtitle.snap.png +0 -0
  235. package/src/components/Logo/tests/__snapshots__/logo-avatar.snap.png +0 -0
  236. package/src/components/Logo/tests/__snapshots__/logo-dark.snap.png +0 -0
  237. package/src/components/Logo/tests/__snapshots__/logo-default.snap.png +0 -0
  238. package/src/components/Logo/tests/__snapshots__/logo-no-organism.snap.png +0 -0
  239. package/src/components/Logo/tests/__snapshots__/logo-no-signature.snap.png +0 -0
  240. package/src/components/Logo/tests/__snapshots__/logo-risque-pro.snap.png +0 -0
  241. package/src/components/RangeField/tests/__snapshots__/range-field-custom-bg.snap.png +0 -0
  242. package/src/components/RangeField/tests/__snapshots__/range-field-custom-range.snap.png +0 -0
  243. package/src/components/RangeField/tests/__snapshots__/range-field-default.snap.png +0 -0
  244. package/src/components/RangeField/tests/__snapshots__/range-field-step.snap.png +0 -0
  245. package/src/components/RangeField/tests/__snapshots__/range-field-with-label.snap.png +0 -0
  246. package/src/components/SyAlert/tests/__snapshots__/sy-alert-closable.snap.png +0 -0
  247. package/src/components/SyAlert/tests/__snapshots__/sy-alert-error.snap.png +0 -0
  248. package/src/components/SyAlert/tests/__snapshots__/sy-alert-info.snap.png +0 -0
  249. package/src/components/SyAlert/tests/__snapshots__/sy-alert-success.snap.png +0 -0
  250. package/src/components/SyAlert/tests/__snapshots__/sy-alert-variant-outlined.snap.png +0 -0
  251. package/src/components/SyAlert/tests/__snapshots__/sy-alert-variant-tonal.snap.png +0 -0
  252. package/src/components/SyAlert/tests/__snapshots__/sy-alert-warning.snap.png +0 -0
  253. /package/src/components/RatingPicker/tests/{RatingPicker.a11y.spect.ts → RatingPicker.a11y.spec.ts} +0 -0
@@ -9,6 +9,7 @@ export { useDateTextField } from './useDateTextField'
9
9
  // Date selection and validation
10
10
  export { useDateSelection } from './useDateSelection'
11
11
  export { useDateValidation } from './useDateValidation'
12
+ export { useDatePickerValidationBridge } from './useDatePickerValidationBridge'
12
13
  export { useDateFormatValidation } from './useDateFormatValidation'
13
14
  export { useDateRangeValidation } from './useDateRangeValidation'
14
15
  export { useManualDateValidation } from './useManualDateValidation'
@@ -311,4 +311,364 @@ describe('useCalendarKeyboardNavigation', () => {
311
311
  addEventListenerSpy.mockRestore()
312
312
  vi.useRealTimers()
313
313
  })
314
+
315
+ it('handles Home/End/PageUp/PageDown navigation', () => {
316
+ vi.useFakeTimers()
317
+ const isDatePickerVisible = ref(true)
318
+ const getCurrentDate = vi.fn(() => new Date(2023, 0, 15))
319
+ const setCurrentDate = vi.fn()
320
+
321
+ let savedListener: ((e: KeyboardEvent) => void) | null = null
322
+ const addEventListenerSpy = vi.spyOn(document, 'addEventListener').mockImplementation((type, listener) => {
323
+ if (type === 'keydown') savedListener = listener as (e: KeyboardEvent) => void
324
+ })
325
+
326
+ let attachListeners!: () => void
327
+ const TestComponent = defineComponent({
328
+ setup() {
329
+ const result = useCalendarKeyboardNavigation({
330
+ isDatePickerVisible,
331
+ datePickerRef: ref(null),
332
+ getCurrentDate,
333
+ setCurrentDate,
334
+ })
335
+ attachListeners = result.attachListeners
336
+ return () => null
337
+ },
338
+ })
339
+ mount(TestComponent)
340
+ attachListeners()
341
+ vi.advanceTimersByTime(150)
342
+
343
+ const fireKey = (key: string, shiftKey = false) => {
344
+ setCurrentDate.mockClear()
345
+ const event = new KeyboardEvent('keydown', { key, shiftKey, bubbles: true })
346
+ Object.defineProperty(event, 'target', { value: document.createElement('div') })
347
+ savedListener!(event)
348
+ return setCurrentDate.mock.calls[0]?.[0] as Date | undefined
349
+ }
350
+
351
+ // Home → premier jour du mois (1 Jan)
352
+ const homeDate = fireKey('Home')
353
+ expect(homeDate?.getDate()).toBe(1)
354
+ expect(homeDate?.getMonth()).toBe(0)
355
+
356
+ // End → dernier jour du mois (31 Jan)
357
+ const endDate = fireKey('End')
358
+ expect(endDate?.getDate()).toBe(31)
359
+
360
+ // PageUp → premier jour du mois précédent (1 Dec 2022)
361
+ const pageUpDate = fireKey('PageUp')
362
+ expect(pageUpDate?.getDate()).toBe(1)
363
+ expect(pageUpDate?.getMonth()).toBe(11)
364
+ expect(pageUpDate?.getFullYear()).toBe(2022)
365
+
366
+ // PageDown → premier jour du mois suivant (1 Feb 2023)
367
+ const pageDownDate = fireKey('PageDown')
368
+ expect(pageDownDate?.getDate()).toBe(1)
369
+ expect(pageDownDate?.getMonth()).toBe(1)
370
+
371
+ // PageUp + Shift → année précédente (1 Jan 2022)
372
+ const pageUpShiftDate = fireKey('PageUp', true)
373
+ expect(pageUpShiftDate?.getFullYear()).toBe(2022)
374
+
375
+ // PageDown + Shift → année suivante (1 Jan 2024)
376
+ const pageDownShiftDate = fireKey('PageDown', true)
377
+ expect(pageDownShiftDate?.getFullYear()).toBe(2024)
378
+
379
+ addEventListenerSpy.mockRestore()
380
+ vi.useRealTimers()
381
+ })
382
+
383
+ it('handles Enter/Space on a day cell', () => {
384
+ vi.useFakeTimers()
385
+ const isDatePickerVisible = ref(true)
386
+ const setCurrentDate = vi.fn()
387
+
388
+ // Créer un rootEl contenant la cellule de jour (nécessaire pour clickDateButton)
389
+ const rootEl = document.createElement('div')
390
+ const dayWrapper = document.createElement('div')
391
+ dayWrapper.setAttribute('data-v-date', '2023-01-10')
392
+ dayWrapper.className = 'v-date-picker-month__day'
393
+ const btn = document.createElement('button')
394
+ btn.type = 'button'
395
+ const clickSpy = vi.spyOn(btn, 'click')
396
+ dayWrapper.appendChild(btn)
397
+ rootEl.appendChild(dayWrapper)
398
+ document.body.appendChild(rootEl)
399
+
400
+ // Le listener est attaché sur rootEl (fallback datePickerEl = rootEl), pas sur document
401
+ let savedListener: ((e: KeyboardEvent) => void) | null = null
402
+ const addSpy = vi.spyOn(rootEl, 'addEventListener').mockImplementation((type, listener) => {
403
+ if (type === 'keydown') savedListener = listener as (e: KeyboardEvent) => void
404
+ })
405
+
406
+ let attachListeners!: () => void
407
+ const TestComponent = defineComponent({
408
+ setup() {
409
+ const result = useCalendarKeyboardNavigation({
410
+ isDatePickerVisible,
411
+ datePickerRef: ref({ $el: rootEl } as unknown as ComponentPublicInstance),
412
+ getCurrentDate: vi.fn(() => new Date(2023, 0, 10)),
413
+ setCurrentDate,
414
+ })
415
+ attachListeners = result.attachListeners
416
+ return () => null
417
+ },
418
+ })
419
+ mount(TestComponent)
420
+ attachListeners()
421
+ vi.advanceTimersByTime(150)
422
+
423
+ const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })
424
+ Object.defineProperty(enterEvent, 'target', { value: btn })
425
+ savedListener!(enterEvent)
426
+
427
+ expect(clickSpy).toHaveBeenCalled()
428
+ document.body.removeChild(rootEl)
429
+
430
+ addSpy.mockRestore()
431
+ vi.useRealTimers()
432
+ })
433
+
434
+ it('handles Enter on header button (month/year control)', () => {
435
+ vi.useFakeTimers()
436
+ const isDatePickerVisible = ref(true)
437
+ const setCurrentDate = vi.fn()
438
+
439
+ let savedListener: ((e: KeyboardEvent) => void) | null = null
440
+ const addEventListenerSpy = vi.spyOn(document, 'addEventListener').mockImplementation((type, listener) => {
441
+ if (type === 'keydown') savedListener = listener as (e: KeyboardEvent) => void
442
+ })
443
+
444
+ let attachListeners!: () => void
445
+ const TestComponent = defineComponent({
446
+ setup() {
447
+ const result = useCalendarKeyboardNavigation({
448
+ isDatePickerVisible,
449
+ datePickerRef: ref(null),
450
+ getCurrentDate: vi.fn(() => null),
451
+ setCurrentDate,
452
+ })
453
+ attachListeners = result.attachListeners
454
+ return () => null
455
+ },
456
+ })
457
+ mount(TestComponent)
458
+ attachListeners()
459
+ vi.advanceTimersByTime(150)
460
+
461
+ // Simuler un bouton dans les contrôles d'entête
462
+ const controls = document.createElement('div')
463
+ controls.className = 'v-date-picker-controls'
464
+ const headerBtn = document.createElement('button')
465
+ const clickSpy = vi.spyOn(headerBtn, 'click')
466
+ controls.appendChild(headerBtn)
467
+ document.body.appendChild(controls)
468
+
469
+ const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })
470
+ Object.defineProperty(enterEvent, 'target', { value: headerBtn })
471
+ savedListener!(enterEvent)
472
+
473
+ expect(clickSpy).toHaveBeenCalled()
474
+ document.body.removeChild(controls)
475
+
476
+ addEventListenerSpy.mockRestore()
477
+ vi.useRealTimers()
478
+ })
479
+
480
+ it('handles ArrowLeft/Right/Up/Down in month dialog', () => {
481
+ vi.useFakeTimers()
482
+ const isDatePickerVisible = ref(true)
483
+ const setCurrentDate = vi.fn()
484
+
485
+ let savedListener: ((e: KeyboardEvent) => void) | null = null
486
+ const addEventListenerSpy = vi.spyOn(document, 'addEventListener').mockImplementation((type, listener) => {
487
+ if (type === 'keydown') savedListener = listener as (e: KeyboardEvent) => void
488
+ })
489
+
490
+ let attachListeners!: () => void
491
+ const TestComponent = defineComponent({
492
+ setup() {
493
+ const result = useCalendarKeyboardNavigation({
494
+ isDatePickerVisible,
495
+ datePickerRef: ref(null),
496
+ getCurrentDate: vi.fn(() => null),
497
+ setCurrentDate,
498
+ })
499
+ attachListeners = result.attachListeners
500
+ return () => null
501
+ },
502
+ })
503
+ mount(TestComponent)
504
+ attachListeners()
505
+ vi.advanceTimersByTime(150)
506
+
507
+ // Créer 3 boutons de mois dans le DOM
508
+ const monthsContainer = document.createElement('div')
509
+ monthsContainer.className = 'v-date-picker-months'
510
+ const buttons = Array.from({ length: 3 }, (_, i) => {
511
+ const b = document.createElement('button')
512
+ b.textContent = `Month ${i + 1}`
513
+ monthsContainer.appendChild(b)
514
+ return b
515
+ })
516
+ document.body.appendChild(monthsContainer)
517
+
518
+ const fireMonthKey = (key: string, targetBtn: HTMLButtonElement) => {
519
+ const event = new KeyboardEvent('keydown', { key, bubbles: true })
520
+ Object.defineProperty(event, 'target', { value: targetBtn })
521
+ savedListener!(event)
522
+ }
523
+
524
+ const focusSpy = vi.spyOn(buttons[1]!, 'focus')
525
+ // ArrowRight depuis bouton 0 → focus sur bouton 1
526
+ fireMonthKey('ArrowRight', buttons[0]!)
527
+ expect(focusSpy).toHaveBeenCalled()
528
+
529
+ // Enter sur un bouton de mois
530
+ const clickSpy = vi.spyOn(buttons[0]!, 'click')
531
+ fireMonthKey('Enter', buttons[0]!)
532
+ expect(clickSpy).toHaveBeenCalled()
533
+
534
+ document.body.removeChild(monthsContainer)
535
+ addEventListenerSpy.mockRestore()
536
+ vi.useRealTimers()
537
+ })
538
+
539
+ it('handles ArrowLeft/Right in year dialog', () => {
540
+ vi.useFakeTimers()
541
+ const isDatePickerVisible = ref(true)
542
+ const setCurrentDate = vi.fn()
543
+
544
+ let savedListener: ((e: KeyboardEvent) => void) | null = null
545
+ const addEventListenerSpy = vi.spyOn(document, 'addEventListener').mockImplementation((type, listener) => {
546
+ if (type === 'keydown') savedListener = listener as (e: KeyboardEvent) => void
547
+ })
548
+
549
+ let attachListeners!: () => void
550
+ const TestComponent = defineComponent({
551
+ setup() {
552
+ const result = useCalendarKeyboardNavigation({
553
+ isDatePickerVisible,
554
+ datePickerRef: ref(null),
555
+ getCurrentDate: vi.fn(() => null),
556
+ setCurrentDate,
557
+ })
558
+ attachListeners = result.attachListeners
559
+ return () => null
560
+ },
561
+ })
562
+ mount(TestComponent)
563
+ attachListeners()
564
+ vi.advanceTimersByTime(150)
565
+
566
+ // Créer 3 boutons d'années dans le DOM
567
+ const yearsContainer = document.createElement('div')
568
+ yearsContainer.className = 'v-date-picker-years'
569
+ const buttons = Array.from({ length: 3 }, (_, i) => {
570
+ const b = document.createElement('button')
571
+ b.textContent = `${2020 + i}`
572
+ yearsContainer.appendChild(b)
573
+ return b
574
+ })
575
+ document.body.appendChild(yearsContainer)
576
+
577
+ const fireYearKey = (key: string, targetBtn: HTMLButtonElement) => {
578
+ const event = new KeyboardEvent('keydown', { key, bubbles: true })
579
+ Object.defineProperty(event, 'target', { value: targetBtn })
580
+ savedListener!(event)
581
+ }
582
+
583
+ const focusSpy = vi.spyOn(buttons[1]!, 'focus')
584
+ // ArrowRight depuis bouton 0 → focus sur bouton 1
585
+ fireYearKey('ArrowRight', buttons[0]!)
586
+ expect(focusSpy).toHaveBeenCalled()
587
+
588
+ // Enter sur un bouton d'année
589
+ const clickSpy = vi.spyOn(buttons[0]!, 'click')
590
+ fireYearKey('Enter', buttons[0]!)
591
+ expect(clickSpy).toHaveBeenCalled()
592
+
593
+ document.body.removeChild(yearsContainer)
594
+ addEventListenerSpy.mockRestore()
595
+ vi.useRealTimers()
596
+ })
597
+
598
+ it('attaches on datePickerEl when no containerEl and detaches from it', () => {
599
+ vi.useFakeTimers()
600
+ const isDatePickerVisible = ref(true)
601
+
602
+ // Créer un rootEl avec .v-date-picker dedans
603
+ const rootEl = document.createElement('div')
604
+ const datePickerEl = document.createElement('div')
605
+ datePickerEl.className = 'v-date-picker'
606
+ rootEl.appendChild(datePickerEl)
607
+ document.body.appendChild(rootEl)
608
+
609
+ const addSpy = vi.spyOn(datePickerEl, 'addEventListener')
610
+ const removeSpy = vi.spyOn(datePickerEl, 'removeEventListener')
611
+
612
+ let detachListeners!: () => void
613
+ const TestComponent = defineComponent({
614
+ setup() {
615
+ const result = useCalendarKeyboardNavigation({
616
+ isDatePickerVisible,
617
+ datePickerRef: ref({ $el: rootEl } as unknown as ComponentPublicInstance),
618
+ getCurrentDate: vi.fn(() => null),
619
+ setCurrentDate: vi.fn(),
620
+ })
621
+ detachListeners = result.detachListeners
622
+ result.attachListeners()
623
+ vi.advanceTimersByTime(150)
624
+ return () => null
625
+ },
626
+ })
627
+ mount(TestComponent)
628
+
629
+ expect(addSpy).toHaveBeenCalledWith('keydown', expect.any(Function), true)
630
+
631
+ detachListeners()
632
+ expect(removeSpy).toHaveBeenCalledWith('keydown', expect.any(Function), true)
633
+
634
+ document.body.removeChild(rootEl)
635
+ vi.useRealTimers()
636
+ })
637
+
638
+ it('does not attach listener when already attached', () => {
639
+ vi.useFakeTimers()
640
+ const isDatePickerVisible = ref(true)
641
+
642
+ const addSpy = vi.spyOn(document, 'addEventListener')
643
+ let attachListeners!: () => void
644
+
645
+ const TestComponent = defineComponent({
646
+ setup() {
647
+ const result = useCalendarKeyboardNavigation({
648
+ isDatePickerVisible,
649
+ datePickerRef: ref(null),
650
+ getCurrentDate: vi.fn(() => null),
651
+ setCurrentDate: vi.fn(),
652
+ })
653
+ attachListeners = result.attachListeners
654
+ return () => null
655
+ },
656
+ })
657
+ mount(TestComponent)
658
+
659
+ const callsBefore = addSpy.mock.calls.length
660
+ attachListeners()
661
+ vi.advanceTimersByTime(150)
662
+ const callsAfterFirst = addSpy.mock.calls.length - callsBefore
663
+
664
+ // Second attach ne doit pas ajouter de listener supplémentaire
665
+ attachListeners()
666
+ vi.advanceTimersByTime(150)
667
+ const callsAfterSecond = addSpy.mock.calls.length - callsBefore
668
+
669
+ expect(callsAfterSecond).toBe(callsAfterFirst)
670
+
671
+ addSpy.mockRestore()
672
+ vi.useRealTimers()
673
+ })
314
674
  })
@@ -0,0 +1,129 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+ import { computed, nextTick, ref } from 'vue'
3
+ import { useDatePickerValidationBridge } from '../useDatePickerValidationBridge'
4
+ import type { DateObjectValue } from '../../types'
5
+
6
+ const createBridgeOptions = (overrides = {}) => ({
7
+ showSuccessMessages: true,
8
+ disableErrorHandling: false,
9
+ noCalendar: false,
10
+ required: false,
11
+ displayRange: false,
12
+ customRules: ref([]),
13
+ customWarningRules: ref([]),
14
+ selectedDates: ref<DateObjectValue>(null),
15
+ isUpdatingFromInternal: ref(false),
16
+ currentRangeIsValid: ref(true),
17
+ getRangeValidationError: ref(''),
18
+ ...overrides,
19
+ })
20
+
21
+ describe('useDatePickerValidationBridge', () => {
22
+ it('conserve un retour synchrone pour le flux standard', () => {
23
+ const selectedDates = ref<DateObjectValue>(new Date('2026-05-13'))
24
+ const { validateDates } = useDatePickerValidationBridge(createBridgeOptions({
25
+ selectedDates,
26
+ }))
27
+
28
+ const result = validateDates()
29
+
30
+ expect(result).not.toBeInstanceOf(Promise)
31
+ expect(result).toMatchObject({
32
+ hasError: false,
33
+ })
34
+ })
35
+
36
+ it('conserve le flux required specifique CalendarMode', async () => {
37
+ const { errors, validateDates } = useDatePickerValidationBridge(createBridgeOptions({
38
+ required: true,
39
+ useCalendarModeRequiredFlow: true,
40
+ isInitialValidation: ref(false),
41
+ isValidateOnBlur: computed(() => true),
42
+ onblur: ref(false),
43
+ }))
44
+
45
+ await validateDates(true)
46
+
47
+ expect(errors.value).toContain('La date est requise.')
48
+ })
49
+
50
+ it('court-circuite validateField en readonly quand demande', () => {
51
+ const readonly = ref(true)
52
+ const { validateField } = useDatePickerValidationBridge(createBridgeOptions({
53
+ readonly,
54
+ skipValidationWhenReadonly: true,
55
+ }))
56
+
57
+ const result = validateField(
58
+ new Date('2026-05-13'),
59
+ [{ type: 'custom', options: { validate: () => false, message: 'Erreur' } }],
60
+ )
61
+
62
+ expect(result).toMatchObject({
63
+ hasError: false,
64
+ state: {
65
+ errors: [],
66
+ warnings: [],
67
+ successes: [],
68
+ },
69
+ })
70
+ })
71
+
72
+ it('nettoie les messages quand readonly change sur le flux CalendarMode', async () => {
73
+ const readonly = ref(false)
74
+ const { errors } = useDatePickerValidationBridge(createBridgeOptions({
75
+ readonly,
76
+ skipValidationWhenReadonly: true,
77
+ }))
78
+
79
+ errors.value = ['Erreur persistante']
80
+ readonly.value = true
81
+ await nextTick()
82
+
83
+ expect(errors.value).toEqual([])
84
+ })
85
+
86
+ it('revalide les dates selectionnees quand les customRules changent si active', async () => {
87
+ const firstValidate = vi.fn(() => true)
88
+ const secondValidate = vi.fn(() => true)
89
+ const customRules = ref([
90
+ { type: 'custom', options: { validate: firstValidate } },
91
+ ])
92
+
93
+ useDatePickerValidationBridge(createBridgeOptions({
94
+ customRules,
95
+ selectedDates: ref<DateObjectValue>(new Date('2026-05-13')),
96
+ revalidateOnCustomRulesChange: true,
97
+ }))
98
+
99
+ customRules.value = [
100
+ { type: 'custom', options: { validate: secondValidate } },
101
+ ]
102
+
103
+ await nextTick()
104
+
105
+ expect(secondValidate).toHaveBeenCalledTimes(1)
106
+ expect(firstValidate).not.toHaveBeenCalled()
107
+ })
108
+
109
+ it('ne revalide pas les customRules si aucune date nest selectionnee', async () => {
110
+ const validate = vi.fn(() => true)
111
+ const customRules = ref([
112
+ { type: 'custom', options: { validate } },
113
+ ])
114
+
115
+ useDatePickerValidationBridge(createBridgeOptions({
116
+ customRules,
117
+ selectedDates: ref<DateObjectValue>(null),
118
+ revalidateOnCustomRulesChange: true,
119
+ }))
120
+
121
+ customRules.value = [
122
+ { type: 'custom', options: { validate } },
123
+ ]
124
+
125
+ await nextTick()
126
+
127
+ expect(validate).not.toHaveBeenCalled()
128
+ })
129
+ })
@@ -0,0 +1,205 @@
1
+ import { computed, watch, type Ref } from 'vue'
2
+ import { useValidation, type ValidationResult, type ValidationRule } from '@/composables/validation/useValidation'
3
+ import { DATE_PICKER_MESSAGES } from '../constants/messages'
4
+ import { useDateValidation } from './useDateValidation'
5
+ import type { DateObjectValue } from '../types'
6
+
7
+ export type DatePickerValidationRule = {
8
+ type: string
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- DatePicker rules are still legacy-shaped during migration.
10
+ options: any
11
+ }
12
+
13
+ export type DatePickerValidationBridgeOptions = {
14
+ showSuccessMessages: boolean
15
+ disableErrorHandling: boolean
16
+ noCalendar: boolean
17
+ required: boolean
18
+ displayRange: boolean
19
+ customRules: Ref<DatePickerValidationRule[]>
20
+ customWarningRules: Ref<DatePickerValidationRule[]>
21
+ selectedDates: Ref<DateObjectValue>
22
+ isUpdatingFromInternal: Ref<boolean>
23
+ currentRangeIsValid: Ref<boolean>
24
+ getRangeValidationError: Ref<string>
25
+ readonly?: Ref<boolean>
26
+ skipValidationWhenReadonly?: boolean
27
+ useCalendarModeRequiredFlow?: boolean
28
+ isInitialValidation?: Ref<boolean>
29
+ isValidateOnBlur?: Ref<boolean>
30
+ onblur?: Ref<boolean>
31
+ fieldIdentifier?: string
32
+ revalidateOnCustomRulesChange?: boolean
33
+ }
34
+
35
+ const emptyValidationResult = (): ValidationResult => ({
36
+ hasError: false,
37
+ hasWarning: false,
38
+ hasSuccess: false,
39
+ state: {
40
+ errors: [],
41
+ warnings: [],
42
+ successes: [],
43
+ },
44
+ })
45
+
46
+ export function useDatePickerValidationBridge(options: DatePickerValidationBridgeOptions) {
47
+ const validation = useValidation({
48
+ showSuccessMessages: options.showSuccessMessages,
49
+ fieldIdentifier: options.fieldIdentifier ?? 'Date',
50
+ disableErrorHandling: options.disableErrorHandling,
51
+ })
52
+
53
+ const {
54
+ errors,
55
+ warnings,
56
+ successes,
57
+ validateField: baseValidateField,
58
+ clearValidation: baseClearValidation,
59
+ } = validation
60
+
61
+ const clearValidation = () => baseClearValidation()
62
+
63
+ if (options.skipValidationWhenReadonly && options.readonly) {
64
+ watch(options.readonly, () => {
65
+ errors.value = []
66
+ warnings.value = []
67
+ successes.value = []
68
+ })
69
+ }
70
+
71
+ const validateField = (
72
+ value: unknown,
73
+ rules: ValidationRule[] = [],
74
+ warningRules: ValidationRule[] = [],
75
+ successRules: ValidationRule[] = [],
76
+ ): Promise<ValidationResult> | ValidationResult => {
77
+ if (options.skipValidationWhenReadonly && options.readonly?.value) {
78
+ return emptyValidationResult()
79
+ }
80
+
81
+ return baseValidateField(value, rules, warningRules, successRules)
82
+ }
83
+
84
+ const validateFieldForDateValidation = (
85
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Compatibility signature for legacy useDateValidation.
86
+ value: any,
87
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Compatibility signature for legacy useDateValidation.
88
+ rules: any[] = [],
89
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Compatibility signature for legacy useDateValidation.
90
+ warningRules: any[] = [],
91
+ ): ValidationResult | Promise<ValidationResult> => {
92
+ return validateField(value, rules, warningRules, [])
93
+ }
94
+
95
+ const { validateDates: coreValidateDates } = useDateValidation({
96
+ noCalendar: options.noCalendar,
97
+ required: options.useCalendarModeRequiredFlow ? false : options.required,
98
+ displayRange: options.displayRange,
99
+ disableErrorHandling: options.disableErrorHandling,
100
+ customRules: computed(() => options.customRules.value),
101
+ customWarningRules: computed(() => options.customWarningRules.value),
102
+ selectedDates: options.selectedDates,
103
+ isUpdatingFromInternal: options.isUpdatingFromInternal,
104
+ currentRangeIsValid: options.currentRangeIsValid,
105
+ getRangeValidationError: options.getRangeValidationError,
106
+ clearValidation,
107
+ validateField: validateFieldForDateValidation,
108
+ errors,
109
+ warnings,
110
+ successes,
111
+ })
112
+
113
+ if (options.revalidateOnCustomRulesChange) {
114
+ watch(options.customRules, () => {
115
+ if (options.selectedDates.value === null) {
116
+ return
117
+ }
118
+
119
+ queueMicrotask(async () => {
120
+ clearValidation()
121
+
122
+ const datesToValidate = Array.isArray(options.selectedDates.value)
123
+ ? options.selectedDates.value
124
+ : [options.selectedDates.value]
125
+
126
+ for (const date of datesToValidate) {
127
+ await Promise.resolve(validateField(
128
+ date,
129
+ options.customRules.value,
130
+ options.customWarningRules.value,
131
+ ))
132
+ }
133
+ })
134
+ }, { deep: true })
135
+ }
136
+
137
+ const validateCalendarModeDates = async (forceValidation = false) => {
138
+ if (!options.useCalendarModeRequiredFlow) {
139
+ return await Promise.resolve(coreValidateDates(forceValidation))
140
+ }
141
+
142
+ if (options.noCalendar) {
143
+ return
144
+ }
145
+
146
+ clearValidation()
147
+
148
+ const shouldDisplayErrors = !options.disableErrorHandling
149
+ const hasNoSelection = !options.selectedDates.value || (Array.isArray(options.selectedDates.value) && options.selectedDates.value.length === 0)
150
+
151
+ if ((forceValidation || !options.isUpdatingFromInternal.value) && options.required && hasNoSelection) {
152
+ if (options.readonly?.value) {
153
+ return
154
+ }
155
+ if (options.onblur?.value && !options.isValidateOnBlur?.value) {
156
+ return
157
+ }
158
+ if (shouldDisplayErrors && (!options.isInitialValidation?.value || forceValidation)) {
159
+ errors.value.push(DATE_PICKER_MESSAGES.ERROR_REQUIRED)
160
+ }
161
+ return
162
+ }
163
+
164
+ if (!options.selectedDates.value) {
165
+ if (!options.customRules.value || options.customRules.value.length === 0) return
166
+
167
+ if (shouldDisplayErrors && (!options.isInitialValidation?.value || forceValidation)) {
168
+ await validateField(
169
+ options.selectedDates.value,
170
+ options.customRules.value,
171
+ options.customWarningRules.value,
172
+ )
173
+ errors.value = [...new Set(errors.value)]
174
+ warnings.value = [...new Set(warnings.value)]
175
+ successes.value = [...new Set(successes.value)]
176
+ }
177
+ return
178
+ }
179
+
180
+ if (shouldDisplayErrors && (!options.isInitialValidation?.value || forceValidation)) {
181
+ return await Promise.resolve(coreValidateDates(forceValidation))
182
+ }
183
+ }
184
+
185
+ const validateDates = (forceValidation = false) => {
186
+ if (!options.useCalendarModeRequiredFlow) {
187
+ return coreValidateDates(forceValidation)
188
+ }
189
+
190
+ return validateCalendarModeDates(forceValidation)
191
+ }
192
+
193
+ return {
194
+ validation,
195
+ errors,
196
+ warnings,
197
+ successes,
198
+ errorMessages: errors,
199
+ warningMessages: warnings,
200
+ successMessages: validation.displaySuccesses,
201
+ clearValidation,
202
+ validateField,
203
+ validateDates,
204
+ }
205
+ }