@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
@@ -1,175 +1,85 @@
1
1
  <script setup lang="ts">
2
- import { computed, nextTick, onMounted, ref, watch, type PropType } from 'vue'
2
+ import { computed, nextTick, onMounted, ref, useSlots, watch } from 'vue'
3
3
  import { mdiChevronDown, mdiCloseCircle } from '@mdi/js'
4
4
  import SyTextField from '@/components/Customs/SyTextField/SyTextField.vue'
5
5
  import SyIcon from '@/components/Customs/SyIcon/SyIcon.vue'
6
6
  import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue'
7
7
  import { ariaManager } from './utils/ariaManager'
8
- import { useFormFieldErrorHandling } from '@/composables/useFormFieldErrorHandling'
9
- import { type ValidationRule } from '@/composables/validation/useValidation'
8
+ import { validationPropsDefaults, type FieldValidationProps } from '@/composables/unifyValidation/useValidation'
10
9
  import type { ItemType, SelectValue, SelectArray } from './types'
11
10
  import { useItemUtils } from './utils/useItemUtils'
12
11
  import { useSelectionLogic } from './utils/useSelectionLogic'
13
12
  import { useSyAutocompleteKeyboard } from './utils/useKeyboardHandler'
13
+ import { useSyAutocompleteValidation } from './composables/useSyAutocompleteValidation'
14
14
  import { locales } from './locales'
15
15
 
16
- const props = defineProps({
17
- bgColor: {
18
- type: String,
19
- default: 'white',
20
- },
21
- chips: {
22
- type: Boolean,
23
- default: false,
24
- },
25
- clearable: {
26
- type: Boolean,
27
- default: false,
28
- },
29
- customRules: {
30
- type: Array as PropType<ValidationRule[]>,
31
- default: () => [],
32
- },
33
- customSuccessRules: {
34
- type: Array as PropType<ValidationRule[]>,
35
- default: () => [],
36
- },
37
- customWarningRules: {
38
- type: Array as PropType<ValidationRule[]>,
39
- default: () => [],
40
- },
41
- debounce: {
42
- type: Number,
43
- default: 200,
44
- },
45
- density: {
46
- type: String as PropType<'default' | 'comfortable' | 'compact' | undefined>,
47
- default: 'default',
48
- },
49
- disableErrorHandling: {
50
- type: Boolean,
51
- default: false,
52
- },
53
- displayAsterisk: {
54
- type: Boolean,
55
- default: false,
56
- },
57
- errorMessages: {
58
- type: Array as PropType<string[] | null>,
59
- default: null,
60
- },
61
- filter: {
62
- type: Boolean,
63
- default: true,
64
- },
65
- hasError: {
66
- type: Boolean,
67
- default: false,
68
- },
69
- hasSuccess: {
70
- type: Boolean,
71
- default: false,
72
- },
73
- hasWarning: {
74
- type: Boolean,
75
- default: false,
76
- },
77
- hideDetails: {
78
- type: Boolean,
79
- default: false,
80
- },
81
- hideNoData: {
82
- type: Boolean,
83
- default: false,
84
- },
85
- isValidateOnBlur: {
86
- type: Boolean,
87
- default: false,
88
- },
89
- items: {
90
- type: Array as PropType<ItemType[]>,
91
- default: () => [],
92
- },
93
- label: {
94
- type: String,
95
- default: 'Rechercher',
96
- },
97
- loading: {
98
- type: Boolean,
99
- default: false,
100
- },
101
- menuId: {
102
- type: String,
103
- default: 'sy-autocomplete-menu',
104
- },
105
- modelValue: {
106
- type: [Object, String, Number, Array, null] as PropType<SelectValue | SelectArray>,
107
- default: null,
108
- },
109
- multiple: {
110
- type: Boolean,
111
- default: false,
112
- },
113
- noDataText: {
114
- type: String,
115
- default: locales.noData,
116
- },
117
- placeholder: {
118
- type: String,
119
- default: '',
120
- },
121
- plainTextKey: {
122
- type: String,
123
- default: '',
124
- },
125
- disabled: {
126
- type: Boolean,
127
- default: false,
128
- },
129
- readonly: {
130
- type: Boolean,
131
- default: false,
132
- },
133
- required: {
134
- type: Boolean,
135
- default: false,
136
- },
137
- returnObject: {
138
- type: Boolean,
139
- default: false,
140
- },
141
- showSuccessMessages: {
142
- type: Boolean,
143
- default: true,
144
- },
145
- successMessages: {
146
- type: Array as PropType<string[] | null>,
147
- default: null,
148
- },
149
- selectionText: {
150
- type: Function as PropType<(selected: SelectArray) => string>,
151
- default: undefined,
152
- },
153
- textKey: {
154
- type: String,
155
- default: 'text',
156
- },
157
- valueKey: {
158
- type: String,
159
- default: 'value',
160
- },
161
- warningMessages: {
162
- type: Array as PropType<string[] | null>,
163
- default: null,
164
- },
165
- })
16
+ interface SyAutocompleteProps {
17
+ bgColor?: string
18
+ chips?: boolean
19
+ clearable?: boolean
20
+ debounce?: number
21
+ density?: 'default' | 'comfortable' | 'compact' | undefined
22
+ displayAsterisk?: boolean
23
+ filter?: boolean
24
+ hideDetails?: boolean
25
+ hideNoData?: boolean
26
+ items?: ItemType[]
27
+ label?: string
28
+ loading?: boolean
29
+ menuId?: string
30
+ modelValue?: SelectValue | SelectArray
31
+ multiple?: boolean
32
+ noDataText?: string
33
+ placeholder?: string
34
+ plainTextKey?: string
35
+ helpText?: string
36
+ returnObject?: boolean
37
+ selectionText?: (selected: SelectArray) => string
38
+ textKey?: string
39
+ valueKey?: string
40
+ }
41
+
42
+ const props = withDefaults(
43
+ defineProps<SyAutocompleteProps & FieldValidationProps>(),
44
+ {
45
+ bgColor: 'white',
46
+ chips: false,
47
+ clearable: false,
48
+ debounce: 200,
49
+ density: 'default',
50
+ displayAsterisk: false,
51
+ filter: true,
52
+ hideDetails: false,
53
+ hideNoData: false,
54
+ items: () => [],
55
+ label: 'Rechercher',
56
+ loading: false,
57
+ menuId: 'sy-autocomplete-menu',
58
+ modelValue: null,
59
+ multiple: false,
60
+ noDataText: locales.noData,
61
+ helpText: '',
62
+ selectionText: undefined,
63
+ placeholder: '',
64
+ plainTextKey: '',
65
+ returnObject: false,
66
+ textKey: 'text',
67
+ valueKey: 'value',
68
+ ...validationPropsDefaults,
69
+ // Diverge du défaut global (true) : modelValue ne change que lors d'une sélection (pas à chaque frappe),
70
+ // donc valider sur ce changement donne un retour immédiat après sélection sans erreurs prématurées pendant la saisie.
71
+ isValidateOnBlur: false,
72
+ },
73
+ )
166
74
 
