@cnamts/synapse 1.0.23 → 1.0.24

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 (292) hide show
  1. package/dist/AutocompleteFilter-BWLR3U7W.js +114 -0
  2. package/dist/AutocompleteFilter-D9jzRzAL.cjs +1 -0
  3. package/dist/{DateFilter-Dc-gSGwk.js → DateFilter-BpwFexzi.js} +1 -1
  4. package/dist/DateFilter-DTUl8hb1.cjs +1 -0
  5. package/dist/{NumberFilter-vP38Wp6j.js → NumberFilter-Bz_NTdX9.js} +3 -3
  6. package/dist/NumberFilter-MAEojdk0.cjs +1 -0
  7. package/dist/PeriodFilter-CC4WgIhl.cjs +1 -0
  8. package/dist/{PeriodFilter-Ba1uYUnT.js → PeriodFilter-DX_wy9g-.js} +1 -1
  9. package/dist/SelectFilter-BR3fvl-a.cjs +1 -0
  10. package/dist/SelectFilter-xqiPtPgX.js +135 -0
  11. package/dist/{TextFilter-B84dpnoq.js → TextFilter-BBl3JFqK.js} +7 -7
  12. package/dist/TextFilter-CCfYFl5F.cjs +1 -0
  13. package/dist/apLightTheme-CFSRrjv2.cjs +1 -0
  14. package/dist/apLightTheme-D1P4jcD0.js +1231 -0
  15. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +7022 -9616
  16. package/dist/components/Amelipro/AmeliproCarousel/AmeliproCarousel.d.ts +2 -2
  17. package/dist/components/Amelipro/AmeliproIconBtn/AmeliproIconBtn.d.ts +2 -2
  18. package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/AmeliproPostalAddressCityRow.d.ts +40 -40
  19. package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +60 -60
  20. package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +7168 -9762
  21. package/dist/components/Amelipro/AmeliproStepper/AmeliproStepper.d.ts +2 -2
  22. package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +7501 -10095
  23. package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +21 -21
  24. package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +41 -41
  25. package/dist/components/Amelipro/StructureMenu/StructureTabs/StructureTabs.d.ts +2 -2
  26. package/dist/components/CookiesSelection/CookiesInformation/CookiesInformation.d.ts +20 -498
  27. package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +108 -146
  28. package/dist/components/Customs/Selects/SyInputSelect/SyInputSelect.d.ts +5 -5
  29. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +12 -16
  30. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +8 -8
  31. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +28 -506
  32. package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +28 -506
  33. package/dist/components/Customs/SyTextField/SyTextField.d.ts +65 -85
  34. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +627 -771
  35. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +315 -402
  36. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +112 -155
  37. package/dist/components/DatePicker/composables/index.d.ts +1 -0
  38. package/dist/components/DatePicker/composables/useDatePickerFocusTrap.d.ts +11 -0
  39. package/dist/components/DatePicker/composables/useDateTextField.d.ts +4 -4
  40. package/dist/components/DatePicker/composables/useDateValidation.d.ts +3 -3
  41. package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +2 -2
  42. package/dist/components/DatePicker/composables/useManualDateValidation.d.ts +2 -2
  43. package/dist/components/HeaderNavigationBar/HeaderNavigationBar.d.ts +4 -4
  44. package/dist/components/HeaderToolbar/HeaderToolbar.d.ts +20 -28
  45. package/dist/components/LunarCalendar/useLunarCalendarValidation.d.ts +3 -3
  46. package/dist/components/MonthPicker/MonthPicker.d.ts +86 -122
  47. package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +85 -121
  48. package/dist/components/NirField/NirField.d.ts +206 -270
  49. package/dist/components/NirField/locales.d.ts +10 -10
  50. package/dist/components/NirField/useNirValidation.d.ts +64 -0
  51. package/dist/components/PasswordField/PasswordField.d.ts +8 -9
  52. package/dist/components/PeriodField/PeriodField.d.ts +1352 -1640
  53. package/dist/components/PhoneField/PhoneField.d.ts +88 -124
  54. package/dist/components/RangeField/RangeSlider/RangeSlider.d.ts +12 -12
  55. package/dist/components/SyTextArea/SyTextArea.d.ts +34 -14
  56. package/dist/components/SyTextArea/useDefaultValidationRules.d.ts +11 -0
  57. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +9 -6
  58. package/dist/components/Tables/SyTable/SyTable.d.ts +9 -6
  59. package/dist/components/Tables/common/SyTableFilter.d.ts +2 -3
  60. package/dist/components/Tables/common/SyTablePagination.d.ts +17 -19
  61. package/dist/components/Tables/common/filters/AutocompleteFilter.d.ts +120 -0
  62. package/dist/components/Tables/common/filters/locales.d.ts +0 -1
  63. package/dist/components/Tables/common/types.d.ts +19 -3
  64. package/dist/components/Tables/common/useClickableTableRow.d.ts +17 -0
  65. package/dist/components/Tables/common/usePagination.d.ts +3 -1
  66. package/dist/components/Tables/common/usePinnedColumns.d.ts +31 -0
  67. package/dist/components/Tables/common/useTableHeaders.d.ts +2 -0
  68. package/dist/components/Tables/common/useTableRowCheckboxAccessibility.d.ts +5 -0
  69. package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +6 -6
  70. package/dist/composables/date/useDatePickerAccessibility.d.ts +1 -1
  71. package/dist/composables/rules/useFieldValidation.d.ts +4 -4
  72. package/dist/composables/unifyValidation/useCustomValidation.d.ts +8 -0
  73. package/dist/composables/unifyValidation/useValidation.d.ts +102 -0
  74. package/dist/composables/unifyValidation/useVuetifyValidation.d.ts +18 -0
  75. package/dist/composables/useFormFieldErrorHandling.d.ts +2 -2
  76. package/dist/composables/validation/useFormValidation.d.ts +11 -2
  77. package/dist/composables/validation/useValidation.d.ts +15 -9
  78. package/dist/design-system-v3.d.ts +2 -0
  79. package/dist/design-system-v3.js +186 -187
  80. package/dist/design-system-v3.umd.cjs +1 -1066
  81. package/dist/{main-aLKwdMi1.js → main-BtTqyn4z.js} +16434 -15672
  82. package/dist/main-C1e3eoxd.cjs +1067 -0
  83. package/dist/main.d.ts +0 -1
  84. package/dist/synapse.css +1 -0
  85. package/dist/tooth-11-D3sLWv2n.cjs +1 -0
  86. package/dist/tooth-12-CXrLuH03.cjs +1 -0
  87. package/dist/tooth-13-BSfo5fpT.cjs +1 -0
  88. package/dist/tooth-14-DMzulx0h.cjs +1 -0
  89. package/dist/tooth-15-BKRFVi-9.cjs +1 -0
  90. package/dist/tooth-16-CpuxAbuM.cjs +1 -0
  91. package/dist/tooth-17-BPoahUdg.cjs +1 -0
  92. package/dist/tooth-18-DhHJz8sy.cjs +1 -0
  93. package/dist/tooth-21-Dgd5hn_X.cjs +1 -0
  94. package/dist/tooth-22-C2Tn19sB.cjs +1 -0
  95. package/dist/tooth-23-C9uaaSGb.cjs +1 -0
  96. package/dist/tooth-24-BrK9UGpf.cjs +1 -0
  97. package/dist/tooth-25-CE_EfGNp.cjs +1 -0
  98. package/dist/tooth-26-Ctv4i9Fy.cjs +1 -0
  99. package/dist/tooth-27-C5J7JkWM.cjs +1 -0
  100. package/dist/tooth-28-Z9oWqjo0.cjs +1 -0
  101. package/dist/tooth-31-BrYqmkTi.cjs +1 -0
  102. package/dist/tooth-32-BNNR0oCZ.cjs +1 -0
  103. package/dist/tooth-33-DuxvqO2J.cjs +1 -0
  104. package/dist/tooth-34-BCSCXMB6.cjs +1 -0
  105. package/dist/tooth-35-BLUXkX88.cjs +1 -0
  106. package/dist/tooth-36-IrKHYqlA.cjs +1 -0
  107. package/dist/tooth-37-BYqpdMwo.cjs +1 -0
  108. package/dist/tooth-38-B_eNXXdu.cjs +1 -0
  109. package/dist/tooth-41-Ddva4Ot8.cjs +1 -0
  110. package/dist/tooth-42-szcDqlM0.cjs +1 -0
  111. package/dist/tooth-43-B3ka6rQm.cjs +1 -0
  112. package/dist/tooth-44-CazyQucj.cjs +1 -0
  113. package/dist/tooth-45-B4HQtc8n.cjs +1 -0
  114. package/dist/tooth-46-BPM40gbG.cjs +1 -0
  115. package/dist/tooth-47-Dvr20dlh.cjs +1 -0
  116. package/dist/tooth-48-Bd8ljGsF.cjs +1 -0
  117. package/dist/tooth-51-OBpwCOF3.cjs +1 -0
  118. package/dist/tooth-52-aKxyHcmq.cjs +1 -0
  119. package/dist/tooth-53-vCwJjTOc.cjs +1 -0
  120. package/dist/tooth-54-DsWu2iFy.cjs +1 -0
  121. package/dist/tooth-55-BxC1X2Dn.cjs +1 -0
  122. package/dist/tooth-61-BbLvxMQi.cjs +1 -0
  123. package/dist/tooth-62-CmTkWczP.cjs +1 -0
  124. package/dist/tooth-63-DI7l_2qI.cjs +1 -0
  125. package/dist/tooth-64-B21sOsJh.cjs +1 -0
  126. package/dist/tooth-65-D2ZC2VEr.cjs +1 -0
  127. package/dist/tooth-71-D473PPO5.cjs +1 -0
  128. package/dist/tooth-72-Drh1wnNu.cjs +1 -0
  129. package/dist/tooth-73-DzlwYI23.cjs +1 -0
  130. package/dist/tooth-74-8aGvcZPg.cjs +1 -0
  131. package/dist/tooth-75-BFK7At_r.cjs +1 -0
  132. package/dist/tooth-81-BZmR-I0M.cjs +1 -0
  133. package/dist/tooth-82-euVfUUZV.cjs +1 -0
  134. package/dist/tooth-83-KV010j64.cjs +1 -0
  135. package/dist/tooth-84-BBg1RjhZ.cjs +1 -0
  136. package/dist/tooth-85-Cr-kc1wM.cjs +1 -0
  137. package/dist/vuetifyConfig.js +561 -0
  138. package/dist/vuetifyConfig.umd.cjs +1 -0
  139. package/package.json +10 -4
  140. package/src/assets/overrides/_btns.scss +0 -6
  141. package/src/assets/overrides/_icons.scss +9 -1
  142. package/src/assets/overrides/_typography.scss +0 -10
  143. package/src/components/Amelipro/AmeliproAutoCompleteField/__tests__/__snapshots__/AmeliproAutoCompleteField.spec.ts.snap +2 -2
  144. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/__tests__/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +1 -1
  145. package/src/components/Amelipro/AmeliproTextArea/__tests__/__snapshots__/AmeliproTextArea.spec.ts.snap +2 -2
  146. package/src/components/Captcha/accessibilite/Accessibility.mdx +86 -8
  147. package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +12 -12
  148. package/src/components/ChipList/ChipList.stories.ts +0 -15
  149. package/src/components/ChipList/ChipList.vue +5 -1
  150. package/src/components/ChipList/accessibilite/Accessibility.mdx +83 -10
  151. package/src/components/ChipList/tests/ChipList.a11y.spec.ts +41 -0
  152. package/src/components/Customs/Selects/SelectBtnField/accessibilite/Accessibility.mdx +0 -9
  153. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +22 -5
  154. package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.spec.ts +143 -0
  155. package/src/components/Customs/Selects/SyAutocomplete/utils/ariaManager.ts +14 -10
  156. package/src/components/Customs/Selects/SyInputSelect/SyInputSelect.stories.ts +4 -4
  157. package/src/components/Customs/Selects/SyInputSelect/SyInputSelect.vue +8 -9
  158. package/src/components/Customs/Selects/SyInputSelect/tests/SyInputSelect.spec.ts +10 -10
  159. package/src/components/Customs/Selects/SySelect/SySelect.vue +14 -11
  160. package/src/components/Customs/Selects/SySelect/tests/SySelect.spec.ts +54 -0
  161. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +6 -9
  162. package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +10 -16
  163. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +16 -11
  164. package/src/components/Customs/SyCheckbox/accessibilite/Accessibility.mdx +35 -0
  165. package/src/components/Customs/SyCheckbox/tests/SyCheckbox.a11y.spec.ts +134 -2
  166. package/src/components/Customs/SyForm/SyForm.stories.ts +31 -5
  167. package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +4 -7
  168. package/src/components/Customs/SyTextField/SyTextField.mdx +1 -1
  169. package/src/components/Customs/SyTextField/SyTextField.stories.ts +29 -27
  170. package/src/components/Customs/SyTextField/SyTextField.vue +154 -157
  171. package/src/components/Customs/SyTextField/tests/SyTextField.a11y.spec.ts +32 -0
  172. package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +120 -11
  173. package/src/components/DatePicker/CalendarMode/DatePicker.stories.ts +62 -58
  174. package/src/components/DatePicker/CalendarMode/DatePicker.vue +330 -223
  175. package/src/components/DatePicker/CalendarMode/accessibilite/Accessibility.mdx +82 -0
  176. package/src/components/DatePicker/CalendarMode/tests/DatePicker.a11y.spec.ts +141 -0
  177. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +2 -56
  178. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +195 -159
  179. package/src/components/DatePicker/ComplexDatePicker/accessibilite/Accessibility.mdx +76 -0
  180. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +10 -10
  181. package/src/components/DatePicker/DatePickerValidationExample/CalendarMode.stories.ts +8 -8
  182. package/src/components/DatePicker/DatePickerValidationExample/ComplexDatePicker.stories.ts +106 -8
  183. package/src/components/DatePicker/DatePickerValidationExample/DateTextInput.stories.ts +12 -11
  184. package/src/components/DatePicker/DatePickerValidationExample/MultiMode.stories.ts +12 -12
  185. package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +0 -12
  186. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +63 -57
  187. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +3 -0
  188. package/src/components/DatePicker/DateTextInput/accessibilite/Accessibility.mdx +66 -0
  189. package/src/components/DatePicker/DateTextInput/tests/DateTextInput.spec.ts +52 -1
  190. package/src/components/DatePicker/composables/index.ts +1 -0
  191. package/src/components/DatePicker/composables/tests/useCalendarKeyboardNavigation.spec.ts +109 -65
  192. package/src/components/DatePicker/composables/tests/useDatePickerFocusTrap.spec.ts +138 -0
  193. package/src/components/DatePicker/composables/tests/useDateValidation.spec.ts +74 -18
  194. package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +39 -0
  195. package/src/components/DatePicker/composables/tests/useManualDateValidation.spec.ts +91 -0
  196. package/src/components/DatePicker/composables/useCalendarKeyboardNavigation.ts +442 -36
  197. package/src/components/DatePicker/composables/useDatePickerFocusTrap.ts +92 -0
  198. package/src/components/DatePicker/composables/useDateTextField.ts +7 -6
  199. package/src/components/DatePicker/composables/useDateValidation.ts +36 -35
  200. package/src/components/DatePicker/composables/useInputBlurHandler.ts +3 -3
  201. package/src/components/DatePicker/composables/useManualDateValidation.ts +6 -2
  202. package/src/components/DiacriticPicker/accessibilite/Accessibility.mdx +76 -8
  203. package/src/components/HeaderBar/HeaderBar.stories.ts +14 -2
  204. package/src/components/Logo/accessibilite/Accessibility.mdx +73 -11
  205. package/src/components/LogoBrandSection/accessibilite/Accessibility.mdx +85 -9
  206. package/src/components/LunarCalendar/tests/LunarCalendar.spec.ts +3 -1
  207. package/src/components/LunarCalendar/useLunarCalendarValidation.ts +4 -5
  208. package/src/components/MonthPicker/tests/MonthPicker.spec.ts +2 -1
  209. package/src/components/MonthPicker/tests/__snapshots__/MonthPicker.spec.ts.snap +7 -7
  210. package/src/components/NirField/NirField.stories.ts +4 -0
  211. package/src/components/NirField/NirField.vue +64 -260
  212. package/src/components/NirField/accessibilite/Accessibility.mdx +2 -2
  213. package/src/components/NirField/locales.ts +1 -1
  214. package/src/components/NirField/tests/NirField.spec.ts +6 -0
  215. package/src/components/NirField/useNirValidation.ts +271 -0
  216. package/src/components/PasswordField/PasswordField.stories.ts +4 -4
  217. package/src/components/PasswordField/PasswordField.vue +18 -24
  218. package/src/components/PasswordField/tests/PasswordField.spec.ts +6 -3
  219. package/src/components/PeriodField/PeriodField.stories.ts +4 -4
  220. package/src/components/PeriodField/PeriodField.vue +57 -57
  221. package/src/components/PeriodField/__tests__/PeriodField.async.spec.ts +32 -0
  222. package/src/components/PeriodField/accessibilite/Accessibility.mdx +68 -8
  223. package/src/components/PeriodField/tests/PeriodField.spec.ts +28 -2
  224. package/src/components/PhoneField/PhoneField.vue +5 -6
  225. package/src/components/PhoneField/tests/PhoneField.spec.ts +1 -0
  226. package/src/components/RangeField/RangeField.vue +6 -0
  227. package/src/components/SyTextArea/SyTextArea.stories.ts +138 -2
  228. package/src/components/SyTextArea/SyTextArea.vue +53 -23
  229. package/src/components/SyTextArea/tests/SyTextArea.spec.ts +126 -3
  230. package/src/components/SyTextArea/useDefaultValidationRules.ts +74 -0
  231. package/src/components/Tables/SyServerTable/SyServerTable.mdx +25 -0
  232. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +673 -1
  233. package/src/components/Tables/SyServerTable/SyServerTable.vue +148 -91
  234. package/src/components/Tables/SyServerTable/tests/SyServerTable.a11y.spec.ts +58 -0
  235. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +122 -0
  236. package/src/components/Tables/SyTable/SyTable.mdx +25 -0
  237. package/src/components/Tables/SyTable/SyTable.stories.ts +452 -1
  238. package/src/components/Tables/SyTable/SyTable.vue +130 -56
  239. package/src/components/Tables/SyTable/tests/SyTable.a11y.spec.ts +57 -0
  240. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +108 -0
  241. package/src/components/Tables/common/SyTableFilter.vue +22 -2
  242. package/src/components/Tables/common/TableHeader.vue +5 -1
  243. package/src/components/Tables/common/filters/AutocompleteFilter.vue +160 -0
  244. package/src/components/Tables/common/filters/NumberFilter.vue +1 -1
  245. package/src/components/Tables/common/filters/SelectFilter.vue +10 -11
  246. package/src/components/Tables/common/filters/TextFilter.vue +1 -1
  247. package/src/components/Tables/common/filters/getFilterComponent.ts +8 -1
  248. package/src/components/Tables/common/filters/locales.ts +0 -1
  249. package/src/components/Tables/common/filters/tests/AutocompleteFilter.a11y.spec.ts +110 -0
  250. package/src/components/Tables/common/filters/tests/AutocompleteFilter.spec.ts +203 -0
  251. package/src/components/Tables/common/filters/tests/SelectFilter.a11y.spec.ts +104 -0
  252. package/src/components/Tables/common/filters/tests/SelectFilter.spec.ts +152 -16
  253. package/src/components/Tables/common/tableFilterUtils.ts +3 -0
  254. package/src/components/Tables/common/tableStyles.scss +48 -4
  255. package/src/components/Tables/common/tests/filterByRange.spec.ts +2 -1
  256. package/src/components/Tables/common/types.ts +13 -4
  257. package/src/components/Tables/common/useClickableTableRow.ts +103 -0
  258. package/src/components/Tables/common/usePagination.ts +13 -0
  259. package/src/components/Tables/common/usePinnedColumns.ts +237 -0
  260. package/src/components/Tables/common/useTableHeaders.ts +3 -3
  261. package/src/components/Tables/common/useTableRowCheckboxAccessibility.ts +41 -0
  262. package/src/composables/date/tests/useDatePickerAccessibility.spec.ts +2 -6
  263. package/src/composables/date/useDatePickerAccessibility.ts +42 -207
  264. package/src/composables/rules/tests/useFieldValidation.spec.ts +120 -120
  265. package/src/composables/rules/useFieldValidation.ts +34 -17
  266. package/src/composables/unifyValidation/tests/useCustomValidation.spec.ts +601 -0
  267. package/src/composables/unifyValidation/tests/useValidation.spec.ts +2048 -0
  268. package/src/composables/unifyValidation/tests/useVuetifyValidation.spec.ts +184 -0
  269. package/src/composables/unifyValidation/useCustomValidation.ts +95 -0
  270. package/src/composables/unifyValidation/useValidation.ts +190 -0
  271. package/src/composables/unifyValidation/useVuetifyValidation.ts +54 -0
  272. package/src/composables/useFormFieldErrorHandling.ts +4 -7
  273. package/src/composables/validation/tests/useFormValidation.spec.ts +14 -0
  274. package/src/composables/validation/tests/useValidation.spec.ts +116 -21
  275. package/src/composables/validation/useFormValidation.ts +20 -13
  276. package/src/composables/validation/useValidatable.ts +8 -1
  277. package/src/composables/validation/useValidation.ts +135 -99
  278. package/src/composantsVuetify/Introduction.mdx +48 -0
  279. package/src/composantsVuetify/VBtn/VBtn.mdx +72 -0
  280. package/src/composantsVuetify/VBtn/v-btn.stories.ts +121 -0
  281. package/src/composantsVuetify/VTooltip/VTooltip.mdx +32 -0
  282. package/src/composantsVuetify/VTooltip/v-tooltip.stories.ts +95 -0
  283. package/src/designTokens/tokens/cnam/cnamSemantic.ts +2 -2
  284. package/src/main.ts +0 -2
  285. package/src/stories/Components/Components.stories.ts +74 -9
  286. package/src/stories/Demarrer/Accueil.stories.ts +3 -3
  287. package/src/stories/GuideDuDev/Amelipro.mdx +15 -0
  288. package/src/stories/GuideDuDev/Amelipro.stories.ts +209 -0
  289. package/src/stories/GuideDuDev/vuetifyOptions.mdx +3 -3
  290. package/dist/SelectFilter-BioGT6Nn.js +0 -136
  291. package/dist/style.css +0 -1
  292. package/src/components/DatePicker/Accessibilite.mdx +0 -14
