@cnamts/synapse 1.0.25 → 1.0.26

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 (211) hide show
  1. package/dist/{AutocompleteFilter-D7qBuCAP.js → AutocompleteFilter-BPR-a55G.js} +1 -1
  2. package/dist/{DateFilter-BitMWrMU.js → DateFilter-CknrJWs2.js} +2 -2
  3. package/dist/{NumberFilter-BTLUxw0a.js → NumberFilter-DJ-yNlzv.js} +1 -1
  4. package/dist/{PeriodFilter-B5rUIPAC.js → PeriodFilter-CiB5Oa9Z.js} +1 -1
  5. package/dist/{SelectFilter-l4QnRcuk.js → SelectFilter-EiafX97M.js} +1 -1
  6. package/dist/{TextFilter-C9hj6Qrp.js → TextFilter-BzOmpdxj.js} +1 -1
  7. package/dist/{apLightTheme-DnIM24Lv.js → apLightTheme-DS0Uy44H.js} +20 -16
  8. package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +4 -2
  9. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +60 -289
  10. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +1 -0
  11. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +1 -0
  12. package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +1 -0
  13. package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -4
  14. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +50 -49
  15. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +29 -28
  16. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +8 -8
  17. package/dist/components/DatePicker/composables/useDatePickerState.d.ts +3 -3
  18. package/dist/components/DatePicker/composables/useDateTextField.d.ts +2 -2
  19. package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +2 -2
  20. package/dist/components/DatePicker/types.d.ts +1 -2
  21. package/dist/components/LunarCalendar/useLunarCalendarValidation.d.ts +1 -0
  22. package/dist/components/MonthPicker/MonthPicker.d.ts +1 -1
  23. package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +1 -1
  24. package/dist/components/NirField/NirField.d.ts +8 -4
  25. package/dist/components/NirField/useNirValidation.d.ts +6 -2
  26. package/dist/components/PeriodField/PeriodField.d.ts +102 -102
  27. package/dist/components/PhoneField/PhoneField.d.ts +11 -1
  28. package/dist/components/RangeField/RangeSlider/RangeSlider.d.ts +0 -3
  29. package/dist/components/RatingPicker/EmotionPicker/EmotionPicker.d.ts +3 -1
  30. package/dist/components/RatingPicker/NumberPicker/NumberPicker.d.ts +4 -3
  31. package/dist/components/RatingPicker/RatingPicker.d.ts +18 -5
  32. package/dist/components/RatingPicker/StarsPicker/StarsPicker.d.ts +3 -1
  33. package/dist/components/RatingPicker/tests/RatingPicker.a11y.spect.d.ts +1 -0
  34. package/dist/components/RatingPicker/useRatingFocus.d.ts +18 -0
  35. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +4 -4
  36. package/dist/components/Tables/SyTable/SyTable.d.ts +4 -4
  37. package/dist/components/Tables/common/SyTablePagination.d.ts +152 -364
  38. package/dist/components/Tables/common/TableHeader.d.ts +1 -1
  39. package/dist/components/Tables/common/filters/DateFilter.d.ts +4 -4
  40. package/dist/composables/date/useDateInitializationDayjs.d.ts +3 -1
  41. package/dist/composables/unifyValidation/useCustomValidation.d.ts +3 -1
  42. package/dist/composables/unifyValidation/useValidation.d.ts +12 -6
  43. package/dist/composables/unifyValidation/useVuetifyValidation.d.ts +1 -1
  44. package/dist/composables/validation/useValidation.d.ts +1 -0
  45. package/dist/design-system-v3.js +2 -2
  46. package/dist/designTokens/tokens/amelipro/apLightTheme.d.ts +2 -0
  47. package/dist/designTokens/tokens/cnam/cnamLightTheme.d.ts +2 -0
  48. package/dist/{main-Cpx8Co6H.js → main-BsJ9ec3i.js} +9103 -9018
  49. package/dist/synapse.css +1 -1
  50. package/dist/vuetifyConfig.js +1 -1
  51. package/package.json +8 -7
  52. package/src/assets/overrides/_icons.scss +0 -13
  53. package/src/assets/overrides/_otp.scss +0 -1
  54. package/src/components/Accordion/Accordion.vue +2 -0
  55. package/src/components/CookiesSelection/CookiesInformation/CookiesInformation.vue +2 -1
  56. package/src/components/CookiesSelection/CookiesSelection.vue +2 -1
  57. package/src/components/CopyBtn/CopyBtn.vue +9 -0
  58. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +1 -1
  59. package/src/components/Customs/Selects/SySelect/SySelect.stories.ts +413 -96
  60. package/src/components/Customs/Selects/SySelect/SySelect.vue +270 -225
  61. package/src/components/Customs/Selects/SySelect/tests/SySelect.spec.ts +245 -6
  62. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +3 -3
  63. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +23 -2
  64. package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +23 -5
  65. package/src/components/Customs/SyTabs/SyTabs.stories.ts +5 -5
  66. package/src/components/Customs/SyTabs/config.ts +3 -3
  67. package/src/components/Customs/SyTextField/SyTextField.vue +31 -4
  68. package/src/components/DatePicker/CalendarMode/DatePicker.stories.ts +1 -1
  69. package/src/components/DatePicker/CalendarMode/DatePicker.vue +17 -14
  70. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +1 -1
  71. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +8 -7
  72. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +1 -1
  73. package/src/components/DatePicker/DatePickerValidationExample/DatePickerValidation.stories.ts +1 -1
  74. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +57 -23
  75. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +1 -1
  76. package/src/components/DatePicker/composables/useDatePickerState.ts +33 -14
  77. package/src/components/DatePicker/composables/useDateRangeInput.ts +2 -1
  78. package/src/components/DatePicker/composables/useDateSelection.ts +2 -1
  79. package/src/components/DatePicker/composables/useDateTextField.ts +2 -2
  80. package/src/components/DatePicker/composables/useInputBlurHandler.ts +2 -2
  81. package/src/components/DatePicker/types.ts +1 -2
  82. package/src/components/DialogBox/DialogBox.stories.ts +8 -8
  83. package/src/components/DialogBox/accessibilite/Accessibility.mdx +86 -22
  84. package/src/components/FilterSideBar/FilterSideBar.vue +2 -1
  85. package/src/components/LangBtn/LangBtn.vue +2 -1
  86. package/src/components/NotificationBar/Notification/Notification.vue +2 -2
  87. package/src/components/PaginatedTable/PaginatedTable.vue +1 -1
  88. package/src/components/PaginatedTable/Pagination.vue +1 -1
  89. package/src/components/PasswordField/PasswordField.vue +7 -3
  90. package/src/components/PhoneField/PhoneField.vue +4 -2
  91. package/src/components/RangeField/RangeSlider/RangeSlider.vue +11 -18
  92. package/src/components/RatingPicker/EmotionPicker/EmotionPicker.vue +32 -48
  93. package/src/components/RatingPicker/EmotionPicker/tests/__snapshots__/EmotionPicker.spec.ts.snap +5 -0
  94. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +48 -53
  95. package/src/components/RatingPicker/NumberPicker/tests/NumberPicker.spec.ts +2 -1
  96. package/src/components/RatingPicker/NumberPicker/tests/__snapshots__/NumberPicker.spec.ts.snap +40 -13
  97. package/src/components/RatingPicker/RatingPicker.stories.ts +65 -88
  98. package/src/components/RatingPicker/RatingPicker.vue +71 -15
  99. package/src/components/RatingPicker/StarsPicker/StarsPicker.vue +28 -37
  100. package/src/components/RatingPicker/StarsPicker/tests/StarsPicker.spec.ts +1 -1
  101. package/src/components/RatingPicker/StarsPicker/tests/__snapshots__/StarsPicker.spec.ts.snap +5 -0
  102. package/src/components/RatingPicker/accessibilite/Accessibility.mdx +137 -9
  103. package/src/components/RatingPicker/tests/RatingPicker.a11y.spect.ts +123 -0
  104. package/src/components/RatingPicker/tests/RatingPicker.spec.ts +3 -2
  105. package/src/components/RatingPicker/tests/__snapshots__/RatingPicker.spec.ts.snap +40 -11
  106. package/src/components/RatingPicker/useRatingFocus.ts +97 -0
  107. package/src/components/SyTextArea/SyTextArea.vue +32 -1
  108. package/src/components/Tables/SyServerTable/SyServerTable.vue +1 -1
  109. package/src/components/Tables/SyTable/SyTable.vue +1 -1
  110. package/src/components/Tables/common/SyTableFilter.vue +4 -4
  111. package/src/components/Tables/common/SyTablePagination.vue +1 -0
  112. package/src/components/Tables/common/TableHeader.vue +1 -1
  113. package/src/components/Tables/common/filters/DateFilter.vue +2 -2
  114. package/src/composables/date/tests/useDateFormatDayjs.spec.ts +81 -0
  115. package/src/composables/date/tests/{useDateInitialization.spec.ts → useDateInitializationDayjs.spec.ts} +39 -3
  116. package/src/composables/date/useDateInitializationDayjs.ts +4 -1
  117. package/src/composables/unifyValidation/documentationValidationProps.ts +7 -7
  118. package/src/composables/unifyValidation/tests/useCustomValidation.spec.ts +2 -1
  119. package/src/composables/unifyValidation/tests/useValidation.spec.ts +22 -0
  120. package/src/composables/unifyValidation/useCustomValidation.ts +16 -4
  121. package/src/composables/unifyValidation/useValidation.ts +46 -15
  122. package/src/composables/unifyValidation/useVuetifyValidation.ts +2 -2
  123. package/src/composables/useFormFieldErrorHandling.ts +4 -1
  124. package/src/composables/validation/tests/useValidation.spec.ts +2 -2
  125. package/src/composables/validation/useValidation.ts +15 -3
  126. package/src/composantsVuetify/VCard/VCard.mdx +59 -0
  127. package/src/composantsVuetify/VCard/v-card.stories.ts +279 -0
  128. package/src/designTokens/tokens/amelipro/apColors2026.ts +1 -1
  129. package/src/designTokens/tokens/amelipro/apLightTheme.ts +3 -0
  130. package/src/designTokens/tokens/cnam/cnamLightTheme.ts +3 -0
  131. package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +61 -91
  132. package/src/stories/Accessibilite/AuditDesignSystem.mdx +5 -8
  133. package/src/stories/Accessibilite/AuditEtContreAudit/Exemptions-derogations.mdx +1 -1
  134. package/src/stories/Accessibilite/AuditEtContreAudit/Introduction.mdx +11 -8
  135. package/src/stories/Accessibilite/AuditEtContreAudit/RGAA.mdx +6 -7
  136. package/src/stories/Accessibilite/Introduction.mdx +30 -30
  137. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +168 -78
  138. package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +13 -6
  139. package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +66 -45
  140. package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +23 -49
  141. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.stories.ts +6 -0
  142. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/Utilisation.mdx +7 -19
  143. package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +18 -20
  144. package/src/stories/Components/Components.stories.ts +52 -3
  145. package/dist/AutocompleteFilter-Df9i5mAl.cjs +0 -1
  146. package/dist/DateFilter-BJD6FMev.cjs +0 -1
  147. package/dist/NumberFilter-DGCzCXzI.cjs +0 -1
  148. package/dist/PeriodFilter-DO_ecTZW.cjs +0 -1
  149. package/dist/SelectFilter-CGwcKWLm.cjs +0 -1
  150. package/dist/TextFilter-B8nf7xoK.cjs +0 -1
  151. package/dist/apLightTheme-CEK4iY3f.cjs +0 -1
  152. package/dist/composables/date/useDateFormat.d.ts +0 -26
  153. package/dist/composables/date/useDateInitialization.d.ts +0 -18
  154. package/dist/design-system-v3.umd.cjs +0 -1
  155. package/dist/main-ByDPHpae.cjs +0 -1067
  156. package/dist/tooth-11-D3sLWv2n.cjs +0 -1
  157. package/dist/tooth-12-CXrLuH03.cjs +0 -1
  158. package/dist/tooth-13-BSfo5fpT.cjs +0 -1
  159. package/dist/tooth-14-DMzulx0h.cjs +0 -1
  160. package/dist/tooth-15-BKRFVi-9.cjs +0 -1
  161. package/dist/tooth-16-CpuxAbuM.cjs +0 -1
  162. package/dist/tooth-17-BPoahUdg.cjs +0 -1
  163. package/dist/tooth-18-DhHJz8sy.cjs +0 -1
  164. package/dist/tooth-21-Dgd5hn_X.cjs +0 -1
  165. package/dist/tooth-22-C2Tn19sB.cjs +0 -1
  166. package/dist/tooth-23-C9uaaSGb.cjs +0 -1
  167. package/dist/tooth-24-BrK9UGpf.cjs +0 -1
  168. package/dist/tooth-25-CE_EfGNp.cjs +0 -1
  169. package/dist/tooth-26-Ctv4i9Fy.cjs +0 -1
  170. package/dist/tooth-27-C5J7JkWM.cjs +0 -1
  171. package/dist/tooth-28-Z9oWqjo0.cjs +0 -1
  172. package/dist/tooth-31-BrYqmkTi.cjs +0 -1
  173. package/dist/tooth-32-BNNR0oCZ.cjs +0 -1
  174. package/dist/tooth-33-DuxvqO2J.cjs +0 -1
  175. package/dist/tooth-34-BCSCXMB6.cjs +0 -1
  176. package/dist/tooth-35-BLUXkX88.cjs +0 -1
  177. package/dist/tooth-36-IrKHYqlA.cjs +0 -1
  178. package/dist/tooth-37-BYqpdMwo.cjs +0 -1
  179. package/dist/tooth-38-B_eNXXdu.cjs +0 -1
  180. package/dist/tooth-41-Ddva4Ot8.cjs +0 -1
  181. package/dist/tooth-42-szcDqlM0.cjs +0 -1
  182. package/dist/tooth-43-B3ka6rQm.cjs +0 -1
  183. package/dist/tooth-44-CazyQucj.cjs +0 -1
  184. package/dist/tooth-45-B4HQtc8n.cjs +0 -1
  185. package/dist/tooth-46-BPM40gbG.cjs +0 -1
  186. package/dist/tooth-47-Dvr20dlh.cjs +0 -1
  187. package/dist/tooth-48-Bd8ljGsF.cjs +0 -1
  188. package/dist/tooth-51-OBpwCOF3.cjs +0 -1
  189. package/dist/tooth-52-aKxyHcmq.cjs +0 -1
  190. package/dist/tooth-53-vCwJjTOc.cjs +0 -1
  191. package/dist/tooth-54-DsWu2iFy.cjs +0 -1
  192. package/dist/tooth-55-BxC1X2Dn.cjs +0 -1
  193. package/dist/tooth-61-BbLvxMQi.cjs +0 -1
  194. package/dist/tooth-62-CmTkWczP.cjs +0 -1
  195. package/dist/tooth-63-DI7l_2qI.cjs +0 -1
  196. package/dist/tooth-64-B21sOsJh.cjs +0 -1
  197. package/dist/tooth-65-D2ZC2VEr.cjs +0 -1
  198. package/dist/tooth-71-D473PPO5.cjs +0 -1
  199. package/dist/tooth-72-Drh1wnNu.cjs +0 -1
  200. package/dist/tooth-73-DzlwYI23.cjs +0 -1
  201. package/dist/tooth-74-8aGvcZPg.cjs +0 -1
  202. package/dist/tooth-75-BFK7At_r.cjs +0 -1
  203. package/dist/tooth-81-BZmR-I0M.cjs +0 -1
  204. package/dist/tooth-82-euVfUUZV.cjs +0 -1
  205. package/dist/tooth-83-KV010j64.cjs +0 -1
  206. package/dist/tooth-84-BBg1RjhZ.cjs +0 -1
  207. package/dist/tooth-85-Cr-kc1wM.cjs +0 -1
  208. package/dist/vuetifyConfig.umd.cjs +0 -1
  209. package/src/composables/date/tests/useDateFormat.spec.ts +0 -67
  210. package/src/composables/date/useDateFormat.ts +0 -110
  211. package/src/composables/date/useDateInitialization.ts +0 -92