167
75
  const emit = defineEmits(['update:modelValue', 'search'])
168
76
 
77
+ const slots = useSlots()
78
+ const hasPrependItem = computed(() => !!slots['prepend-item'])
79
+
169
80
  const isOpen = ref(false)
170
81
  const search = ref('')
171
82
  const selected = ref<SelectValue | SelectArray>(props.modelValue as SelectValue | SelectArray)
172
- const hasInteracted = ref(false)
173
83
  const suppressNextInput = ref(false)
174
84
  const suppressMenuOpen = ref(false)
175
85
  type SyTextFieldInstance = InstanceType<typeof SyTextField> & { $refs?: { input?: HTMLInputElement } }
@@ -179,7 +89,21 @@
179
89
  const optionIdPrefixed = computed(() => `${uniqueMenuId.value}-option`)
180
90
  const activeDescendantId = ref('')
181
91
 
182
- const errorHandling = useFormFieldErrorHandling(props, selected)
92
+ const {
93
+ focused,
94
+ hasInteracted,
95
+ markInteracted,
96
+ clearValidation,
97
+ validateOnSubmit,
98
+ validateOnBlur,
99
+ displayErrors,
100
+ displayWarnings,
101
+ displaySuccesses,
102
+ displayHasError,
103
+ displayHasWarning,
104
+ displayHasSuccess,
105
+ validationIcon,
106
+ } = useSyAutocompleteValidation(props)
183
107
 
184
108
  const formattedItems = computed(() => props.items.map((item) => {
185
109
  if (typeof item === 'string') {
@@ -222,12 +146,11 @@
222
146
  })
223
147
  })
224
148
 