@@ -0,0 +1,160 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import type { FilterOption, TableColumnHeader } from '../types'
4
+ import SyAutocomplete from '@/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue'
5
+
6
+ const props = defineProps({
7
+ header: {
8
+ type: Object as () => TableColumnHeader,
9
+ required: true,
10
+ },
11
+ filters: {
12
+ type: Array as () => FilterOption[],
13
+ default: () => [],
14
+ },
15
+ filterValue: {
16
+ type: [String, Number, Object, Array, undefined, null] as unknown as () => string | number | Record<string, unknown> | Array<string | number | Record<string, unknown>> | undefined | null,
17
+ default: null,
18
+ },
19
+ inputConfig: {
20
+ type: Object as () => {
21
+ disableErrorHandling?: boolean
22
+ variant?: string
23
+ hideDetails?: boolean
24
+ density?: 'default' | 'comfortable' | 'compact'
25
+ backgroundColor?: string
26
+ clearable?: boolean
27
+ },
28
+ default: () => ({}),
29
+ },
30
+ disableErrorHandling: {
31
+ type: Boolean,
32
+ default: false,
33
+ },
34
+ variant: {
35
+ type: String,
36
+ default: 'outlined',
37
+ },
38
+ hideDetails: {
39
+ type: Boolean,
40
+ default: true,
41
+ },
42
+ density: {
43
+ type: String as () => 'default' | 'comfortable' | 'compact',
44
+ default: 'compact',
45
+ },
46
+ backgroundColor: {
47
+ type: String,
48
+ default: 'white',
49
+ },
50
+ clearable: {
51
+ type: Boolean,
52
+ default: true,
53
+ },
54
+ })
55
+
56
+ const emit = defineEmits(['update:filters'])
57
+
58
+ function generateUniqueKey() {
59
+ return String(props.header.key || props.header.value || (props.header.title ? `filter_${props.header.title}` : `filter_${Date.now()}`))
60
+ }
61
+
62
+ const filterItems = computed(() => {
63
+ if (!props.header.filterOptions || !Array.isArray(props.header.filterOptions)) {
64
+ return []
65
+ }
66
+ return props.header.filterOptions
67
+ })
68
+
69
+ const modelValue = computed({
70
+ get: () => {
71
+ if (props.filterValue === null || props.filterValue === undefined) {
72
+ return props.header.multiple ? [] : null
73
+ }
74
+ return props.filterValue
75
+ },
76
+ set: (newValue) => {
77
+ const key = generateUniqueKey()
78
+ if (!key) return
79
+
80
+ if (props.header.multiple) {
81
+ if (!newValue || (Array.isArray(newValue) && newValue.length === 0)) {
82
+ const newFilters = props.filters.filter(f => f.key !== key)
83
+ emit('update:filters', newFilters)
84
+ return
85
+ }
86
+
87
+ const existingFilterIndex = props.filters.findIndex(f => f.key === key)
88
+ const newFilters = [...props.filters]
89
+
90
+ if (existingFilterIndex >= 0) {
91
+ newFilters[existingFilterIndex]!.value = newValue as string | number | Date | Array<string | number | Date> | Record<string, unknown> | null | undefined
92
+ }
93
+ else {
94
+ newFilters.push({
95
+ key,
96
+ value: newValue as string | number | Date | Array<string | number | Date> | Record<string, unknown> | null | undefined,
97
+ type: 'autocomplete',
98
+ })
99
+ }
100
+
101
+ emit('update:filters', newFilters)
102
+ return
103
+ }
104
+
105
+ if (newValue === undefined || newValue === null) {
106
+ const newFilters = props.filters.filter(f => f.key !== key)
107
+ emit('update:filters', newFilters)
108
+ return
109
+ }
110
+
111
+ const existingFilterIndex = props.filters.findIndex(f => f.key === key)
112
+ const newFilters = [...props.filters]
113
+
114
+ if (existingFilterIndex >= 0) {
115
+ newFilters[existingFilterIndex]!.value = newValue as string | number | Date | Array<string | number | Date> | Record<string, unknown> | null | undefined
116
+ }
117
+ else {
118
+ newFilters.push({
119
+ key,
120
+ value: newValue as string | number | Date | Array<string | number | Date> | Record<string, unknown> | null | undefined,
121
+ type: 'autocomplete',
122
+ })
123
+ }
124
+
125
+ emit('update:filters', newFilters)
126
+ },
127
+ })
128
+
129
+ function handleClear() {
130
+ const key = generateUniqueKey()
131
+ const newFilters = props.filters.filter(f => f.key !== key)
132
+ emit('update:filters', newFilters)
133
+ }
134
+ </script>
135
+
136
+ <template>
137
+ <SyAutocomplete
138
+ v-model="modelValue"
139
+ :label="props.header.title || ''"
140
+ :items="filterItems"
141
+ :clearable="clearable"
142
+ :density="inputConfig?.density ?? density"
143
+ :hide-details="inputConfig?.hideDetails ?? hideDetails"
144
+ :variant-style="inputConfig?.variant ?? variant"
145
+ :bg-color="inputConfig?.backgroundColor ?? backgroundColor"
146
+ :disable-error-handling="inputConfig?.disableErrorHandling ?? disableErrorHandling"
147
+ :multiple="props.header.multiple"
148
+ :chips="props.header.chips"
149
+ :filter="true"
150
+ class="filter-input"
151
+ :aria-label="props.header.title || 'Filtre'"
152
+ @click:clear="handleClear"
153
+ />
154
+ </template>
155
+
156
+ <style lang="scss" scoped>
157
+ .filter-input {
158
+ width: 100%;
159
+ }
160
+ </style>
@@ -203,7 +203,7 @@
203
203
  <div class="number-filter-container">
