@cnamts/synapse 1.0.1 → 1.0.2

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 (217) hide show
  1. package/README.md +1 -1
  2. package/dist/{DateFilter-BmRuzQ9Z.js → DateFilter-YWOTbfeL.js} +1 -1
  3. package/dist/{NumberFilter-CnIPDHqx.js → NumberFilter-DMmMgALM.js} +1 -1
  4. package/dist/{PeriodFilter-CZwZ8CnQ.js → PeriodFilter-Bok5BHcn.js} +1 -1
  5. package/dist/SelectFilter-BKud2WhN.js +136 -0
  6. package/dist/{TextFilter-DTxZHJwX.js → TextFilter-DvMf2thH.js} +1 -1
  7. package/dist/components/Accordion/Accordion.d.ts +2 -1
  8. package/dist/components/Accordion/composables/useAccordionGroupCommunication.d.ts +5 -0
  9. package/dist/components/Accordion/composables/useAccordionKeyboardNavigation.d.ts +12 -0
  10. package/dist/components/Accordion/composables/useAccordionState.d.ts +13 -0
  11. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +85 -0
  12. package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
  13. package/dist/components/Customs/SySelect/SySelect.d.ts +33 -13
  14. package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -2
  15. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +1585 -1452
  16. package/dist/components/DatePicker/DatePicker/DatePicker.d.ts +16 -2
  17. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +3 -1
  18. package/dist/components/DatePicker/composables/index.d.ts +2 -0
  19. package/dist/components/DatePicker/composables/useAsteriskDisplay.d.ts +14 -0
  20. package/dist/components/DatePicker/composables/useDateAutoClamp.d.ts +16 -0
  21. package/dist/components/DatePicker/composables/useDateRangeInput.d.ts +1 -1
  22. package/dist/components/DatePicker/composables/useDisplayedDateString.d.ts +3 -0
  23. package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +1 -0
  24. package/dist/components/DatePicker/composables/useMonthButtonCustomization.d.ts +5 -2
  25. package/dist/components/NirField/NirField.d.ts +7 -3
  26. package/dist/components/NirField/nirValidation.d.ts +1 -1
  27. package/dist/components/PasswordField/PasswordField.d.ts +2 -0
  28. package/dist/components/PeriodField/PeriodField.d.ts +52 -8
  29. package/dist/components/PhoneField/PhoneField.d.ts +2 -2
  30. package/dist/components/RangeField/RangeField.d.ts +2 -0
  31. package/dist/components/SearchListField/SearchListField.d.ts +9 -0
  32. package/dist/components/SyTextArea/SyTextArea.d.ts +2 -0
  33. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +14 -9
  34. package/dist/components/Tables/SyTable/SyTable.d.ts +12 -7
  35. package/dist/components/Tables/common/SyTablePagination.d.ts +1636 -0
  36. package/dist/components/Tables/common/TableHeader.d.ts +2 -20
  37. package/dist/components/Tables/common/filters/SelectFilter.d.ts +5 -5
  38. package/dist/components/Tables/common/filters/getFilterComponent.d.ts +1 -0
  39. package/dist/components/Tables/common/filters/locales.d.ts +4 -0
  40. package/dist/components/Tables/common/filters/logics/date.d.ts +1 -0
  41. package/dist/components/Tables/common/filters/logics/number.d.ts +1 -0
  42. package/dist/components/Tables/common/filters/logics/period.d.ts +1 -0
  43. package/dist/components/Tables/common/filters/logics/select.d.ts +1 -0
  44. package/dist/components/Tables/common/filters/logics/text.d.ts +1 -0
  45. package/dist/components/Tables/common/locales.d.ts +21 -0
  46. package/dist/components/Tables/common/organizeColumns/OrganizeColumns.d.ts +267 -0
  47. package/dist/components/Tables/common/organizeColumns/sortHeaders.d.ts +2 -0
  48. package/dist/components/Tables/common/tableFilterUtils.d.ts +1 -0
  49. package/dist/components/Tables/common/tableStorageUtils.d.ts +41 -1
  50. package/dist/components/Tables/common/tableUtils.d.ts +42 -5
  51. package/dist/components/Tables/common/types.d.ts +19 -8
  52. package/dist/components/Tables/common/usePagination.d.ts +22 -0
  53. package/dist/components/Tables/common/useTableCheckbox.d.ts +20 -0
  54. package/dist/components/Tables/common/useTableHeaders.d.ts +76 -0
  55. package/dist/components/Tables/common/useTableItems.d.ts +24 -0
  56. package/dist/components/Tables/common/useTableOptions.d.ts +18 -0
  57. package/dist/components/ToolbarContainer/ToolbarContainer.d.ts +11 -0
  58. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +9 -2
  59. package/dist/components/index.d.ts +8 -6
  60. package/dist/design-system-v3.js +58 -56
  61. package/dist/design-system-v3.umd.cjs +22 -22
  62. package/dist/main-Cx8qG7YR.js +16344 -0
  63. package/dist/stories/Accessibilite/Vuetify/VuetifyItems.d.ts +14 -2
  64. package/dist/stories/DesignTokens/StylesTypographiques.stories.new.d.ts +8 -0
  65. package/dist/stories/DesignTokens/TypographyDisplay.d.ts +28 -0
  66. package/dist/stories/DesignTokens/vue-shims.d.ts +6 -0
  67. package/dist/style.css +1 -1
  68. package/package.json +1 -1
  69. package/src/common/imgs/accessibility-svgrepo-com.svg +4 -0
  70. package/src/components/Accordion/Accessibilite/AccessibilityGuide.mdx +249 -0
  71. package/src/components/Accordion/Accordion.vue +48 -76
  72. package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +146 -0
  73. package/src/components/Accordion/composables/__tests__/useAccordionKeyboardNavigation.spec.ts +209 -0
  74. package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +144 -0
  75. package/src/components/Accordion/composables/useAccordionGroupCommunication.ts +52 -0
  76. package/src/components/Accordion/composables/useAccordionKeyboardNavigation.ts +111 -0
  77. package/src/components/Accordion/composables/useAccordionState.ts +59 -0
  78. package/src/components/Accordion/tests/__snapshots__/accordion.spec.ts.snap +3 -0
  79. package/src/components/Customs/SyCheckbox/Accessibilite.mdx +303 -0
  80. package/src/components/Customs/SyCheckbox/SyCheckbox.mdx +50 -0
  81. package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +630 -0
  82. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +326 -0
  83. package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +201 -0
  84. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +1 -0
  85. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +8 -1
  86. package/src/components/Customs/SySelect/SySelect.stories.ts +160 -0
  87. package/src/components/Customs/SySelect/SySelect.vue +291 -32
  88. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +230 -0
  89. package/src/components/Customs/SyTextField/SyTextField.stories.ts +3 -2
  90. package/src/components/Customs/SyTextField/SyTextField.vue +19 -8
  91. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +241 -31
  92. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +305 -57
  93. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.events.spec.ts +161 -0
  94. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +4 -2
  95. package/src/components/DatePicker/DatePicker/DatePicker.stories.ts +259 -137
  96. package/src/components/DatePicker/DatePicker/DatePicker.vue +153 -25
  97. package/src/components/DatePicker/DatePicker/tests/DatePicker.events.spec.ts +189 -0
  98. package/src/components/DatePicker/DatePicker/{DatePicker.spec.ts → tests/DatePicker.spec.ts} +1 -15
  99. package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +24 -14
  100. package/src/components/DatePicker/DateTextInput/DateTextInput.events.spec.ts +148 -0
  101. package/src/components/DatePicker/DateTextInput/DateTextInput.spec.ts +3 -1
  102. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +200 -5
  103. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +241 -31
  104. package/src/components/DatePicker/composables/index.ts +2 -0
  105. package/src/components/DatePicker/composables/tests/useDateAutoClamp.spec.ts +190 -0
  106. package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +182 -4
  107. package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +105 -80
  108. package/src/components/DatePicker/composables/useAsteriskDisplay.ts +31 -0
  109. package/src/components/DatePicker/composables/useDateAutoClamp.ts +136 -0
  110. package/src/components/DatePicker/composables/useDateRangeInput.ts +21 -18
  111. package/src/components/DatePicker/composables/useDisplayedDateString.ts +13 -1
  112. package/src/components/DatePicker/composables/useInputBlurHandler.ts +84 -20
  113. package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +149 -51
  114. package/src/components/DiacriticPicker/DiacriticPicker.stories.ts +10 -0
  115. package/src/components/ErrorPage/Accessibilite.stories.ts +8 -0
  116. package/src/components/ErrorPage/ErrorPage.vue +12 -6
  117. package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +4 -4
  118. package/src/components/NirField/NirField.mdx +22 -9
  119. package/src/components/NirField/NirField.stories.ts +26 -2
  120. package/src/components/NirField/NirField.vue +209 -22
  121. package/src/components/NirField/nirValidation.ts +17 -3
  122. package/src/components/NirField/tests/NirField.spec.ts +2 -2
  123. package/src/components/NotFoundPage/Accessibilite.stories.ts +8 -0
  124. package/src/components/NotFoundPage/NotFoundPage.vue +2 -1
  125. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +8 -6
  126. package/src/components/PaginatedTable/PaginatedTable.mdx +2 -0
  127. package/src/components/PasswordField/PasswordField.stories.ts +4 -0
  128. package/src/components/PasswordField/PasswordField.vue +3 -0
  129. package/src/components/PeriodField/PeriodField.vue +2 -0
  130. package/src/components/PhoneField/PhoneField.stories.ts +15 -15
  131. package/src/components/PhoneField/PhoneField.vue +1 -1
  132. package/src/components/RangeField/RangeField.stories.ts +9 -0
  133. package/src/components/RangeField/RangeField.vue +4 -0
  134. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +12 -0
  135. package/src/components/SearchListField/SearchListField.vue +5 -0
  136. package/src/components/SyTextArea/SyTextArea.vue +3 -0
  137. package/src/components/SyTextArea/tests/SyTextArea.spec.ts +0 -1
  138. package/src/components/Tables/SyServerTable/FilterRules.stories.ts +632 -15
  139. package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -5
  140. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +2844 -1377
  141. package/src/components/Tables/SyServerTable/SyServerTable.vue +155 -66
  142. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +256 -4
  143. package/src/components/Tables/SyTable/FilterRules.stories.ts +183 -0
  144. package/src/components/Tables/SyTable/SyTable.mdx +14 -4
  145. package/src/components/Tables/SyTable/SyTable.stories.ts +1265 -477
  146. package/src/components/Tables/SyTable/SyTable.vue +152 -72
  147. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +366 -4
  148. package/src/components/Tables/common/SyTableFilter.vue +3 -56
  149. package/src/components/Tables/common/SyTablePagination.vue +375 -0
  150. package/src/components/Tables/common/TableHeader.vue +10 -26
  151. package/src/components/Tables/common/filters/SelectFilter.vue +131 -22
  152. package/src/components/Tables/common/filters/getFilterComponent.ts +54 -0
  153. package/src/components/Tables/common/filters/locales.ts +4 -0
  154. package/src/components/Tables/common/filters/logics/date.ts +12 -0
  155. package/src/components/Tables/common/filters/logics/number.ts +48 -0
  156. package/src/components/Tables/common/filters/logics/period.ts +25 -0
  157. package/src/components/Tables/common/filters/logics/select.ts +27 -0
  158. package/src/components/Tables/common/filters/logics/tests/TextFilterLogic.spec.ts +177 -0
  159. package/src/components/Tables/common/filters/logics/text.ts +62 -0
  160. package/src/components/Tables/common/filters/tests/TextFilter.spec.ts +11 -11
  161. package/src/components/Tables/common/locales.ts +24 -0
  162. package/src/components/Tables/common/organizeColumns/OrganizeColumns.vue +269 -0
  163. package/src/components/Tables/common/organizeColumns/sortHeaders.ts +9 -0
  164. package/src/components/Tables/common/tableFilterUtils.ts +43 -295
  165. package/src/components/Tables/common/tableStorageUtils.ts +27 -2
  166. package/src/components/Tables/common/tableStyles.scss +26 -0
  167. package/src/components/Tables/common/tableUtils.ts +3 -16
  168. package/src/components/Tables/common/tests/SyTablePagination.spec.ts +170 -0
  169. package/src/components/Tables/common/tests/filterByRange.spec.ts +215 -0
  170. package/src/components/Tables/common/tests/tableFilterUtils.spec.ts +0 -14
  171. package/src/components/Tables/common/tests/tableUtils.spec.ts +7 -51
  172. package/src/components/Tables/common/types.ts +17 -6
  173. package/src/components/Tables/common/usePagination.ts +83 -0
  174. package/src/components/Tables/common/useTableCheckbox.ts +58 -0
  175. package/src/components/Tables/common/useTableHeaders.ts +88 -0
  176. package/src/components/Tables/common/useTableItems.ts +87 -0
  177. package/src/components/Tables/common/useTableOptions.ts +93 -0
  178. package/src/components/ToolbarContainer/ToolbarContainer.mdx +16 -0
  179. package/src/components/ToolbarContainer/ToolbarContainer.stories.ts +675 -0
  180. package/src/components/ToolbarContainer/ToolbarContainer.vue +128 -0
  181. package/src/components/ToolbarContainer/tests/ToolbarContainer.spec.ts +156 -0
  182. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +74 -0
  183. package/src/components/UserMenuBtn/UserMenuBtn.vue +19 -17
  184. package/src/components/index.ts +8 -6
  185. package/src/stories/Accessibilite/Aculturation/AuditDesignSystem.mdx +293 -20
  186. package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +448 -54
  187. package/src/stories/Accessibilite/Audit/RGAA.mdx +231 -23
  188. package/src/stories/Accessibilite/Avancement/Avancement.mdx +591 -7
  189. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +139 -38
  190. package/src/stories/Accessibilite/Introduction.mdx +258 -18
  191. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +221 -31
  192. package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +204 -22
  193. package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +537 -24
  194. package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +577 -70
  195. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru.mdx +382 -31
  196. package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +419 -81
  197. package/src/stories/Accessibilite/Vuetify/Vuetify.mdx +132 -6
  198. package/src/stories/Accessibilite/Vuetify/Vuetify.stories.ts +370 -146
  199. package/src/stories/Accessibilite/Vuetify/VuetifyItems.ts +35 -57
  200. package/src/stories/Demarrer/Accueil.stories.ts +20 -5
  201. package/src/stories/DesignTokens/StylesTypographiques.mdx +10 -9
  202. package/src/stories/DesignTokens/StylesTypographiques.stories.new.ts +397 -0
  203. package/src/stories/DesignTokens/StylesTypographiques.stories.ts +397 -0
  204. package/src/stories/DesignTokens/TypographyDisplay.vue +155 -0
  205. package/src/stories/DesignTokens/vue-shims.d.ts +6 -0
  206. package/src/stories/GuideDuDev/LesBreackingChanges.mdx +0 -2
  207. package/src/stories/GuideDuDev/MigrationDepuisBridge.mdx +1 -1
  208. package/src/stories/GuideDuDev/MigrationDepuisVue2.mdx +1 -1
  209. package/src/stories/GuideDuDev/PortailAgent.mdx +10 -0
  210. package/src/stories/GuideDuDev/PortailAgent.stories.ts +506 -0
  211. package/src/stories/GuideDuDev/Theme.mdx +41 -0
  212. package/dist/SelectFilter-Cj-GW2Cc.js +0 -97
  213. package/dist/main-WDqeoGM-.js +0 -14788
  214. package/src/components/PaginatedTable/tests/__snapshots__/PaginatedTable.spec.ts.snap +0 -886
  215. package/src/components/Tables/SyServerTable/tests/__snapshots__/SyServerTable.spec.ts.snap +0 -521
  216. package/src/components/Tables/SyTable/tests/__snapshots__/SyTable.spec.ts.snap +0 -521
  217. package/src/stories/DesignTokens/ThemePA.mdx +0 -35
