@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
@@ -4,7 +4,7 @@
4
4
  inheritAttrs: false,
5
5
  })
6
6
  import { mdiAlertCircle, mdiAlertOutline, mdiCheck, mdiChevronDown, mdiClose, mdiCloseCircle, mdiInformationOutline } from '@mdi/js'
7
- import { ref, watch, watchEffect, onMounted, onBeforeUnmount, computed, nextTick, useAttrs, toRef, type Ref } from 'vue'
7
+ import { ref, watch, watchEffect, onMounted, onBeforeUnmount, computed, nextTick, useAttrs } from 'vue'
8
8
  import { useSySelectKeyboard } from './composables/useSySelectKeyboard'
9
9
  import type { ColorType, IconType, VariantStyle } from '@/types/vuetifyTypes'
10
10
  import type { VList, VTextField } from 'vuetify/components'
@@ -13,8 +13,8 @@
13
13
  import IconSlot from '@/components/Common/IconSlot/IconSlot.vue'
14
14
  import SyIcon from '@/components/Customs/SyIcon/SyIcon.vue'
15
15
  import { locales } from './locales'
16
- import type { ValidationRule } from '@/composables/validation/useValidation'
17
- import { useValidation, validationPropsDefaults, type FieldValidationProps } from '@/composables/unifyValidation/useValidation'
16
+ import { validationPropsDefaults, type FieldValidationProps } from '@/composables/unifyValidation/useValidation'
17
+ import { useSySelectValidation } from './composables/useSySelectValidation'
18
18
 
19
19
  export type ItemType = {
20
20
  [key: string]: unknown
@@ -121,9 +121,9 @@
121
121
 
122
122
  const iconColor = computed(() => {
123
123
  if (hasError.value) return 'error'
124
- if (hasWarning.value) return 'warning'
125
- if (hasSuccess.value) return 'success'
126
- return 'rgb(var(--v-theme-iconBase))'
124
+ if (hasWarning.value) return 'onWarningVariant'
125
+ if (hasSuccess.value) return 'onSuccessVariant'
126
+ return 'rgb(var(--v-theme-onSurface))'
127
127
  })
128
128
 
129
129
  const variant = computed(() => {
@@ -134,43 +134,9 @@
134
134
  const isOpen = ref(false)
135
135
  // Initialize selectedItem with props.modelValue or empty array for multiple mode
136
136
  const selectedItem = ref<SelectItemValueType | SelectItemArrayType>(props.modelValue)
137
- const focused = ref(false)
138
137
  const menuMinWidth = ref<number | null>(null)
139
138
 
140
- const defaultRules = computed<ValidationRule[]>(() => props.required
141
- ? [{
142
- type: 'required',
143
- options: {
144
- message: `Le champ ${props.label || 'ce champ'} est requis.`,
145
- fieldIdentifier: props.label,
146
- },
147
- }]
148
- : [],
149
- )
150
-
151
- const { validate, clearValidation, errors, warnings, successes, hasError, hasWarning, hasSuccess } = useValidation({
152
- modelValue: toRef(props, 'modelValue') as Ref<unknown>,
153
- readonly: toRef(props, 'readonly'),
154
- disabled: toRef(props, 'disabled'),
155
- required: toRef(props, 'required'),
156
- isValidateOnBlur: toRef(props, 'isValidateOnBlur'),
157
- showSuccessMessages: toRef(props, 'showSuccessMessages'),
158
- disableErrorHandling: toRef(props, 'disableErrorHandling'),
159
- useVuetifyValidation: toRef(props, 'useVuetifyValidation'),
160
- label: toRef(props, 'label'),
161
- rules: toRef(props, 'rules'),
162
- customRules: computed(() => [...defaultRules.value, ...(props.customRules ?? [])]),
163
- customWarningRules: toRef(props, 'customWarningRules'),
164
- customSuccessRules: toRef(props, 'customSuccessRules'),
165
- errorMessages: toRef(props, 'errorMessages'),
166
- warningMessages: toRef(props, 'warningMessages'),
167
- successMessages: toRef(props, 'successMessages'),
168
- hasErrorProp: toRef(props, 'hasError'),
169
- hasWarningProp: toRef(props, 'hasWarning'),
170
- hasSuccessProp: toRef(props, 'hasSuccess'),
171
- maxErrors: toRef(props, 'maxErrors'),
172
- focused: focused,
173
- })
139
+ const { focused, validate, clearValidation, errors, warnings, successes, hasError, hasWarning, hasSuccess, validationIcon } = useSySelectValidation(props)
174
140
 
175
141
  const labelWidth = ref(0)
176
142
  const labelRef = ref<HTMLElement | null>(null)
@@ -567,14 +533,6 @@
567
533
  return formattedErrorMessages.value || 'Le champ contient une erreur.'
568
534
  })
569
535
 
570
- const validationIcon = computed(() => {
571
- if (props.useVuetifyValidation) return null
572
- if (hasError.value) return mdiAlertCircle
573
- if (hasWarning.value) return mdiAlertOutline
574
- if (hasSuccess.value) return mdiCheck
575
- return null
576
- })
577
-
578
536
  watch(() => props.modelValue, (newValue) => {
579
537
  selectedItem.value = newValue
580
538
  })
@@ -944,6 +902,14 @@
944
902
  }