@@ -4,9 +4,8 @@
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, type PropType } from 'vue'
7
+ import { ref, watch, watchEffect, onMounted, onBeforeUnmount, computed, nextTick, useAttrs, toRef, type Ref } from 'vue'
8
8
  import { useSySelectKeyboard } from './composables/useSySelectKeyboard'
9
- import { useValidatable } from '@/composables/validation/useValidatable'
10
9
  import type { ColorType, IconType, VariantStyle } from '@/types/vuetifyTypes'
11
10
  import type { VList, VTextField } from 'vuetify/components'
12
11
  import { VChip } from 'vuetify/components'
@@ -14,6 +13,8 @@
14
13
  import IconSlot from '@/components/Common/IconSlot/IconSlot.vue'
15
14
  import SyIcon from '@/components/Customs/SyIcon/SyIcon.vue'
16
15
  import { locales } from './locales'
16
+ import type { ValidationRule } from '@/composables/validation/useValidation'
17
+ import { useValidation, validationPropsDefaults, type FieldValidationProps } from '@/composables/unifyValidation/useValidation'
17
18
 
18
19
  export type ItemType = {
19
20
  [key: string]: unknown
@@ -22,147 +23,71 @@
22
23
  export type SelectItemValueType = Record<string, unknown> | string | number | null | undefined
23
24
  export type SelectItemArrayType = Array<Record<string, unknown> | string | number>
24
25
 
25
- // Définition des props avec typage correct pour modelValue
26
- const props = defineProps({
27
- modelValue: {
28
- // En Vue, on ne peut pas mettre null directement comme type
29
- // On utilise PropType pour définir le type complet incluant null
30
- type: [Object, String, Number, Array] as PropType<Record<string, unknown> | string | number | null | SelectItemArrayType>,
31
- default: null,
26
+ const props = withDefaults(
27
+ defineProps<{
28
+ modelValue?: Record<string, unknown> | string | number | null | SelectItemArrayType
29
+ items?: ItemType[]
30
+ label?: string
31
+ menuId?: string
32
+ outlined?: boolean
33
+ variantStyle?: VariantStyle
34
+ color?: ColorType
35
+ textKey?: string
36
+ plainTextKey?: string
37
+ valueKey?: string
38
+ displayAsterisk?: boolean
39
+ returnObject?: boolean
40
+ density?: 'default' | 'comfortable' | 'compact'
41
+ bgColor?: string
42
+ clearable?: boolean
43
+ hideDetails?: boolean
44
+ width?: string
45
+ multiple?: boolean
46
+ chips?: boolean
47
+ helpText?: string
48
+ allowHtml?: boolean
49
+ autocomplete?: 'on' | 'off' | string
50
+ prependIcon?: IconType
51
+ appendIcon?: IconType
52
+ prependTooltip?: string
53
+ appendTooltip?: string
54
+ tooltipLocation?: 'top' | 'bottom' | 'start' | 'end'
55
+ noIcon?: boolean
56
+ disableClickButton?: boolean
57
+ } & FieldValidationProps>(),
58
+ {
59
+ modelValue: null,
60
+ items: () => [],
61
+ label: 'Sélectionnez une option',
62
+ menuId: 'sy-select-menu',
63
+ outlined: true,
64
+ variantStyle: undefined,
65
+ color: 'primary',
66
+ textKey: 'text',
67
+ plainTextKey: '',
68
+ valueKey: 'value',
69
+ displayAsterisk: false,
70
+ returnObject: false,
71
+ density: 'default',
72
+ bgColor: 'white',
73
+ clearable: false,
74
+ hideDetails: false,
75
+ width: 'undefined',
76
+ multiple: false,
77
+ chips: false,
78
+ helpText: '',
79
+ allowHtml: false,
80
+ autocomplete: 'on',
81
+ prependIcon: undefined,
82
+ appendIcon: undefined,
83
+ prependTooltip: undefined,
84
+ appendTooltip: undefined,
85
+ tooltipLocation: 'top',
86
+ noIcon: false,
87
+ disableClickButton: true,
88
+ ...validationPropsDefaults,
32
89
  },
33
- items: {
34
- type: Array as PropType<ItemType[]>,
35
- default: () => [],
36
- },
37
- label: {
38
- type: String,
39
- default: 'Sélectionnez une option',
40
- },
41
- errorMessages: {
42
- type: [String, Array] as PropType<string | readonly string[]>,
43
- default: () => [],
44
- },
45
- required: {
46
- type: Boolean,
47
- default: false,
48
- },
49
- disabled: {
50
- type: Boolean,
51
- default: false,
52
- },
53
- menuId: {
54
- type: String,
55
- default: 'sy-select-menu',
56
- },
57
- outlined: {
58
- type: Boolean,
59
- default: true,
60
- },
61
- variantStyle: {
62
- type: String as PropType<VariantStyle | undefined>,
63
- default: undefined,
64
- },
65
- color: {
66
- type: String as PropType<ColorType>,
67
- default: 'primary',
68
- },
69
- textKey: {
70
- type: String,
71
- default: 'text',
72
- },
73
- plainTextKey: {
74
- type: String,
75
- default: '',
76
- },
77
- valueKey: {
78
- type: String,
79
- default: 'value',
80
- },
81
- displayAsterisk: {
82
- type: Boolean,
83
- default: false,
84
- },
85
- returnObject: {
86
- type: Boolean,
87
- default: false,
88
- },
89
- disableErrorHandling: {
90
- type: Boolean,
91
- default: false,
92
- },
93
- density: {
94
- type: String as PropType<'default' | 'comfortable' | 'compact' | undefined>,
95
- default: 'default',
96
- },
97
- bgColor: {
98
- type: String,
99
- default: 'white',
100
- },
101
- readonly: {
102
- type: Boolean,
103
- default: false,
104
- },
105
- clearable: {
106
- type: Boolean,
107
- default: false,
108
- },
109
- hideMessages: {
110
- type: Boolean,
111
- default: false,
112
- },
113
- width: {
114
- type: String,
115
- default: 'undefined',
116
- },
117
- multiple: {
118
- type: Boolean,
119
- default: false,
120
- },
121
- chips: {
122
- type: Boolean,
123
- default: false,
124
- },
125
- helpText: {
126
- type: String,
127
- default: '',
128
- },
129
- allowHtml: {
130
- type: Boolean,
131
- default: false,
132
- },
133
- autocomplete: {
134
- type: String as PropType<'on' | 'off' | undefined | string>,
135
- default: 'on',
136
- },
137
- prependIcon: {
138
- type: String as PropType<IconType>,
139
- default: undefined,
140
- },
141
- appendIcon: {
142
- type: String as PropType<IconType>,
143
- default: undefined,
144
- },
145
- prependTooltip: {
146
- type: String,
147
- default: undefined,
148
- },
149
- appendTooltip: {
150
- type: String,
151
- default: undefined,
152
- },
153
- tooltipLocation: {
154
- type: String as PropType<'top' | 'bottom' | 'start' | 'end'>,
155
- default: 'top',
156
- },
157
- noIcon: {
158
- type: Boolean,
159
- default: false,
160
- },
161
- disableClickButton: {
162
- type: Boolean,
163
- default: true,
164
- },
165
- })
90
+ )
166
91
 
167
92
  // pr récupérer proprement aria-label
168
93
  const attrs = useAttrs()
@@ -195,7 +120,9 @@
195
120
  const disableClickButton = computed(() => props.disableClickButton)
196
121
 
197
122
  const iconColor = computed(() => {
198
- if (hasError.value || props.errorMessages.length > 0) return 'error'
123
+ if (hasError.value) return 'error'
124
+ if (hasWarning.value) return 'warning'
125
+ if (hasSuccess.value) return 'success'
199
126
  return 'rgb(var(--v-theme-iconBase))'
200
127
  })
201
128
 
@@ -207,9 +134,44 @@
207
134
  const isOpen = ref(false)
208
135
  // Initialize selectedItem with props.modelValue or empty array for multiple mode
209
136
  const selectedItem = ref<SelectItemValueType | SelectItemArrayType>(props.modelValue)
210
- const hasError = ref(false)
137
+ const focused = ref(false)
211
138
  const menuMinWidth = ref<number | null>(null)
212
139
 
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
+ })
174
+
213
175
  const labelWidth = ref(0)