@@ -0,0 +1,326 @@
1
+ <script lang="ts" setup>
2
+ import { computed, ref, watch, onMounted, nextTick } from 'vue'
3
+ import { useValidation, type ValidationRule } from '@/composables/validation/useValidation'
4
+
5
+ const props = withDefaults(
6
+ defineProps<{
7
+ modelValue?: boolean | null
8
+ indeterminate?: boolean
9
+ label?: string
10
+ color?: string
11
+ disabled?: boolean
12
+ readonly?: boolean
13
+ required?: boolean
14
+ hideDetails?: boolean | 'auto'
15
+ density?: 'default' | 'comfortable' | 'compact'
16
+ errorMessages?: string[] | null
17
+ warningMessages?: string[] | null
18
+ successMessages?: string[] | null
19
+ customRules?: ValidationRule[]
20
+ customWarningRules?: ValidationRule[]
21
+ customSuccessRules?: ValidationRule[]
22
+ showSuccessMessages?: boolean
23
+ isValidateOnBlur?: boolean
24
+ disableErrorHandling?: boolean
25
+ id?: string
26
+ name?: string
27
+ value?: unknown
28
+ trueValue?: unknown
29
+ falseValue?: unknown
30
+ controlsIds?: string[]
31
+ }>(),
32
+ {
33
+ modelValue: false,
34
+ indeterminate: false,
35
+ label: '',
36
+ color: 'primary',
37
+ disabled: false,
38
+ readonly: false,
39
+ required: false,
40
+ hideDetails: false,
41
+ density: 'default',
42
+ errorMessages: null,
43
+ warningMessages: null,
44
+ successMessages: null,
45
+ customRules: () => [],
46
+ customWarningRules: () => [],
47
+ customSuccessRules: () => [],
48
+ showSuccessMessages: true,
49
+ isValidateOnBlur: true,
50
+ disableErrorHandling: false,
51
+ id: undefined,
52
+ name: undefined,
53
+ value: undefined,
54
+ trueValue: () => true,
55
+ falseValue: () => false,
56
+ controlsIds: () => [],
57
+ },
58
+ )
59
+
60
+ const emit = defineEmits(['update:modelValue', 'update:indeterminate', 'change'])
61
+
62
+ const internalIndeterminate = ref(props.indeterminate)
63
+
64
+ const model = computed({
65
+ get() {
66
+ return props.modelValue
67
+ },
68
+ set(value) {
69
+ if (internalIndeterminate.value) {
70
+ internalIndeterminate.value = false
71
+ emit('update:indeterminate', false)
72
+ }
73
+ emit('update:modelValue', value)
74
+ emit('change', value)
75
+ },
76
+ })
77
+
78
+ watch(() => props.indeterminate, (val) => {
79
+ internalIndeterminate.value = val
80
+ })
81
+
82
+ // Initialisation du composable de validation
83
+ const validation = useValidation({
84
+ customRules: props.customRules,
85
+ warningRules: props.customWarningRules,
86
+ successRules: props.customSuccessRules,
87
+ showSuccessMessages: props.showSuccessMessages,
88
+ fieldIdentifier: props.label,
89
+ disableErrorHandling: props.disableErrorHandling,
90
+ })
91
+
92
+ // Synchronisation des messages externes
93
+ watch(() => props.errorMessages, (newVal) => {
94
+ validation.errors.value = newVal || []
95
+ }, { immediate: true })
96
+
97
+ watch(() => props.warningMessages, (newVal) => {
98
+ validation.warnings.value = newVal || []
99
+ }, { immediate: true })
100
+
101
+ watch(() => props.successMessages, (newVal) => {
102
+ validation.successes.value = newVal || []
103
+ }, { immediate: true })
104
+
105
+ // Construction des règles de validation
106
+ const defaultRules = computed<ValidationRule[]>(() => props.required
107
+ ? [{
108
+ type: 'required',
109
+ options: {
110
+ message: `Le champ ${props.label || 'ce champ'} est requis.`,
111
+ fieldIdentifier: props.label,
112
+ },
113
+ }]
114
+ : [],
115
+ )
116
+
117
+ const validateField = (value: boolean | null) => {
118
+ // Si en lecture seule ou si la valeur est null et non requise, pas de validation
119
+ if (props.readonly) {
120
+ validation.clearValidation()
121
+ return true
122
+ }
123
+
124
+ if (value === null && !props.required) {
125
+ validation.clearValidation()
126
+ return true
127
+ }
128
+
129
+ // Pour les règles personnalisées qui vérifient si la case est cochée
130
+ // Si la valeur est true, on peut déjà savoir que la validation va réussir
131
+ if (value === true && props.customRules.every(rule =>
132
+ rule.type === 'custom',
133
+ )) {
134
+ validation.clearValidation()
135
+ return true
136
+ }
137
+
138
+ // Validation standard
139
+ const result = validation.validateField(
140
+ value,
141
+ [...defaultRules.value, ...props.customRules],
142
+ props.customWarningRules,
143
+ )
144
+
145
+ return !result.hasError
146
+ }
147
+
148
+ const validateOnSubmit = () => {
149
+ return validateField(model.value)
150
+ }
151
+
152
+ const checkErrorOnBlur = () => {
153
+ validateField(model.value)
154
+ }
155
+
156
+ watch(model, (newValue) => {
157
+ if (!props.isValidateOnBlur) {
158
+ // Valider le champ et s'assurer que l'état d'erreur est correctement mis à jour
159
+ const isValid = validateField(newValue)
160
+
161
+ // Si la validation réussit, s'assurer que les erreurs sont effacées
162
+ if (isValid && validation.hasError.value) {
163
+ validation.clearValidation()
164
+ }
165
+ }
166
+ })
167
+
168
+ const hasError = computed(() => validation.hasError.value)
169
+ const hasWarning = computed(() => validation.hasWarning.value)
170
+ const hasSuccess = computed(() => validation.hasSuccess.value)
171
+
172
+ const errors = computed(() => validation.errors.value)
173
+ const warnings = computed(() => validation.warnings.value)
174
+ const successes = computed(() => validation.successes.value)
175
+
176
+ const ariaChecked = computed(() => {
177
+ if (internalIndeterminate.value) return 'mixed'
178
+ return model.value ? 'true' : 'false'
179
+ })
180
+
181
+ // Propriétés ARIA personnalisées pour éviter les conflits
182
+ const ariaAttributes = computed(() => {
183
+ return {
184
+ 'aria-checked': ariaChecked.value,
185
+ 'aria-controls': props.controlsIds.length > 0 ? props.controlsIds.join(' ') : undefined,
186
+ }
187
+ })
188
+
189
+ // Fonction pour supprimer l'attribut aria-disabled="false" des éléments input
190
+ const removeAriaDisabled = () => {
191
+ nextTick(() => {
192
+ // Sélectionner tous les inputs de type checkbox dans le composant
193
+ const checkboxInputs = document.querySelectorAll('input[type="checkbox"][aria-disabled="false"]')
194
+
195
+ // Supprimer l'attribut aria-disabled="false" de chaque input
196
+ checkboxInputs.forEach((input) => {
197
+ input.removeAttribute('aria-disabled')
198
+ })
199
+
200
+ // Configurer un MutationObserver pour surveiller les changements futurs
201
+ const observer = new MutationObserver((mutations) => {
202
+ mutations.forEach(() => {
203
+ const newCheckboxInputs = document.querySelectorAll('input[type="checkbox"][aria-disabled="false"]')
204
+ newCheckboxInputs.forEach((input) => {
205
+ input.removeAttribute('aria-disabled')
206
+ })
207
+ })
208
+ })
209
+
210
+ // Observer le document pour les changements
211
+ observer.observe(document.body, {
212
+ subtree: true,
213
+ childList: true,
214
+ attributes: true,
215
+ attributeFilter: ['aria-disabled'],
216
+ })
217
+ })
218
+ }
219
+
220
+ // Appliquer la correction lors du montage du composant
221
+ onMounted(() => {
222
+ removeAriaDisabled()
223
+ })
224
+
225
+ const toggleMixed = () => {
226
+ if (!props.readonly && !props.disabled) {
227
+ if (internalIndeterminate.value) {
228
+ // Désactiver l'état indéterminé
229
+ internalIndeterminate.value = false
230
+ emit('update:indeterminate', false)
231
+ // Émettre l'événement update:modelValue directement
232
+ emit('update:modelValue', true)
233
+ emit('change', true)
234
+ }
235
+ else if (model.value) {
236
+ // Émettre l'événement update:modelValue directement
237
+ emit('update:modelValue', false)
238
+ emit('change', false)
239
+ }
240
+ else {
241
+ if (props.controlsIds.length > 0) {
242
+ // Activer l'état indéterminé
243
+ internalIndeterminate.value = true
244
+ emit('update:indeterminate', true)
245
+ }
246
+ else {
247
+ // Émettre l'événement update:modelValue directement
248
+ emit('update:modelValue', true)
249
+ emit('change', true)
250
+ }
251
+ }
252
+ }
253
+ }
254
+
255
+ defineExpose({
256
+ validation,
257
+ validateOnSubmit,
258
+ checkErrorOnBlur,
259
+ toggleMixed,
260
+ })
261
+ </script>
262
+
263
+ <template>
264
+ <VCheckbox
265
+ :id="props.id"
266
+ v-model="model"
267
+ :name="props.name"
268
+ :label="props.label"
269
+ :color="props.color"
270
+ :disabled="props.disabled"
271
+ :readonly="props.readonly"
272
+ :hide-details="props.hideDetails"
273
+ :density="props.density"
274
+ :error="hasError"
275
+ :error-messages="errors"
276
+ :messages="hasError ? errors : (hasWarning ? warnings : (hasSuccess && props.showSuccessMessages ? successes : []))"
277
+ :indeterminate="internalIndeterminate"
278
+ :value="props.value"
279
+ :true-value="props.trueValue"
280
+ :false-value="props.falseValue"
281
+ v-bind="ariaAttributes"
282
+ @click="toggleMixed"
283
+ @blur="checkErrorOnBlur"
284
+ >
285
+ <template
286
+ v-if="$slots.label"
287
+ #label
288
+ >
289
+ <slot name="label" />
290
+ </template>
291
+ <template
292
+ v-if="$slots.default"
293
+ #default
294
+ >
295
+ <slot />
296
+ </template>
297
+ </VCheckbox>
298
+ </template>
299
+
300
+ <style scoped>
301
+ :deep(.v-selection-control--dirty .v-selection-control__input) {
302
+ color: v-bind('props.color');
303
+ }
304
+
305
+ :deep(.v-checkbox--indeterminate .v-selection-control__input) {
306
+ color: v-bind('props.color');
307
+ }
308
+
309
+ :deep(.v-checkbox--indeterminate .v-selection-control__input .v-selection-control__input-icon) {
310
+ transform: scale(0.8);
311
+ height: 16px;
312
+ width: 16px;
313
+ }
314
+
315
+ :deep(.v-selection-control__input) {
316
+ cursor: pointer;
317
+ }
318
+
319
+ :deep(.v-selection-control--disabled .v-selection-control__input) {
320
+ cursor: not-allowed;
321
+ }
322
+
323
+ :deep(.v-selection-control--error .v-selection-control__input) {
324
+ color: rgb(var(--v-theme-error));
325
+ }
326
+ </style>
@@ -0,0 +1,201 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, it, expect } from 'vitest'
3
+ import { nextTick } from 'vue'
4
+ import SyCheckbox from '../SyCheckbox.vue'
5
+ import { createVuetify } from 'vuetify'
6
+ import * as components from 'vuetify/components'
7
+ import * as directives from 'vuetify/directives'
8
+
9
+ describe('SyCheckbox', () => {
10
+ // Configuration de Vuetify pour les tests
11
+ const vuetify = createVuetify({
12
+ components,
13
+ directives,
14
+ })
15
+
16
+ const global = {
17
+ plugins: [vuetify],
18
+ }
19
+
20
+ it('should render correctly', () => {
21
+ const wrapper = mount(SyCheckbox, {
22
+ props: {
23
+ label: 'Test checkbox',
24
+ },
25
+ global,
26
+ })
27
+
28
+ expect(wrapper.find('.v-checkbox').exists()).toBe(true)
29
+ expect(wrapper.text()).toContain('Test checkbox')
30
+ })
31
+
32
+ it('should handle v-model correctly', async () => {
33
+ const wrapper = mount(SyCheckbox, {
34
+ props: {
35
+ 'modelValue': false,
36
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
37
+ },
38
+ global,
39
+ })
40
+
41
+ await wrapper.find('input[type="checkbox"]').setValue(true)
42
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true])
43
+ expect(wrapper.emitted('change')?.[0]).toEqual([true])
44
+ })
45
+
46
+ it('should handle indeterminate state correctly', async () => {
47
+ const wrapper = mount(SyCheckbox, {
48
+ props: {
49
+ 'modelValue': false,
50
+ 'indeterminate': true,
51
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
52
+ 'onUpdate:indeterminate': e => wrapper.setProps({ indeterminate: e }),
53
+ },
54
+ global,
55
+ })
56
+
57
+ // Vérifier que l'état indéterminé est actif
58
+ expect(wrapper.props('indeterminate')).toBe(true)
59
+
60
+ // Cliquer sur la case à cocher devrait changer l'état indéterminé à checked
61
+ await wrapper.find('.v-selection-control').trigger('click')
62
+ expect(wrapper.emitted('update:indeterminate')?.[0]).toEqual([false])
63
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true])
64
+ })
65
+
66
+ it('should toggle between states correctly', async () => {
67
+ // Monter le composant avec des handlers pour les événements
68
+ const wrapper = mount(SyCheckbox, {
69
+ props: {
70
+ modelValue: false,
71
+ controlsIds: ['child-1', 'child-2'],
72
+ },
73
+ global,
74
+ })
75
+
76
+ // État initial: non coché
77
+ expect(wrapper.props('modelValue')).toBe(false)
78
+
79
+ // Premier toggle: passe à indéterminé (car controlsIds est défini)
80
+ await wrapper.vm.toggleMixed()
81
+ await nextTick()
82
+
83
+ // Vérifier que l'événement update:indeterminate a été émis
84
+ const indeterminateEvents = wrapper.emitted('update:indeterminate')
85
+ expect(indeterminateEvents).toBeTruthy()
86
+ expect(indeterminateEvents && indeterminateEvents[0]).toEqual([true])
87
+
88
+ // Simuler la mise à jour des props par le parent
89
+ await wrapper.setProps({
90
+ indeterminate: true,
91
+ modelValue: false,
92
+ })
93
+
94
+ // Deuxième toggle: passe à coché
95
+ await wrapper.vm.toggleMixed()
96
+ await nextTick()
97
+
98
+ // Vérifier que les événements ont été émis
99
+ const updatedIndeterminateEvents = wrapper.emitted('update:indeterminate')
100
+ const modelValueEvents = wrapper.emitted('update:modelValue')
101
+ expect(updatedIndeterminateEvents && updatedIndeterminateEvents[1]).toEqual([false])
102
+ expect(modelValueEvents).toBeTruthy()
103
+ expect(modelValueEvents && modelValueEvents[0]).toEqual([true])
104
+
105
+ // Simuler la mise à jour des props par le parent
106
+ await wrapper.setProps({
107
+ indeterminate: false,
108
+ modelValue: true,
109
+ })
110
+
111
+ // Troisième toggle: passe à non coché
112
+ await wrapper.vm.toggleMixed()
113
+ await nextTick()
114
+
115
+ // Vérifier que l'événement update:modelValue a été émis avec false
116
+ const finalModelValueEvents = wrapper.emitted('update:modelValue')
117
+ expect(finalModelValueEvents && finalModelValueEvents[1]).toEqual([false])
118
+ })
119
+
120
+ it('should handle validation correctly', async () => {
121
+ const wrapper = mount(SyCheckbox, {
122
+ props: {
123
+ 'modelValue': false,
124
+ 'label': 'Required checkbox',
125
+ 'required': true,
126
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
127
+ },
128
+ global,
129
+ })
130
+
131
+ // Simuler un événement blur pour déclencher la validation
132
+ await wrapper.find('.v-checkbox').trigger('blur')
133
+
134
+ // Vérifier que le message d'erreur est affiché
135
+ expect(wrapper.find('.v-messages').exists()).toBe(true)
136
+ expect(wrapper.find('.v-messages').text()).toContain('Required checkbox est requis')
137
+ })
138
+
139
+ it('should handle custom validation rules', async () => {
140
+ // Créer une règle de validation au format attendu par le composant
141
+ const customRule = {
142
+ type: 'custom',
143
+ validator: (value: boolean) => value === true,
144
+ options: {
145
+ message: 'This checkbox must be checked',
146
+ fieldIdentifier: 'Custom checkbox',
147
+ },
148
+ }
149
+
150
+ // Monter le composant avec la règle de validation personnalisée
151
+ const wrapper = mount(SyCheckbox, {
152
+ props: {
153
+ 'modelValue': false,
154
+ 'customRules': [customRule],
155
+ 'isValidateOnBlur': false, // Valider immédiatement
156
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
157
+ },
158
+ global,
159
+ })
160
+
161
+ // Vérifier l'état initial
162
+ expect(wrapper.props('modelValue')).toBe(false)
163
+
164
+ // Simuler la validation du formulaire
165
+ const isValid = await wrapper.vm.validateOnSubmit()
166
+ await wrapper.vm.$nextTick()
167
+
168
+ // La validation devrait échouer car la case n'est pas cochée
169
+ expect(isValid).toBe(false)
170
+
171
+ // Cocher la case
172
+ await wrapper.setProps({ modelValue: true })
173
+
174
+ // Simuler à nouveau la validation du formulaire
175
+ const isValidAfterCheck = await wrapper.vm.validateOnSubmit()
176
+ await wrapper.vm.$nextTick()
177
+
178
+ // La validation devrait réussir maintenant
179
+ expect(isValidAfterCheck).toBe(true)
180
+ })
181
+
182
+ it('should handle readonly and disabled states', async () => {
183
+ const wrapper = mount(SyCheckbox, {
184
+ props: {
185
+ 'modelValue': false,
186
+ 'readonly': true,
187
+ 'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
188
+ },
189
+ global,
190
+ })
191
+
192
+ // Cliquer sur une case à cocher en lecture seule ne devrait pas changer sa valeur
193
+ await wrapper.find('.v-checkbox').trigger('click')
194
+ expect(wrapper.emitted('update:modelValue')).toBeFalsy()
195
+
196
+ // Tester l'état désactivé
197
+ await wrapper.setProps({ readonly: false, disabled: true })
198
+ await wrapper.find('.v-checkbox').trigger('click')
199
+ expect(wrapper.emitted('update:modelValue')).toBeFalsy()
200
+ })
201
+ })
@@ -22,6 +22,7 @@ const meta = {
22
22
  vuetifyOptions: { control: 'object' },
23
23
  displayAsterisk: { control: 'boolean' },
24
24
  readonly: { control: 'boolean' },
25
+ bgColor: { control: 'color' },
25
26
  },