945
903
  }
946
904
 
905
+ const onBlur = () => {
906
+ // Trigger blur validation only when focus truly leaves the component.
907
+ // Skip if the menu is open — focus is moving to the dropdown list, not exiting.
908
+ if (!isOpen.value) {
909
+ validate()
910
+ }
911
+ }
912
+
947
913
  return {
948
914
  ...activatorProps,
949
915
  onKeydown: undefined,
@@ -953,7 +919,8 @@
953
919
  textInput.value = el
954
920
  activatorProps.ref?.(el)
955
921
  },
956
- onFocus: onFocus,
922
+ onFocus,
923
+ onBlur,
957
924
  }
958
925
  }
959
926
  </script>
@@ -1270,12 +1237,12 @@
1270
1237
 
1271
1238
  :deep(.v-input__prepend > .v-icon__svg),
1272
1239
  :deep(.v-input__append > .v-icon__svg) {
1273
- fill: rgb(var(--v-theme-iconBase));
1240
+ fill: rgb(var(--v-theme-onSurface));
1274
1241
  }
1275
1242
 
1276
1243
  :deep(.v-input__prepend .v-icon:focus-visible),
1277
1244
  :deep(.v-input__append .v-icon:focus-visible) {
1278
- outline: 2px solid rgb(var(--v-theme-borderAccentPrimary));
1245
+ outline: 2px solid rgb(var(--v-theme-primary));
1279
1246
  outline-offset: 2px;
1280
1247
  opacity: 1;
1281
1248
  }
@@ -1283,30 +1250,30 @@
1283
1250
 
1284
1251
  .warning-field {
1285
1252
  :deep(.v-icon__svg) {
1286
- fill: rgb(var(--v-theme-textWarning)) !important;
1253
+ fill: rgb(var(--v-theme-onWarningVariant)) !important;
1287
1254
  }
1288
1255
 
1289
1256
  :deep(.v-icon.arrow) {
1290
- color: rgb(var(--v-theme-iconBase)) !important;
1257
+ color: rgb(var(--v-theme-primary)) !important;
1291
1258
  }
1292
1259
 
1293
1260
  :deep(.v-icon.arrow .v-icon__svg) {
1294
- fill: rgb(var(--v-theme-iconBase)) !important;
1261
+ fill: rgb(var(--v-theme-primary)) !important;
1295
1262
  }
1296
1263
 
1297
1264
  :deep(.sy-select__clear-icon .v-icon__svg) {
1298
- fill: rgb(var(--v-theme-iconBase)) !important;
1265
+ fill: rgb(var(--v-theme-primary)) !important;
1299
1266
  }
1300
1267
 
1301
1268
  :deep(.v-field) {
1302
- color: rgb(var(--v-theme-borderWarning)) !important;
1269
+ color: rgb(var(--v-theme-onWarningVariant)) !important;
1303
1270
 
1304
1271
  --v-medium-emphasis-opacity: 1;
1305
1272
 
1306
1273
  .v-field__outline {
1307
1274
  --v-field-border-opacity: 1;
1308
1275
 
1309
- color: rgb(var(--v-theme-borderWarning)) !important;
1276
+ color: rgb(var(--v-theme-onWarningVariant)) !important;
1310
1277
  }
1311
1278
  }
1312
1279
 
@@ -1314,19 +1281,19 @@
1314
1281
  opacity: 1 !important;
1315
1282
 
1316
1283
  .v-messages__message {
1317
- color: rgb(var(--v-theme-borderWarning)) !important;
1284
+ color: rgb(var(--v-theme-onWarningVariant)) !important;
1318
1285
  }
1319
1286
  }
1320
1287
  }
1321
1288
 