214
176
  const labelRef = ref<HTMLElement | null>(null)
215
177
  const list = ref<VList | null>(null)
@@ -262,7 +224,7 @@
262
224
  // text d'aide
263
225
  const helpTextId = computed(() => `${inputId.value}-help`)
264
226
  // messages d'erreur, success avertissement
265
- const messagesId = computed(() => `${inputId.value}-messages`)
227
+ const messagesId = computed(() => `${inputId.value}-sr-messages`)
266
228
  // live region pour le lecteur ecran
267
229
  const liveRegionId = computed(() => `${inputId.value}-live`)
268
230
  // un libellé caché pour la popup/grid
@@ -315,6 +277,7 @@
315
277
  if (item === null || item === undefined) {
316
278
  selectedItem.value = props.multiple ? [] : null
317
279
  emit('update:modelValue', props.multiple ? [] : null)
280
+ clearValidation()
318
281
 
319
282
  // Garder la liste ouverte après une suppression et réinitialiser la navigation au clavier
320
283
  const target = event?.target as HTMLElement | undefined
@@ -500,12 +463,25 @@
500
463
  return !props.chips && props.multiple && Array.isArray(selectedItem.value) && (selectedItem.value as unknown[]).length > 0
501
464
  })
502
465
 
466
+ const hasSingleSelection = computed(() => {
467
+ return !props.multiple && selectedItem.value !== null && selectedItem.value !== undefined && selectedItemText.value !== ''
468
+ })
469
+
503
470
  const hasSelectionToClear = computed(() => {
504
471
  return props.multiple
505
472
  ? (((selectedItem.value as unknown[] | null | undefined)?.length) ?? 0) > 0
506
473
  : selectedItem.value != null
507
474
  })