225
- const markInteracted = () => {
226
- hasInteracted.value = true
227
- }
228
-
229
149
  const selectItem = (item: ItemType | string | number | null | undefined) => {
230
150
  markInteracted()
151
+ if (item === null || item === undefined) {
152
+ clearValidation()
153
+ }
231
154
  updateValue(item ?? null)
232
155
  if (props.multiple) {
233
156
  suppressNextInput.value = true
@@ -257,13 +180,12 @@
257
180
 
258
181
  focusInput(textFieldRef)
259
182
 
260
- if (!props.filter) return
261
-
262
183
  if (debounceHandle) {
263
184
  clearTimeout(debounceHandle)
264
185
  }
265
186
 
266
187
  debounceHandle = setTimeout(() => {
188
+ emit('search', search.value)
267
189
  }, props.debounce)
268
190
  })
269
191
 
@@ -315,7 +237,7 @@
315
237
  : index
316
238
  }
317
239
 
318
- const { focusInput, keyboardActiveId, handleTabKey } = useSyAutocompleteKeyboard({
240
+ const { focusInput, focusPrepend, keyboardActiveId, handleTabKey } = useSyAutocompleteKeyboard({
319
241
  multiple: props.multiple,
320
242
  chips: props.chips,
321
243
  }, {
@@ -327,6 +249,7 @@
327
249
  filteredItems,
328
250
  uniqueMenuId,
329
251
  focusListItem: false,
252
+ hasPrependItem,
330
253
  })
331
254
 
332
255
  watch(keyboardActiveId, (val) => {
@@ -343,41 +266,6 @@
343
266
  return (textFieldRef.value?.$el as HTMLElement | undefined)?.querySelector('.v-field') ?? undefined
344
267
  })
345
268
 
346
- const shouldDisableErrorHandling = computed(() => props.disableErrorHandling)
347
-
348
- const externalErrors = computed(() => props.errorMessages || [])
349
- const displayErrors = computed(() => {
350
- if (shouldDisableErrorHandling.value) return []
351
- return externalErrors.value.length > 0
352
- ? externalErrors.value
353
- : (hasInteracted.value ? errorHandling.errors.value : [])
354
- })
355
- const displayWarnings = computed(() => {
356
- if (shouldDisableErrorHandling.value) return []
357
- return hasInteracted.value ? errorHandling.warnings.value : []
358
- })
359
- const displaySuccesses = computed(() => {
360
- if (shouldDisableErrorHandling.value) return []
361
- return hasInteracted.value ? errorHandling.successes.value : []
362
- })
363
- const displayHasError = computed(() => {
364
- if (shouldDisableErrorHandling.value) return false
365
- return externalErrors.value.length > 0 || (hasInteracted.value && errorHandling.hasError.value)
366
- })
367
- const displayHasWarning = computed(() => {
368
- if (shouldDisableErrorHandling.value) return false
369
- return hasInteracted.value && errorHandling.hasWarning.value
370
- })
371
- const displayHasSuccess = computed(() => {
372
- if (shouldDisableErrorHandling.value) return false
373
- return hasInteracted.value && errorHandling.hasSuccess.value
374
- })
375
-
376
- const validateOnSubmit = () => {
377
- markInteracted()
378
- return errorHandling.validateOnSubmit()
379
- }
380
-
381
269
  const checkErrorOnBlur = (event?: FocusEvent) => {
382
270
  const relatedTarget = event?.relatedTarget as HTMLElement | null | undefined
383
271
  if (relatedTarget?.closest('.sy-autocomplete__chip') || relatedTarget?.closest('.sy-autocomplete__clear-button')) {
@@ -387,8 +275,7 @@
387
275
  })
388
276
  return
389
277
  }
390
- markInteracted()
391
- return errorHandling.checkErrorOnBlur()
278
+ validateOnBlur()
392
279
  }
393
280
 
394
281
  const getInputValue = (value: string | Event): string | null => {
@@ -418,13 +305,13 @@
418
305
  updateValue(null)
419
306
  }
420
307
 
421
- emit('search', inputValue)
422
308
  openAndFocus()
423
309
  }
424
310
 
425
311
  const openAndFocus = () => {
426
312
  if (props.disabled || props.readonly) return
427
313
  markInteracted()
314
+ focused.value = true
428
315
  isOpen.value = true
429
316
  focusInput(textFieldRef)
430
317
  }
@@ -442,12 +329,12 @@
442
329
 