1322
1289
  .error-field {
1323
1290
  :deep(.v-field) {
1324
- color: rgb(var(--v-theme-borderError)) !important;
1291
+ color: rgb(var(--v-theme-error)) !important;
1325
1292
 
1326
1293
  .v-field__outline {
1327
1294
  --v-field-border-opacity: 1;
1328
1295
 
1329
- color: rgb(var(--v-theme-borderError)) !important;
1296
+ color: rgb(var(--v-theme-error)) !important;
1330
1297
  }
1331
1298
  }
1332
1299
 
@@ -1334,45 +1301,45 @@
1334
1301
  opacity: 1 !important;
1335
1302
 
1336
1303
  .v-messages__message {
1337
- color: rgb(var(--v-theme-borderError)) !important;
1304
+ color: rgb(var(--v-theme-error)) !important;
1338
1305
  }
1339
1306
  }
1340
1307
 
1341
1308
  :deep(.v-icon.arrow) {
1342
- color: rgb(var(--v-theme-iconSubdued)) !important;
1309
+ color: rgb(var(--v-theme-onSurfaceVariant)) !important;
1343
1310
  }
1344
1311
 
1345
1312
  :deep(.v-icon.arrow .v-icon__svg) {
1346
- fill: rgb(var(--v-theme-iconSubdued)) !important;
1313
+ fill: rgb(var(--v-theme-onSurfaceVariant)) !important;
1347
1314
  }
1348
1315
  }
1349
1316
 
1350
1317
  .success-field {
1351
1318
  :deep(.v-icon__svg) {
1352
- fill: rgb(var(--v-theme-textSuccess)) !important;
1319
+ fill: rgb(var(--v-theme-onSuccessVariant)) !important;
1353
1320
  }
1354
1321
 
1355
1322
  :deep(.v-icon.arrow) {
1356
- color: rgb(var(--v-theme-iconBase)) !important;
1323
+ color: rgb(var(--v-theme-onSurface)) !important;
1357
1324
  }
1358
1325
 
1359
1326
  :deep(.v-icon.arrow .v-icon__svg) {
1360
- fill: rgb(var(--v-theme-iconBase)) !important;
1327
+ fill: rgb(var(--v-theme-onSurface)) !important;
1361
1328
  }
1362
1329
 
1363
1330
  :deep(.sy-select__clear-icon .v-icon__svg) {
1364
- fill: rgb(var(--v-theme-iconBase)) !important;
1331
+ fill: rgb(var(--v-theme-onSurface)) !important;
1365
1332
  }
1366
1333
 
1367
1334
  :deep(.v-field) {
1368
- color: rgb(var(--v-theme-borderSuccess)) !important;
1335
+ color: rgb(var(--v-theme-onSuccessVariant)) !important;
1369
1336
 
1370
1337
  --v-medium-emphasis-opacity: 1;
1371
1338
 
1372
1339
  .v-field__outline {
1373
1340
  --v-field-border-opacity: 1;
1374
1341
 
1375
- color: rgb(var(--v-theme-borderSuccess)) !important;
1342
+ color: rgb(var(--v-theme-onSuccessVariant)) !important;
1376
1343
  }
1377
1344
  }
1378
1345
 
@@ -1380,14 +1347,14 @@
1380
1347
  opacity: 1 !important;
1381
1348
 
1382
1349
  .v-messages__message {
1383
- color: rgb(var(--v-theme-borderSuccess)) !important;
1350
+ color: rgb(var(--v-theme-onSuccessVariant)) !important;
1384
1351
  }
1385
1352
  }
1386
1353
  }
1387
1354
 
1388
1355
  .basic-field {
1389
1356
  :deep(.v-field--focused .v-field__outline) {
1390
- color: rgb(var(--v-theme-borderAccentPrimary)) !important;
1357
+ color: rgb(var(--v-theme-primary)) !important;
1391
1358
  opacity: 1 !important;
1392
1359
  }
1393
1360
  }
@@ -1415,29 +1382,29 @@
1415
1382
  }
1416
1383
 
1417
1384
  .help-text {
1418
- color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
1385
+ color: rgba(var(--v-theme-onSurface), var(--v-medium-emphasis-opacity));
1419
1386
  font-size: var(--v-fontSize-liensEtLibelles);
1420
1387
  line-height: 1.2;
1421
1388
  }
1422
1389
 
1423
1390
  .help-text.text-disabled {
1424
- color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
1391
+ color: rgba(var(--v-theme-onSurface), var(--v-disabled-opacity));
1425
1392
  }