508
475
 
476
+ const isFieldActive = computed(() => {
477
+ return hasChips.value
478
+ || hasMultipleSelections.value
479
+ || hasSingleSelection.value
480
+ || isOpen.value
481
+ || focused.value
482
+ || hasMessages.value
483
+ })
484
+
509
485
  const labelWithAsterisk = computed(() => {
510
486
  return isShouldDisplayAsterisk.value ? `${props.label} *` : props.label
511
487
  })
@@ -520,15 +496,14 @@
520
496
  })
521
497
 
522
498
  const isRequired = computed(() => {
523
- if (props.disableErrorHandling) return false
524
- if (props.readonly) return
525
- return (props.required || props.errorMessages.length > 0) && !selectedItem.value
499
+ if (props.readonly) return false
500
+ return props.required === true
526
501
  })
527
502
 
528
503
  // Détecte s'il y a des messages d'erreur, de succès ou d'avertissement
529
504
  const hasMessages = computed(() => {
530
505
  if (props.disableErrorHandling) return false
531
- return props.errorMessages.length > 0 || hasError.value
506
+ return hasError.value || hasWarning.value || hasSuccess.value
532
507
  })
533
508
 
534
509
  // Détermine si le helpText doit être affiché à la position du message ou en dessous
@@ -538,8 +513,8 @@
538
513
  })