443
330
  onMounted(() => {
444
331
  syncSearchFromValue()
445
- ariaManager.setupAriaAttributesForAutocomplete(textFieldRef, isOpen, uniqueMenuId.value, activeDescendantId, props.loading, props.label)
332
+ ariaManager.setupAriaAttributesForAutocomplete(textFieldRef, isOpen, uniqueMenuId.value, activeDescendantId, props.loading, props.label, props.required, displayHasError.value)
446
333
  focusInput(textFieldRef, true)
447
334
  })
448
335
 
449
- watch([isOpen, activeDescendantId, () => props.loading], () => {
450
- ariaManager.setupAriaAttributesForAutocomplete(textFieldRef, isOpen, uniqueMenuId.value, activeDescendantId, props.loading, props.label)
336
+ watch([isOpen, activeDescendantId, () => props.loading, displayHasError, () => props.required], () => {
337
+ ariaManager.setupAriaAttributesForAutocomplete(textFieldRef, isOpen, uniqueMenuId.value, activeDescendantId, props.loading, props.label, props.required, displayHasError.value)
451
338
  }, { flush: 'post' })
452
339
 
453
340
  watch(isOpen, (open) => {
@@ -456,9 +343,17 @@
456
343
  }
457
344
  })
458
345
 
346
+ // flush: 'post' + rAF: Vuetify uses requestAnimationFrame (requestNewFrame) for overlay rendering,
347
+ // so nextTick/setTimeout(0) fire before the listbox is in the DOM.
348
+ watch(isOpen, (open) => {
349
+ if (open && hasPrependItem.value) {
350
+ requestAnimationFrame(() => focusPrepend())
351
+ }
352
+ }, { flush: 'post' })
353
+
459
354
  defineExpose({
460
- validation: errorHandling.validation,
461
355
  validateOnSubmit,
356
+ clearValidation,
462
357
  checkErrorOnBlur,
463
358
  isOpen,
464
359
  selectItem,
@@ -508,6 +403,7 @@
508
403
  :display-asterisk="required && displayAsterisk"
509
404
  :disable-error-handling="disableErrorHandling"
510
405
  :loading="loading"
406
+ :help-text="helpText"
511
407
  :are-details-hidden="hideDetails"
512
408
  :aria-label="hasInlineSelections ? label : undefined"
513
409
  @click="openAndFocus"
@@ -516,10 +412,19 @@
516
412
  @keydown.tab="handleTabKey"
517
413
  >
518
414
  <template #append-inner>
415
+ <SyIcon
416
+ v-if="validationIcon"
417
+ class="mr-6"
418
+ :color="displayHasError ? 'error' : (displayHasWarning ? 'warning' : 'success')"
419
+ :icon="validationIcon"
420
+ role="presentation"
421
+ :decorative="true"
422
+ />
519
423
  <button
520
424
  v-if="clearable && hasSelectionToClear"
521
425
  type="button"
522
426
  class="sy-autocomplete__clear-button"
427
+ :class="{ 'sy-autocomplete__clear-button--with-icon': validationIcon }"
523
428
  :aria-label="locales.clearSelection"
524
429
  @click.stop.prevent="selectItem(null)"
525
430
  >
@@ -581,6 +486,7 @@
581
486
  tabindex="-1"
582
487
  @click.stop
583
488
  >
489
+ <slot name="prepend-item" />
584
490
  <template v-if="filteredItems.length === 0 && !hideNoData && !loading">
585
491
  <VListItem
586
492
  :title="noDataText"
@@ -603,16 +509,18 @@
603
509
  v-if="multiple"
604
510
  #prepend
605
511
  >
606
- <SyCheckbox
607
- :model-value="isItemSelected(item)"
608
- density="compact"
609
- hide-details
610
- color="primary"
611
- class="mt-0 pt-0 mr-1"
612
- :title="getItemText(item) as string"
613
- :aria-label="getItemText(item) as string"
614
- @mousedown.stop.prevent="() => selectItem(item)"
615
- />
512
+ <div
513
+ aria-hidden="true"
514
+ inert
515
+ >
516
+ <SyCheckbox
517
+ :model-value="isItemSelected(item)"
518
+ density="compact"
519
+ hide-details
520
+ color="primary"
521
+ class="mt-0 pt-0 mr-1"
522
+ />
523
+ </div>
616
524
  </template>
617
525
  <VListItemTitle>
618
526
  {{ getItemText(item) }}
@@ -649,7 +557,13 @@
649
557
  border: 0;
650
558
  }
651
559
 
560
+ .v-icon.arrow {
561
+ position: absolute;
562
+ right: 10px;
563
+ }
564
+
652
565
  .sy-autocomplete__clear-button {
566
+ position: absolute;
653
567
  background: transparent;
654
568
  border: none;
655
569
  padding: 0;
@@ -657,10 +571,22 @@
657
571
  display: flex;
658
572
  align-items: center;
659
573
  justify-content: center;
574
+ top: 50%;
575
+ transform: translateY(-50%);
576
+ right: 42px;
577
+
578
+ &--with-icon {
579
+ right: 62px;
580
+ }
581
+
582
+ .v-icon {
583
+ position: static;
584
+ }
660
585
  }
661
586
 
662
587
  .sy-autocomplete__clear-icon {
663
- color: rgb(var(--v-theme-iconBase));
588
+ color: rgb(var(--v-theme-primary)) !important;
589
+ opacity: var(--v-medium-emphasis-opacity) !important;
664
590
  }
665
591
 
666
592
  .sy-autocomplete__chip {
@@ -724,12 +650,50 @@ li:hover {
724
650
  }
725
651
 
726
652
  /* Ensure focus styles match selection styles for keyboard navigation (align with SySelect) */
653
+
654
+ /* :deep() is required for keyboard-focused so the style applies to slot content (prepend-item),
655
+ which carries the parent's scoped attribute, not SyAutocomplete's. */
727
656
  .v-list-item:focus-visible,
728
- .v-list-item.keyboard-focused,
729
- li:focus-visible,
730
- li.keyboard-focused {
657
+ li:focus-visible {
731
658
  outline: 2px solid rgb(var(--v-theme-borderAccentPrimary));
732
659
  outline-offset: -2px;
733
660
  background-color: rgb(0 0 0 / 8%);
734
661
  }
662
+
663
+ :deep(.v-list-item.keyboard-focused),
664
+ :deep(li.keyboard-focused) {
665
+ outline: 2px solid rgb(var(--v-theme-borderAccentPrimary));
666
+ outline-offset: -2px;
667
+ background-color: rgb(0 0 0 / 8%);
668
+ }
669
+
670
+ :deep(.error-field .v-icon.arrow),
671
+ :deep(.error-field .v-icon.arrow .v-icon__svg) {
672
+ color: rgb(var(--v-theme-iconSubdued)) !important;
673
+ fill: rgb(var(--v-theme-iconSubdued)) !important;
674
+ }
675
+
676
+ :deep(.error-field .sy-autocomplete__clear-icon .v-icon__svg) {
677
+ fill: rgb(var(--v-theme-iconBase)) !important;
678
+ }
679
+
680
+ :deep(.warning-field .v-icon.arrow),
681
+ :deep(.warning-field .v-icon.arrow .v-icon__svg) {
682
+ color: rgb(var(--v-theme-iconBase)) !important;
683
+ fill: rgb(var(--v-theme-iconBase)) !important;
684
+ }
685
+
686
+ :deep(.warning-field .sy-autocomplete__clear-icon .v-icon__svg) {
687
+ fill: rgb(var(--v-theme-iconBase)) !important;
688
+ }
689
+
690
+ :deep(.success-field .v-icon.arrow),
691
+ :deep(.success-field .v-icon.arrow .v-icon__svg) {
692
+ color: rgb(var(--v-theme-iconBase)) !important;
693
+ fill: rgb(var(--v-theme-iconBase)) !important;
694
+ }
695
+
696
+ :deep(.success-field .sy-autocomplete__clear-icon .v-icon__svg) {
697
+ fill: rgb(var(--v-theme-iconBase)) !important;
698
+ }
735
699
  </style>
@@ -0,0 +1,101 @@
1
+ import { computed, ref, toRef, watch } from 'vue'
2
+ import type { Ref } from 'vue'
3
+ import type { ValidationRule as VuetifyValidationRule } from 'vuetify'
4
+ import { mdiAlertCircle, mdiAlertOutline, mdiCheck } from '@mdi/js'
5
+ import { type ValidationRule } from '@/composables/validation/useValidation'
6
+ import { useValidation, type FieldValidationProps } from '@/composables/unifyValidation/useValidation'
7
+ import { useValidatable } from '@/composables/validation/useValidatable'
8
+
9
+ export function useSyAutocompleteValidation(props: FieldValidationProps) {
10
+ const hasInteracted = ref(false)
11
+ const focused = ref(false)
12
+
13
+ const defaultRules = computed<ValidationRule[]>(() =>
14
+ props.required
15
+ ? [{
16
+ type: 'required',
17
+ options: {
18
+ message: `Le champ ${props.label || 'ce champ'} est requis.`,
19
+ fieldIdentifier: props.label,
20
+ },
21
+ }]
22
+ : [],
23
+ )
24
+
25
+ const { validate, clearValidation, errors, warnings, successes, hasError, hasWarning, hasSuccess } = useValidation({
26
+ modelValue: toRef(props, 'modelValue') as Ref<unknown>,
27
+ readonly: toRef(props, 'readonly') as Ref<boolean>,
28
+ disabled: toRef(props, 'disabled') as Ref<boolean>,
29
+ required: toRef(props, 'required') as Ref<boolean>,
30
+ isValidateOnBlur: toRef(props, 'isValidateOnBlur') as Ref<boolean>,
31
+ showSuccessMessages: toRef(props, 'showSuccessMessages') as Ref<boolean>,
32
+ disableErrorHandling: toRef(props, 'disableErrorHandling') as Ref<boolean>,
33
+ useVuetifyValidation: toRef(props, 'useVuetifyValidation') as Ref<boolean>,
34
+ label: toRef(props, 'label') as Ref<string | undefined>,
35
+ rules: toRef(props, 'rules') as Ref<VuetifyValidationRule[] | undefined>,
36
+ customRules: computed(() => [...defaultRules.value, ...(props.customRules ?? [])]),
37
+ customWarningRules: toRef(props, 'customWarningRules') as Ref<ValidationRule[]>,
38
+ customSuccessRules: toRef(props, 'customSuccessRules') as Ref<ValidationRule[]>,
39
+ errorMessages: toRef(props, 'errorMessages') as Ref<string[] | null | undefined>,
40
+ warningMessages: toRef(props, 'warningMessages') as Ref<string[] | null | undefined>,
41
+ successMessages: toRef(props, 'successMessages') as Ref<string[] | null | undefined>,
42
+ hasErrorProp: toRef(props, 'hasError') as Ref<boolean>,
43
+ hasWarningProp: toRef(props, 'hasWarning') as Ref<boolean>,
44
+ hasSuccessProp: toRef(props, 'hasSuccess') as Ref<boolean>,
45
+ maxErrors: toRef(props, 'maxErrors') as Ref<number>,
46
+ focused,
47
+ })
48
+
49
+ watch([errors, warnings, successes], ([e, w, s]) => {
50
+ if (e.length > 0 || w.length > 0 || s.length > 0) hasInteracted.value = true
51
+ })
52
+
53
+ const markInteracted = () => {
54
+ hasInteracted.value = true
55
+ }
56
+
57
+ const displayErrors = computed(() => hasInteracted.value ? errors.value : [])
58
+ const displayWarnings = computed(() => hasInteracted.value ? warnings.value : [])
59
+ const displaySuccesses = computed(() => hasInteracted.value ? successes.value : [])
60
+ const displayHasError = computed(() => hasInteracted.value && hasError.value)
61
+ const displayHasWarning = computed(() => hasInteracted.value && hasWarning.value)
62
+ const displayHasSuccess = computed(() => hasInteracted.value && hasSuccess.value)
63
+
64
+ const validationIcon = computed(() => {
65
+ if (props.useVuetifyValidation) return null
66
+ if (displayHasError.value) return mdiAlertCircle
67
+ if (displayHasWarning.value) return mdiAlertOutline
68
+ if (displayHasSuccess.value) return mdiCheck
69
+ return null
70
+ })
71
+
72
+ const validateOnSubmit = async () => {
73
+ markInteracted()
74
+ return await validate()
75
+ }
76
+
77
+ const validateOnBlur = () => {
78
+ markInteracted()
79
+ focused.value = false
80
+ validate()
81
+ }
82
+
83
+ useValidatable(validateOnSubmit, clearValidation)
84
+
85
+ return {
86
+ focused,
87
+ hasInteracted,
88
+ markInteracted,
89
+ validate,
90
+ clearValidation,
91
+ validateOnSubmit,
92
+ validateOnBlur,
93
+ displayErrors,
94
+ displayWarnings,
95
+ displaySuccesses,
96
+ displayHasError,
97
+ displayHasWarning,
98
+ displayHasSuccess,
99
+ validationIcon,
100
+ }
101
+ }