1426
1393
 
1427
1394
  .help-text-below {
1428
- color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
1395
+ color: rgba(var(--v-theme-onSurface), var(--v-medium-emphasis-opacity));
1429
1396
  font-size: var(--v-fontSize-liensEtLibelles);
1430
1397
  line-height: 1.2;
1431
1398
  }
1432
1399
 
1433
1400
  .help-text-below.text-disabled {
1434
- color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
1401
+ color: rgba(var(--v-theme-onSurface), var(--v-disabled-opacity));
1435
1402
  }
1436
1403
 
1437
1404
  /* Ensure focus styles match selection styles for keyboard navigation */
1438
1405
  .v-list-item:focus-visible,
1439
1406
  .v-list-item.keyboard-focused {
1440
- outline: 2px solid rgb(var(--v-theme-borderAccentPrimary));
1407
+ outline: 2px solid rgb(var(--v-theme-primary));
1441
1408
  outline-offset: -2px;
1442
1409
  background-color: rgb(0 0 0 / 8%);
1443
1410
  }
@@ -1467,7 +1434,7 @@
1467
1434
  }
1468
1435
 
1469
1436
  .sy-select__clear-icon {
1470
- color: rgb(var(--v-theme-iconBase)) !important;
1437
+ color: rgb(var(--v-theme-onSurface)) !important;
1471
1438
  opacity: var(--v-medium-emphasis-opacity) !important;
1472
1439
  }
1473
1440
 
@@ -1512,7 +1479,7 @@
1512
1479
 
1513
1480
  .sy-select :deep(.v-field__input) {
1514
1481
  opacity: 1;
1515
- color: rgb(var(--v-theme-iconBase)) !important;
1482
+ color: rgb(var(--v-theme-onSurface)) !important;
1516
1483
  cursor: pointer;
1517
1484
  caret-color: transparent;
1518
1485
  padding-right: 25px;
@@ -12,6 +12,7 @@ export interface UseSySelectKeyboardOptions {
12
12
  getItemText: (item: unknown) => unknown
13
13
  optionIdPrefix?: string
14
14
  focusListItem?: boolean
15
+ skipInitialFocus?: Ref<boolean>
15
16
  }
16
17
 
17
18
  export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
@@ -23,6 +24,7 @@ export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
23
24
  getItemText,
24
25
  optionIdPrefix = 'option',
25
26
  focusListItem = true,
27
+ skipInitialFocus,
26
28
  } = options
27
29
 
28
30
  const getOptionId = (index: number) => `${optionIdPrefix}-${index}`
@@ -339,6 +341,7 @@ export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
339
341
  // Gérer l'ouverture et la fermeture de la liste