539
514
 
540
515
  const showHelpTextBelow = computed(() => {
541
- // Afficher en dessous si il y a des messages d'erreur ET hideMessages n'est pas activé
542
- return props.helpText && hasMessages.value && !props.hideMessages
516
+ // Afficher en dessous si il y a des messages d'erreur ET hideDetails n'est pas activé
517
+ return props.helpText && hasMessages.value && !props.hideDetails
543
518
  })
544
519
 
545
520
  // Ici on calcule dynamiquement la liste des ids à rattacher à l'input :
@@ -551,11 +526,11 @@
551
526
  ids.push(helpTextId.value)
552
527
  }
553
528
  // messages affichés
554
- if (!props.hideMessages && hasMessages.value) {
529
+ if (!props.hideDetails && hasMessages.value) {
555
530
  ids.push(messagesId.value)
556
531
  }
557
532
  // live region si erreur
558
- if (hasError.value || (Array.isArray(props.errorMessages) && props.errorMessages.length > 0)) {
533
+ if (hasError.value || errors.value.length > 0) {
559
534
  ids.push(liveRegionId.value)
560
535
  }
561
536
 
@@ -578,21 +553,13 @@
578
553
  return undefined
579
554
  })
580
555
 
581
- const validationRules = computed(() => {
582
- return hasError.value && !props.disableErrorHandling ? ['Le champ est requis.'] : []
583
- })
584
-
585
556
  const menuTarget = computed<HTMLElement | undefined>(() => {
586
557
  const rootEl = textInput.value?.$el as HTMLElement | undefined
587
558
  if (!rootEl) return undefined
588
559
  return (rootEl.querySelector('.v-field') as HTMLElement | null) ?? rootEl
589
560
  })