204
204
  <SyTextField
205
205
  v-model="modelValue"
206
- :label="header.title"
206
+ :label="header.title || ''"
207
207
  type="text"
208
208
  :clearable="inputConfig?.clearable ?? clearable"
209
209
  :density="inputConfig?.density ?? density"
@@ -62,15 +62,15 @@
62
62
  return String(props.header.key || props.header.value || (props.header.title ? `filter_${props.header.title}` : `filter_${Date.now()}`))
63
63
  }
64
64
 
65
- // Ajouter l'option "- choisir -" et gérer les valeurs vides
65
+ // Gérer les valeurs vides dans les options
66
66
  const filterOptions = computed(() => {
67
67
  if (!props.header.filterOptions || !Array.isArray(props.header.filterOptions)) {
68
- return [{ text: locales.defaultOption, value: locales.defaultOption }]
68
+ return []
69
69
  }
70
70
 
71
71
  // Définir le type des options pour accepter null et unknown
72
72
  type FilterOptionValue = { text: string, value: unknown | null }
73
- const options: FilterOptionValue[] = [{ text: locales.defaultOption, value: locales.defaultOption }]
73
+ const options: FilterOptionValue[] = []
74
74
 
75
75
  // Traiter les options existantes et remplacer les valeurs vides par "(vide)"
76
76
  props.header.filterOptions.forEach((option) => {
@@ -87,8 +87,8 @@
87
87
 
88
88
  const modelValue = computed({
89
89
  get: () => {
90
- if (props.filterValue === null) {
91
- return props.header.multiple ? [] : locales.defaultOption
90
+ if (props.filterValue === null || props.filterValue === undefined) {
91
+ return props.header.multiple ? [] : null
92
92
  }
93
93
  return props.filterValue
94
94
  },
@@ -125,9 +125,9 @@
125
125
  return
126
126
  }
127
127
 
128
- // Pour la sélection simple (comportement existant)
129
- if (newValue === undefined || newValue === null || newValue === locales.defaultOption) {
130
- // Effacer le filtre si la valeur est vide ou "-choisir-"
128
+ // Pour la sélection simple
129
+ if (newValue === undefined || newValue === null) {
130
+ // Effacer le filtre si la valeur est vide
131
131
  const newFilters = props.filters.filter(f => f.key !== key)
132
132
  emit('update:filters', newFilters)
133
133
  return
@@ -178,11 +178,10 @@
178
178
  if (import.meta.env?.MODE === 'test' || import.meta.env?.NODE_ENV === 'test') {
179
179
  return true
180
180
  }
181
- // En mode normal, cacher le bouton quand l'option par défaut est sélectionnée
182
181
  if (props.header.multiple) {
183
182
  return Array.isArray(modelValue.value) && modelValue.value.length > 0
184
183
  }
185
- return modelValue.value !== locales.defaultOption
184
+ return modelValue.value !== null
186
185
  })
187
186
  </script>
188
187
 
@@ -200,7 +199,7 @@
200
199
  :variant="inputConfig?.variant ?? variant"
201
200
  :bg-color="inputConfig?.backgroundColor ?? backgroundColor"
202
201
  :disable-error-handling="inputConfig?.disableErrorHandling ?? disableErrorHandling"
203
- :multiple="props.header.multiple"
202
+ :multiple="props.header.multiple === true"
204
203
  :chips="props.header.chips"
205
204
  class="filter-input"
206
205
  :aria-label="props.header.title || 'Filtre'"
@@ -161,7 +161,7 @@
161
161
  <div class="text-filter-container">
162
162
  <SyTextField
163
163
  v-model="modelValue"
164
- :label="header.title"
164
+ :label="header.title || ''"
165
165
  :clearable="inputConfig?.clearable ?? clearable"
166
166
  :density="inputConfig?.density ?? density"
167
167
  :hide-details="inputConfig?.hideDetails ?? hideDetails"
@@ -6,7 +6,10 @@ export default function getFilterComponent(filterType?: string, filterOptions?:
6
6
  // Déterminer le type de composant à charger
7
7
  let componentType = 'text'
8
8
 
9
- if (filterType === 'select' || filterOptions) {
9
+ if (filterType === 'autocomplete') {
10
+ componentType = 'autocomplete'
11
+ }
12
+ else if (filterType === 'select' || filterOptions) {
10
13
  componentType = 'select'
11
14
  }
12
15
  else if (filterType === 'date') {
@@ -27,6 +30,10 @@ export default function getFilterComponent(filterType?: string, filterOptions?:
27
30
  // Sinon, charger le composant de manière asynchrone
28
31
  let asyncComponent
29
32
  switch (componentType) {
33
+ case 'autocomplete':
34
+ asyncComponent = markRaw(defineAsyncComponent(() => import('./AutocompleteFilter.vue')))
35
+ Object.defineProperty(asyncComponent, 'name', { value: 'AutocompleteFilter' })
36
+ break
30
37
  case 'select':
31
38
  asyncComponent = markRaw(defineAsyncComponent(() => import('./SelectFilter.vue')))
32
39
  Object.defineProperty(asyncComponent, 'name', { value: 'SelectFilter' })
@@ -1,4 +1,3 @@
1
1
  export const locales = {
2
- defaultOption: '- choisir -',
3
2
  emptyValue: '(vide)',
4
3
  }
@@ -0,0 +1,110 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { describe, it, afterEach } from 'vitest'
4
+ import { mount } from '@vue/test-utils'
5
+ import { axe } from 'vitest-axe'
6
+ import { assertNoA11yViolations } from '@tests/unit/accessibility/axeUtils'
7
+
8
+ import AutocompleteFilter from '../AutocompleteFilter.vue'
9
+
10
+ // Stub accessible : un <input> avec un <label> associé représente
11
+ // le champ de saisie de l'autocomplete de façon évaluable par axe.
12
+ const accessibleSyAutocompleteStub = {
13
+ template: `
14
+ <div>
15
+ <label :for="inputId">{{ label }}</label>
16
+ <input
17
+ :id="inputId"
18
+ type="text"
19
+ role="combobox"
20
+ :aria-label="label"
21
+ :aria-expanded="false"
22
+ aria-autocomplete="list"
23
+ v-bind="$attrs"
24
+ />
25
+ </div>
26
+ `,
27
+ props: ['modelValue', 'label', 'items', 'clearable', 'density', 'hideDetails',
28
+ 'disableErrorHandling', 'variantStyle', 'bgColor', 'multiple', 'chips', 'filter'],
29
+ emits: ['update:modelValue', 'click:clear'],
30
+ setup() {
31
+ const inputId = `autocomplete-stub-${Math.random().toString(36).slice(2)}`
32
+ return { inputId }
33
+ },
34
+ }
35
+
36
+ const baseHeader = {
37
+ title: 'Statut',
38
+ key: 'status',
39
+ filterOptions: [
40
+ { text: 'Actif', value: 'Actif' },
41
+ { text: 'En congé', value: 'En congé' },
42
+ { text: 'Inactif', value: 'Inactif' },
43
+ ],
44
+ }
45
+
46
+ afterEach(() => {
47
+ document.body.innerHTML = ''
48
+ })
49
+
50
+ describe('AutocompleteFilter – accessibilité (axe)', () => {
51
+ it('has no axe violations in default (single) state', async () => {
52
+ const wrapper = mount(AutocompleteFilter, {
53
+ attachTo: document.body,
54
+ global: { stubs: { SyAutocomplete: accessibleSyAutocompleteStub } },
55
+ props: {
56
+ header: baseHeader,
57
+ filters: [],
58
+ filterValue: undefined,
59
+ },
60
+ })
61
+
62
+ const results = await axe(wrapper.element as HTMLElement)
63
+ assertNoA11yViolations(results, 'AutocompleteFilter – single, empty', { ignoreRules: ['region'] })
64
+ })
65
+
66
+ it('has no axe violations when a value is selected', async () => {
67
+ const wrapper = mount(AutocompleteFilter, {
68
+ attachTo: document.body,
69
+ global: { stubs: { SyAutocomplete: accessibleSyAutocompleteStub } },
70
+ props: {
71
+ header: baseHeader,
72
+ filters: [{ key: 'status', value: 'Actif', type: 'autocomplete' }],
73
+ filterValue: 'Actif',
74
+ },
75
+ })
76
+
77
+ const results = await axe(wrapper.element as HTMLElement)
78
+ assertNoA11yViolations(results, 'AutocompleteFilter – single, with value', { ignoreRules: ['region'] })
79
+ })
80
+
81
+ it('has no axe violations in multiple selection state', async () => {
82
+ const wrapper = mount(AutocompleteFilter, {
83
+ attachTo: document.body,
84
+ global: { stubs: { SyAutocomplete: accessibleSyAutocompleteStub } },
85
+ props: {
86
+ header: { ...baseHeader, multiple: true, chips: true },
87
+ filters: [],
88
+ filterValue: [],
89
+ },
90
+ })
91
+
92
+ const results = await axe(wrapper.element as HTMLElement)
93
+ assertNoA11yViolations(results, 'AutocompleteFilter – multiple, empty', { ignoreRules: ['region'] })
94
+ })
95
+
96
+ it('has no axe violations when header has no title (falls back to aria-label "Filtre")', async () => {
97
+ const wrapper = mount(AutocompleteFilter, {
98
+ attachTo: document.body,
99
+ global: { stubs: { SyAutocomplete: accessibleSyAutocompleteStub } },
100
+ props: {
101
+ header: { key: 'status', filterOptions: baseHeader.filterOptions },
102
+ filters: [],
103
+ filterValue: undefined,
104
+ },
105
+ })
106
+
107
+ const results = await axe(wrapper.element as HTMLElement)
108
+ assertNoA11yViolations(results, 'AutocompleteFilter – no title', { ignoreRules: ['region'] })
109
+ })
110
+ })
@@ -0,0 +1,203 @@
1
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+
4
+ import AutocompleteFilter from '../AutocompleteFilter.vue'
5
+ import SyAutocomplete from '@/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue'
6
+ import type { FilterType } from '../../types'
7
+
8
+ describe('AutocompleteFilter.vue', () => {
9
+ let wrapper: ReturnType<typeof mount<typeof AutocompleteFilter>>
10
+ const header = {
11
+ title: 'Test Autocomplete',
12
+ key: 'test',
13
+ filterOptions: [
14
+ { text: 'Option 1', value: 'option1' },
15
+ { text: 'Option 2', value: 'option2' },
16
+ ],
17
+ }
18
+ const filters: { key: string, value: string | number, type: FilterType }[] = []
19
+
20
+ beforeEach(() => {
21
+ wrapper = mount(AutocompleteFilter, {
22
+ global: {
23
+ stubs: {
24
+ SyAutocomplete: {
25
+ template: '<div class="sy-autocomplete-stub" data-testid="sy-autocomplete" :label="label" :clearable="clearable" :density="density" :hideDetails="hideDetails"></div>',
26
+ props: ['modelValue', 'label', 'items', 'clearable', 'density', 'hideDetails', 'disableErrorHandling', 'variantStyle', 'multiple', 'chips', 'filter'],
27
+ emits: ['update:modelValue', 'click:clear'],
28
+ },
29
+ },
30
+ },
31
+ props: {
32
+ header,
33
+ filters,
34
+ filterValue: undefined,
35
+ },
36
+ })
37
+ })
38
+
39
+ afterEach(() => {
40
+ vi.clearAllMocks()
41
+ document.body.innerHTML = ''
42
+ })
43
+
44
+ it('renders correctly with default props', () => {
45
+ expect(wrapper.exists()).toBe(true)
46
+ expect(wrapper.findComponent(SyAutocomplete).exists()).toBe(true)
47
+ })
48
+
49
+ it('passes the correct props to SyAutocomplete', () => {
50
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
51
+ expect(syAutocomplete.attributes('label')).toBe('Test Autocomplete')
52
+ expect(syAutocomplete.attributes('clearable')).toBe('true')
53
+ expect(syAutocomplete.attributes('density')).toBe('compact')
54
+ expect(syAutocomplete.attributes('hidedetails')).toBe('true')
55
+ })
56
+
57
+ it('emits update:filters event when value changes', async () => {
58
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
59
+ syAutocomplete.vm.$emit('update:modelValue', 'option1')
60
+
61
+ expect(wrapper.emitted('update:filters')).toBeTruthy()
62
+ expect(wrapper.emitted('update:filters')![0]?.[0]).toEqual([
63
+ { key: 'test', value: 'option1', type: 'autocomplete' as FilterType },
64
+ ])
65
+ })
66
+
67
+ it('emits update:filters event to remove filter when value is null', async () => {
68
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
69
+ syAutocomplete.vm.$emit('update:modelValue', 'option1')
70
+ syAutocomplete.vm.$emit('update:modelValue', null)
71
+
72
+ expect(wrapper.emitted('update:filters')![1]?.[0]).toEqual([])
73
+ })
74
+
75
+ it('emits update:filters event to remove filter when value is undefined', async () => {
76
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
77
+ await syAutocomplete.vm.$emit('update:modelValue', 'option1')
78
+ syAutocomplete.vm.$emit('update:modelValue', undefined)
79
+
80
+ expect(wrapper.emitted('update:filters')![1]?.[0]).toEqual([])
81
+ })
82
+
83
+ it('handles clear button click', async () => {
84
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
85
+ await syAutocomplete.vm.$emit('click:clear')
86
+
87
+ expect(wrapper.emitted('update:filters')).toBeTruthy()
88
+ expect(wrapper.emitted('update:filters')![0]?.[0]).toEqual([])
89
+ })
90
+
91
+ it('updates existing filter when one already exists', async () => {
92
+ const existingFilters = [{ key: 'test', value: 'option1', type: 'autocomplete' as FilterType }]
93
+ await wrapper.setProps({ filters: existingFilters })
94
+
95
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
96
+ syAutocomplete.vm.$emit('update:modelValue', 'option2')
97
+
98
+ expect(wrapper.emitted('update:filters')![0]?.[0]).toEqual([
99
+ { key: 'test', value: 'option2', type: 'autocomplete' as FilterType },
100
+ ])
101
+ })
102
+
103
+ it('handles multiple selection - emits array value', async () => {
104
+ await wrapper.setProps({
105
+ header: { ...header, multiple: true },
106
+ })
107
+
108
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
109
+ syAutocomplete.vm.$emit('update:modelValue', ['option1', 'option2'])
110
+
111
+ expect(wrapper.emitted('update:filters')).toBeTruthy()
112
+ expect(wrapper.emitted('update:filters')![0]?.[0]).toEqual([
113
+ { key: 'test', value: ['option1', 'option2'], type: 'autocomplete' as FilterType },
114
+ ])
115
+ })
116
+
117
+ it('removes filter when multiple selection is cleared to empty array', async () => {
118
+ await wrapper.setProps({
119
+ header: { ...header, multiple: true },
120
+ filters: [{ key: 'test', value: ['option1'], type: 'autocomplete' as FilterType }],
121
+ })
122
+
123
+ const syAutocomplete = wrapper.findComponent(SyAutocomplete)
124
+ syAutocomplete.vm.$emit('update:modelValue', [])
125
+
126
+ expect(wrapper.emitted('update:filters')![0]?.[0]).toEqual([])
127
+ })
128
+
129
+ it('generates unique key from title when header.key is absent', async () => {
130
+ const headerWithoutKey = {
131
+ title: 'Test Autocomplete',
132
+ filterOptions: [
133
+ { text: 'Option 1', value: 'option1' },
134
+ ],
135
+ }
136
+ const newWrapper = mount(AutocompleteFilter, {
137
+ global: {
138
+ stubs: {
139
+ SyAutocomplete: {
140
+ template: '<div class="sy-autocomplete-stub"></div>',
141
+ props: ['modelValue', 'label', 'items', 'clearable', 'density', 'hideDetails', 'disableErrorHandling', 'variantStyle', 'multiple', 'chips', 'filter'],
142
+ emits: ['update:modelValue', 'click:clear'],
143
+ },
144
+ },
145
+ },
146
+ props: {
147
+ header: headerWithoutKey,
148
+ filters: [],
149
+ filterValue: undefined,
150
+ },
151
+ })
152
+
153
+ const syAutocomplete = newWrapper.findComponent(SyAutocomplete)
154
+ await syAutocomplete.vm.$emit('update:modelValue', 'option1')
155
+
156
+ expect(newWrapper.emitted('update:filters')).toBeTruthy()
157
+ const emittedFilters = newWrapper.emitted('update:filters')![0]?.[0] as Array<{ key: string, value: string, type: string }>
158
+ expect(emittedFilters.length).toBe(1)
159
+ expect(emittedFilters[0]?.key).toBe('filter_Test Autocomplete')
160
+ expect(emittedFilters[0]?.value).toBe('option1')
161
+ expect(emittedFilters[0]?.type).toBe('autocomplete')
162
+ })
163
+
164
+ it('generates unique key with timestamp when all header properties are absent', async () => {
165
+ const originalDateNow = Date.now
166
+ const mockTimestamp = 1622548800000
167
+ global.Date.now = vi.fn(() => mockTimestamp)
168
+
169
+ const emptyHeader = {
170
+ filterOptions: [
171
+ { text: 'Option 1', value: 'option1' },
172
+ ],
173
+ }
174
+ const newWrapper = mount(AutocompleteFilter, {
175
+ global: {
176
+ stubs: {
177
+ SyAutocomplete: {
178
+ template: '<div class="sy-autocomplete-stub"></div>',
179
+ props: ['modelValue', 'label', 'items', 'clearable', 'density', 'hideDetails', 'disableErrorHandling', 'variantStyle', 'multiple', 'chips', 'filter'],
180
+ emits: ['update:modelValue', 'click:clear'],
181
+ },
182
+ },
183
+ },
184
+ props: {
185
+ header: emptyHeader,
186
+ filters: [],
187
+ filterValue: undefined,
188
+ },
189
+ })
190
+
191
+ const syAutocomplete = newWrapper.findComponent(SyAutocomplete)
192
+ await syAutocomplete.vm.$emit('update:modelValue', 'option1')
193
+
194
+ expect(newWrapper.emitted('update:filters')).toBeTruthy()
195
+ const emittedFilters = newWrapper.emitted('update:filters')![0]?.[0] as Array<{ key: string, value: string, type: string }>
196
+ expect(emittedFilters.length).toBe(1)
197
+ expect(emittedFilters[0]?.key).toBe(`filter_${mockTimestamp}`)
198
+ expect(emittedFilters[0]?.value).toBe('option1')
199
+ expect(emittedFilters[0]?.type).toBe('autocomplete')
200
+
201
+ global.Date.now = originalDateNow
202
+ })
203
+ })
@@ -0,0 +1,104 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { describe, it, afterEach } from 'vitest'
4
+ import { mount } from '@vue/test-utils'
5
+ import { axe } from 'vitest-axe'
6
+ import { assertNoA11yViolations } from '@tests/unit/accessibility/axeUtils'
7
+
8
+ import SelectFilter from '../SelectFilter.vue'
9
+
10
+ // Stub accessible : un <select> avec un <label> associé permet à axe
11
+ // de valider label / form-field sans dépendre de l'implémentation SySelect.
12
+ const accessibleSySelectStub = {
13
+ template: `
14
+ <div>
15
+ <label :for="inputId">{{ label }}</label>
16
+ <select :id="inputId" :aria-label="label" v-bind="$attrs">
17
+ <option v-for="item in items" :key="item.value" :value="item.value">{{ item.text }}</option>
18
+ </select>
19
+ </div>
20
+ `,
21
+ props: ['modelValue', 'label', 'items', 'clearable', 'density', 'hideDetails', 'hideMessages',
22
+ 'disableErrorHandling', 'variant', 'bgColor', 'multiple', 'chips'],
23
+ emits: ['update:modelValue', 'click:clear'],
24
+ setup() {
25
+ const inputId = `select-stub-${Math.random().toString(36).slice(2)}`
26
+ return { inputId }
27
+ },
28
+ }
29
+
30
+ const baseHeader = {
31
+ title: 'Département',
32
+ key: 'department',
33
+ filterOptions: [
34
+ { text: 'RH', value: 'RH' },
35
+ { text: 'IT', value: 'IT' },
36
+ { text: 'Finance', value: 'Finance' },
37
+ ],
38
+ }
39
+
40
+ afterEach(() => {
41
+ document.body.innerHTML = ''
42
+ })
43
+
44
+ describe('SelectFilter – accessibilité (axe)', () => {
45
+ it('has no axe violations in default (single) state', async () => {
46
+ const wrapper = mount(SelectFilter, {
47
+ attachTo: document.body,
48
+ global: { stubs: { SySelect: accessibleSySelectStub } },
49
+ props: {
50
+ header: baseHeader,
51
+ filters: [],
52
+ filterValue: undefined,
53
+ },
54
+ })
55
+
56
+ const results = await axe(wrapper.element as HTMLElement)
57
+ assertNoA11yViolations(results, 'SelectFilter – single, empty', { ignoreRules: ['region'] })
58
+ })
59
+
60
+ it('has no axe violations when a value is selected', async () => {
61
+ const wrapper = mount(SelectFilter, {
62
+ attachTo: document.body,
63
+ global: { stubs: { SySelect: accessibleSySelectStub } },
64
+ props: {
65
+ header: baseHeader,
66
+ filters: [{ key: 'department', value: 'RH', type: 'select' }],
67
+ filterValue: 'RH',
68
+ },
69
+ })
70
+
71
+ const results = await axe(wrapper.element as HTMLElement)
72
+ assertNoA11yViolations(results, 'SelectFilter – single, with value', { ignoreRules: ['region'] })
73
+ })
74
+
75
+ it('has no axe violations in multiple selection state', async () => {
76
+ const wrapper = mount(SelectFilter, {
77
+ attachTo: document.body,
78
+ global: { stubs: { SySelect: accessibleSySelectStub } },
79
+ props: {
80
+ header: { ...baseHeader, multiple: true, chips: true },
81
+ filters: [],
82
+ filterValue: [],
83
+ },
84
+ })
85
+
86
+ const results = await axe(wrapper.element as HTMLElement)
87
+ assertNoA11yViolations(results, 'SelectFilter – multiple, empty', { ignoreRules: ['region'] })
88
+ })
89
+
90
+ it('has no axe violations when header has no title (falls back to aria-label "Filtre")', async () => {
91
+ const wrapper = mount(SelectFilter, {
92
+ attachTo: document.body,
93
+ global: { stubs: { SySelect: accessibleSySelectStub } },
94
+ props: {
95
+ header: { key: 'status', filterOptions: baseHeader.filterOptions },
96
+ filters: [],
97
+ filterValue: undefined,
98
+ },
99
+ })
100
+
101
+ const results = await axe(wrapper.element as HTMLElement)
102
+ assertNoA11yViolations(results, 'SelectFilter – no title', { ignoreRules: ['region'] })
103
+ })
104
+ })