26
27
  } as Meta<typeof SyInputSelect>
27
28
 
@@ -20,6 +20,7 @@
20
20
  clearable?: boolean
21
21
  customRules?: ValidationRule[]
22
22
  disableErrorHandling?: boolean
23
+ bgColor?: string
23
24
  }>(), {
24
25
 
25
26
  modelValue: null,
@@ -36,6 +37,7 @@
36
37
  clearable: false,
37
38
  customRules: () => [],
38
39
  disableErrorHandling: false,
40
+ bgColor: 'white',
39
41
  })
40
42
 
41
43
  const options = useCustomizableOptions(defaultOptions, props)
@@ -241,7 +243,8 @@
241
243
  'sy-input-select',
242
244
  buttonClass,
243
245
  hasError ? 'text-error' : 'text-'+options.menu.color,
244
- hasError ? 'error--text' : ''
246
+ hasError ? 'error--text' : '',
247
+ bgColor ? 'bg-color' : '',
245
248
  ]"
246
249
  role="menu"
247
250
  tabindex="0"
@@ -323,6 +326,10 @@
323
326
  max-height: 300px;
324
327
  }
325
328
 
329
+ .bg-color {
330
+ background-color: v-bind(bgColor);
331
+ }
332
+
326
333
  .v-list-item:hover {
327
334
  background-color: rgb(0 0 0 / 4%);
328
335
  }