590
561
 
591
- const formattedErrorMessages = computed(() => {
592
- return Array.isArray(props.errorMessages)
593
- ? props.errorMessages.join(' ')
594
- : props.errorMessages
595
- })
562
+ const formattedErrorMessages = computed(() => errors.value.join(' '))
596
563
 
597
564
  const liveRegionMessage = computed(() => {
598
565
  if (!hasError.value) return ''
@@ -600,6 +567,14 @@
600
567
  return formattedErrorMessages.value || 'Le champ contient une erreur.'
601
568
  })
602
569
 
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
+
603
578
  watch(() => props.modelValue, (newValue) => {
604
579
  selectedItem.value = newValue
605
580
  })
@@ -720,35 +695,6 @@
720
695
  }
721
696
  }
722
697
 
723
- watch(isOpen, (newIsOpen) => {
724
- if (!newIsOpen) {
725
- // Valider uniquement à la fermeture du menu
726
- if (props.disableErrorHandling || props.readonly) {
727
- hasError.value = false
728
- }
729
- else {
730
- const shouldHaveError = (!selectedItem.value && isRequired.value) || props.errorMessages.length > 0
731
- hasError.value = shouldHaveError
732
-
733
- // Forcer la validation du VTextField avec nextTick pour que le DOM soit à jour
734
- nextTick(() => {
735
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
736
- if (textInput.value && (textInput.value as any).validate) {
737
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
738
- ;(textInput.value as any).validate()
739
- }
740
- })
741
- }
742
- }
743
- // Ne rien faire à l'ouverture pour préserver l'état actuel
744
- })
745
-
746
- watch(() => props.errorMessages, (newValue) => {
747
- if (!props.disableErrorHandling) {
748
- hasError.value = newValue.length > 0
749
- }
750
- })
751
-
752
698
  const ariaManager = {
753
699
  cleanInputAttributes(inputElement: HTMLElement): void {
754
700
  if (!inputElement) return
@@ -886,6 +832,8 @@
886
832
  watch(isOpen, async (newValue) => {
887
833
  await nextTick()
888
834
 
835
+ focused.value = newValue
836
+
889
837
  if (!textInput.value || !textInput.value.$el) return
890
838
 
891
839
  setupAriaAttributes()
@@ -937,25 +885,6 @@
937
885
  })
938
886
  }, { deep: true })