340
342
  watch(isOpen, (open) => {
341
343
  if (open) {
344
+ if (skipInitialFocus?.value) return
342
345
  // À l'ouverture, restaurer le dernier focus ou initialiser au premier élément
343
346
  nextTick(() => {
344
347
  if (lastFocusedIndex.value >= 0 && lastFocusedIndex.value < formattedItems.value.length) {
@@ -0,0 +1,64 @@
1
+ import { computed, ref } from 'vue'
2
+ import { mdiAlertCircle, mdiAlertOutline, mdiCheck } from '@mdi/js'
3
+ import { useValidation, type FieldValidationProps } from '@/composables/unifyValidation/useValidation'
4
+ import type { ValidationRule } from '@/composables/validation/useValidation'
5
+
6
+ export function useSySelectValidation(props: FieldValidationProps & { modelValue?: unknown }) {
7
+ const focused = ref(false)
8
+
9
+ const defaultRules = computed<ValidationRule[]>(() => props.required
10
+ ? [{
11
+ type: 'required',
12
+ options: {
13
+ message: `Le champ ${props.label || 'ce champ'} est requis.`,
14
+ fieldIdentifier: props.label,
15
+ },
16
+ }]
17
+ : [],
18
+ )
19
+
20
+ const { validate, clearValidation, errors, warnings, successes, hasError, hasWarning, hasSuccess } = useValidation({
21
+ modelValue: computed(() => props.modelValue),
22
+ readonly: computed(() => props.readonly ?? false),
23
+ disabled: computed(() => props.disabled ?? false),
24
+ required: computed(() => props.required ?? false),
25
+ isValidateOnBlur: computed(() => props.isValidateOnBlur ?? false),
26
+ showSuccessMessages: computed(() => props.showSuccessMessages ?? false),
27
+ disableErrorHandling: computed(() => props.disableErrorHandling ?? false),
28
+ useVuetifyValidation: computed(() => props.useVuetifyValidation ?? false),
29
+ label: computed(() => props.label ?? ''),
30
+ rules: computed(() => props.rules ?? []),
31
+ customRules: computed(() => [...defaultRules.value, ...(props.customRules ?? [])]),
32
+ customWarningRules: computed(() => props.customWarningRules ?? []),
33
+ customSuccessRules: computed(() => props.customSuccessRules ?? []),
34
+ errorMessages: computed(() => props.errorMessages ?? []),
35
+ warningMessages: computed(() => props.warningMessages ?? []),
36
+ successMessages: computed(() => props.successMessages ?? []),
37
+ hasErrorProp: computed(() => props.hasError ?? false),
38
+ hasWarningProp: computed(() => props.hasWarning ?? false),
39
+ hasSuccessProp: computed(() => props.hasSuccess ?? false),
40
+ maxErrors: computed(() => props.maxErrors ?? 1),
41
+ focused,
42
+ })
43
+
44
+ const validationIcon = computed(() => {
45
+ if (props.useVuetifyValidation) return null
46
+ if (hasError.value) return mdiAlertCircle
47
+ if (hasWarning.value) return mdiAlertOutline
48
+ if (hasSuccess.value) return mdiCheck
49
+ return null
50
+ })
51
+
52
+ return {
53
+ focused,
54
+ validate,
55
+ clearValidation,
56
+ errors,
57
+ warnings,
58
+ successes,
59
+ hasError,
60
+ hasWarning,
61
+ hasSuccess,
62
+ validationIcon,
63
+ }
64
+ }
@@ -783,6 +783,202 @@ describe('SySelect.vue', () => {
783
783
 
784
784
  wrapper.unmount()
785
785
  })
786
+
787
+ it('ne valide pas lors d\'un changement de valeur mais seulement à la fermeture du menu quand isValidateOnBlur est true', async () => {
788
+ const wrapper = mount(SySelect, {
789
+ props: {
790
+ items: [
791
+ { text: 'Option 1', value: '1' },
792
+ { text: 'Option 2', value: '2' },
793
+ ],
794
+ label: 'Test Label',
795
+ modelValue: undefined,
796
+ isValidateOnBlur: true,
797
+ customRules: [{
798
+ type: 'custom',
799
+ options: {
800
+ validate: (value: unknown) => value === '2',
801
+ message: 'Test error message',
802
+ },
803
+ }],
804
+ },
805
+ attachTo: document.body,
806
+ })
807
+
808
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
809
+ const instance = wrapper.vm as any
810
+ expect(instance.hasError).toBe(false)
811
+
812
+ // Changement de valeur programmatique — l'erreur ne doit PAS apparaître
813
+ await wrapper.setProps({ modelValue: '1' })
814
+ await wrapper.vm.$nextTick()
815
+ expect(instance.hasError).toBe(false)
816
+
817
+ // Ouverture puis fermeture du menu (= blur) — l'erreur doit apparaître
818
+ await wrapper.find('.v-field').trigger('click')
819
+ await wrapper.vm.$nextTick()
820
+ await wrapper.find('.v-field').trigger('click')
821
+ await wrapper.vm.$nextTick()
822
+
823
+ await vi.waitUntil(() => instance.hasError === true)
824
+ expect(wrapper.find('.v-messages').text()).toContain('Test error message')
825
+
826
+ wrapper.unmount()
827
+ })
828
+
829
+ it('déclenche la validation au blur natif sans ouvrir le menu', async () => {
830
+ const wrapper = mount(SySelect, {
831
+ props: {
832
+ required: true,
833
+ label: 'Test Label',
834
+ modelValue: undefined,
835
+ items: [
836
+ { text: 'Option 1', value: '1' },
837
+ { text: 'Option 2', value: '2' },
838
+ ],
839
+ },
840
+ attachTo: document.body,
841
+ })
842
+
843
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
844
+ const instance = wrapper.vm as any
845
+ expect(instance.hasError).toBe(false)
846
+
847
+ // Simuler un blur natif sur l'input sans jamais ouvrir le menu
848
+ const input = wrapper.find('input')
849
+ await input.trigger('blur')
850
+ await wrapper.vm.$nextTick()
851
+
852
+ await vi.waitUntil(() => instance.hasError === true)
853
+ expect(wrapper.find('.v-messages').text()).toContain('requis')
854
+
855
+ wrapper.unmount()
856
+ })
857
+
858
+ it('affiche un avertissement avec customWarningRules', async () => {
859
+ const wrapper = mount(SySelect, {
860
+ props: {
861
+ items: [
862
+ { text: 'Option 1', value: '1' },
863
+ { text: 'Option 2', value: '2' },
864
+ ],
865
+ label: 'Test Label',
866
+ modelValue: undefined,
867
+ isValidateOnBlur: false,
868
+ customWarningRules: [{
869
+ type: 'custom',
870
+ options: {
871
+ validate: (value: unknown) => value === '2',
872
+ warningMessage: 'Option 1 est dépréciée.',
873
+ },
874
+ }],
875
+ },
876
+ attachTo: document.body,
877
+ })
878
+
879
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
880
+ const instance = wrapper.vm as any
881
+ expect(instance.hasWarning).toBe(false)
882
+
883
+ await wrapper.find('.v-field').trigger('click')
884
+ await wrapper.vm.$nextTick()
885
+ await wrapper.findComponent(VList).findAll('.v-list-item').at(0)!.trigger('click')
886
+ await wrapper.setProps({ modelValue: '1' })
887
+
888
+ await vi.waitUntil(() => instance.hasWarning === true)
889
+ expect(wrapper.find('.v-messages').text()).toContain('Option 1 est dépréciée.')
890
+
891
+ wrapper.unmount()
892
+ })
893
+
894
+ it('validateOnSubmit retourne true quand le champ est valide', async () => {
895
+ const wrapper = mount(SySelect, {
896
+ props: {
897
+ required: true,
898
+ label: 'Test Label',
899
+ modelValue: '1',
900
+ items: [
901
+ { text: 'Option 1', value: '1' },
902
+ { text: 'Option 2', value: '2' },
903
+ ],
904
+ },
905
+ attachTo: document.body,
906
+ })
907
+
908
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
909
+ const isValid = await (wrapper.vm as any).validateOnSubmit()
910
+ await nextTick()
911
+
912
+ expect(isValid).toBe(true)
913
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
914
+ expect((wrapper.vm as any).hasError).toBe(false)
915
+
916
+ wrapper.unmount()
917
+ })
918
+
919
+ it('affiche le message de succès avec customSuccessRules quand showSuccessMessages est true', async () => {
920
+ const wrapper = mount(SySelect, {
921
+ props: {
922
+ items: [
923
+ { text: 'Option 1', value: '1' },
924
+ { text: 'Option 2', value: '2' },
925
+ ],
926
+ label: 'Test Label',
927
+ modelValue: undefined,
928
+ isValidateOnBlur: false,
929
+ showSuccessMessages: true,
930
+ customSuccessRules: [{
931
+ type: 'custom',
932
+ options: {
933
+ validate: (value: unknown) => value === '2',
934
+ successMessage: 'Test success message',
935
+ },
936
+ }],
937
+ },
938
+ attachTo: document.body,
939
+ })
940
+
941
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
942
+ const instance = wrapper.vm as any
943
+ expect(instance.hasSuccess).toBe(false)
944
+
945
+ await wrapper.setProps({ modelValue: '2' })
946
+
947
+ await vi.waitUntil(() => instance.hasSuccess === true)
948
+ expect(wrapper.find('.success-field').exists()).toBe(true)
949
+ expect(wrapper.find('.v-messages').text()).toContain('Test success message')
950
+
951
+ wrapper.unmount()
952
+ })
953
+
954
+ it('clearValidation remet l\'état d\'erreur à zéro', async () => {
955
+ const wrapper = mount(SySelect, {
956
+ props: {
957
+ required: true,
958
+ label: 'Test Label',
959
+ modelValue: undefined,
960
+ items: [
961
+ { text: 'Option 1', value: '1' },
962
+ { text: 'Option 2', value: '2' },
963
+ ],
964
+ },
965
+ attachTo: document.body,
966
+ })
967
+
968
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
969
+ const instance = wrapper.vm as any
970
+
971
+ await instance.validateOnSubmit()
972
+ await nextTick()
973
+ expect(instance.hasError).toBe(true)
974
+
975
+ instance.clearValidation()
976
+ await nextTick()
977
+ expect(instance.hasError).toBe(false)
978
+ expect(wrapper.find('.v-messages__message').exists()).toBe(false)
979
+
980
+ wrapper.unmount()
981
+ })
786
982
  })
787
983
 
788
984
  describe('Comportement du menu', () => {