939
887
 
940
- // Méthode de validation pour l'enregistrement avec le système de validation du formulaire
941
- const validateOnSubmit = (): boolean => {
942
- // Si en mode readonly ou si la gestion d'erreur est désactivée, toujours valide
943
- if (props.readonly || props.disableErrorHandling) {
944
- return true
945
- }
946
-
947
- // Vérifier si une valeur est sélectionnée quand le champ est requis
948
- const isValid = !isRequired.value
949
-
950
- // Mettre à jour l'état d'erreur
951
- hasError.value = !isValid || props.errorMessages.length > 0
952
-
953
- return isValid
954
- }
955
-
956
- // Intégration avec le système de validation du formulaire
957
- useValidatable(validateOnSubmit)
958
-
959
888
  watch(isOpen, () => {
960
889
  nextTick(() => {
961
890
  updateMenuMinWidth()
@@ -970,7 +899,7 @@
970
899
  defineExpose({
971
900
  isOpen,
972
901
  closeList,
973
- validateOnSubmit,
902
+ validateOnSubmit: validate,
974
903
  })
975
904
 
976
905
  // on reprend la mm methode que pour le datepicker : useDatePickerAccesssibity (updateAccessibility)
@@ -1058,19 +987,26 @@
1058
987
  :disabled="disabled"
1059
988
  :label="labelWithAsterisk"
1060
989
  :aria-label="accessibleLabel"
1061
- :error-messages="props.disableErrorHandling ? [] : errorMessages"
990
+ :error="hasError"
991
+ :error-messages="errors"
992
+ :messages="hasError ? errors : (hasWarning ? warnings : (hasSuccess && props.showSuccessMessages ? successes : undefined))"
1062
993
  :variant="variant"
1063
- :rules="validationRules"
1064
994
  :bg-color="props.bgColor"
1065
995
  :density="props.density"
1066
- :active="hasChips || hasMultipleSelections || isOpen"
996
+ :active="isFieldActive"
1067
997
  readonly
1068
- :hide-details="props.hideMessages && !showHelpTextAsMessage"
998
+ :hide-details="props.hideDetails && !showHelpTextAsMessage"
1069
999
  :hint="showHelpTextAsMessage ? props.helpText : ''"
1070
1000
  :persistent-hint="!!showHelpTextAsMessage"
1071
1001
  :autocomplete="props.autocomplete"
1072
1002
  :width="calculatedWidth"
1073
1003
  :style="hasError ? { minWidth: `${labelWidth + 18}px`} : { minWidth: `${labelWidth}px` }"
1004
+ :class="{
1005
+ 'error-field': hasError,
1006
+ 'warning-field': hasWarning,
1007
+ 'success-field': hasSuccess,
1008
+ 'basic-field': !hasError && !hasWarning && !hasSuccess,
1009
+ }"
1074
1010
  v-bind="{
1075
1011
  ...Object.fromEntries(Object.entries($attrs).filter(([key]) => key !== 'display-asterisk')),
1076
1012
  ...initializeActivatorProps(activatorProps),
@@ -1165,19 +1101,18 @@
1165
1101
 
1166
1102
  <template #append-inner>
1167
1103
  <SyIcon
1168
- v-if="hasError"
1104
+ v-if="validationIcon"
1169
1105
  class="mr-6"
1170
- color="error"
1171
- :icon="mdiAlertCircle"
1172
- :decorative="false"
1173
- label="Information"
1174
- role="img"
1106
+ :color="hasError ? 'error' : (hasWarning ? 'warning' : 'success')"
1107
+ :icon="validationIcon"
1108
+ :decorative="true"
1109
+ role="presentation"
1175
1110
  />
1176
1111
  <button
1177
1112
  v-if="props.clearable && hasSelectionToClear"
1178
1113
  type="button"
1179
1114
  class="sy-select__clear-button"
1180
- :style="{ right: hasError ? '62px' : '42px' }"
1115
+ :style="{ right: (hasError || hasWarning || hasSuccess) ? '62px' : '42px' }"
1181
1116
  :aria-label="locales.clear"
1182
1117
  @keydown.enter.prevent="$event => selectItem(null, $event)"
1183
1118
  @keydown.space.prevent="$event => selectItem(null, $event)"
@@ -1297,11 +1232,11 @@
1297
1232
  </div>
1298
1233
 
1299
1234
  <div
1300
- v-if="!props.hideMessages && hasMessages"
1235
+ v-if="!props.hideDetails && hasMessages"
1301
1236
  :id="messagesId"
1302
1237
  class="d-sr-only"
1303
1238
  >
1304
- {{ formattedErrorMessages }}
1239
+ {{ hasError ? errors.join(' ') : (hasWarning ? warnings.join(' ') : successes.join(' ')) }}
1305
1240
  </div>
1306
1241
 
1307
1242
  <div
@@ -1346,6 +1281,117 @@
1346
1281
  }
1347
1282
  }
1348
1283
 
1284
+ .warning-field {
1285
+ :deep(.v-icon__svg) {
1286
+ fill: rgb(var(--v-theme-textWarning)) !important;
1287
+ }
1288
+
1289
+ :deep(.v-icon.arrow) {
1290
+ color: rgb(var(--v-theme-iconBase)) !important;
1291
+ }
1292
+
1293
+ :deep(.v-icon.arrow .v-icon__svg) {
1294
+ fill: rgb(var(--v-theme-iconBase)) !important;
1295
+ }
1296
+
1297
+ :deep(.sy-select__clear-icon .v-icon__svg) {
1298
+ fill: rgb(var(--v-theme-iconBase)) !important;
1299
+ }
1300
+
1301
+ :deep(.v-field) {
1302
+ color: rgb(var(--v-theme-borderWarning)) !important;
1303
+
1304
+ --v-medium-emphasis-opacity: 1;
1305
+
1306
+ .v-field__outline {
1307
+ --v-field-border-opacity: 1;
1308
+
1309
+ color: rgb(var(--v-theme-borderWarning)) !important;
1310
+ }
1311
+ }
1312
+
1313
+ :deep(.v-messages) {
1314
+ opacity: 1 !important;
1315
+
1316
+ .v-messages__message {
1317
+ color: rgb(var(--v-theme-borderWarning)) !important;
1318
+ }
1319
+ }
1320
+ }
1321
+
1322
+ .error-field {
1323
+ :deep(.v-field) {
1324
+ color: rgb(var(--v-theme-borderError)) !important;
1325
+
1326
+ .v-field__outline {
1327
+ --v-field-border-opacity: 1;
1328
+
1329
+ color: rgb(var(--v-theme-borderError)) !important;
1330
+ }
1331
+ }
1332
+
1333
+ :deep(.v-messages) {
1334
+ opacity: 1 !important;
1335
+
1336
+ .v-messages__message {
1337
+ color: rgb(var(--v-theme-borderError)) !important;
1338
+ }
1339
+ }
1340
+
1341
+ :deep(.v-icon.arrow) {
1342
+ color: rgb(var(--v-theme-iconSubdued)) !important;
1343
+ }
1344
+
1345
+ :deep(.v-icon.arrow .v-icon__svg) {
1346
+ fill: rgb(var(--v-theme-iconSubdued)) !important;
1347
+ }
1348
+ }
1349
+
1350
+ .success-field {
1351
+ :deep(.v-icon__svg) {
1352
+ fill: rgb(var(--v-theme-textSuccess)) !important;
1353
+ }
1354
+
1355
+ :deep(.v-icon.arrow) {
1356
+ color: rgb(var(--v-theme-iconBase)) !important;
1357
+ }
1358
+
1359
+ :deep(.v-icon.arrow .v-icon__svg) {
1360
+ fill: rgb(var(--v-theme-iconBase)) !important;
1361
+ }
1362
+
1363
+ :deep(.sy-select__clear-icon .v-icon__svg) {
1364
+ fill: rgb(var(--v-theme-iconBase)) !important;
1365
+ }
1366
+
1367
+ :deep(.v-field) {
1368
+ color: rgb(var(--v-theme-borderSuccess)) !important;
1369
+
1370
+ --v-medium-emphasis-opacity: 1;
1371
+
1372
+ .v-field__outline {
1373
+ --v-field-border-opacity: 1;
1374
+
1375
+ color: rgb(var(--v-theme-borderSuccess)) !important;
1376
+ }
1377
+ }
1378
+
1379
+ :deep(.v-messages) {
1380
+ opacity: 1 !important;
1381
+
1382
+ .v-messages__message {
1383
+ color: rgb(var(--v-theme-borderSuccess)) !important;
1384
+ }
1385
+ }
1386
+ }
1387
+
1388
+ .basic-field {
1389
+ :deep(.v-field--focused .v-field__outline) {
1390
+ color: rgb(var(--v-theme-borderAccentPrimary)) !important;
1391
+ opacity: 1 !important;
1392
+ }
1393
+ }
1394
+
1349
1395
  .v-field {
1350
1396
  position: relative;
1351
1397
  }
@@ -1418,7 +1464,6 @@
1418
1464
  .v-icon.arrow {
1419
1465
  position: absolute;
1420
1466
  right: 10px;
1421
- color: rgb(var(--v-theme-iconBase));
1422
1467
  }
1423
1468
 
1424
1469
  .sy-select__clear-icon {