@cnamts/synapse 1.0.20 → 1.0.21
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.
- package/dist/{DateFilter-XURUmpMl.js → DateFilter-uN8OURoP.js} +1 -1
- package/dist/{NumberFilter-BZc0O8wV.js → NumberFilter-sm1dQNQi.js} +1 -1
- package/dist/{PeriodFilter-ZNdXcl3p.js → PeriodFilter-Cklsxnh9.js} +1 -1
- package/dist/{SelectFilter-DshYU5OK.js → SelectFilter-CWefj27Z.js} +1 -1
- package/dist/{TextFilter-D_c5dRPl.js → TextFilter-Ddyj885L.js} +1 -1
- package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +160 -0
- package/dist/components/Customs/SyCheckBoxGroup/locales.d.ts +3 -0
- package/dist/components/Customs/SyCheckBoxGroup/types.d.ts +10 -0
- package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +1545 -2
- package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +1495 -2
- package/dist/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.d.ts +60 -0
- package/dist/components/ErrorPage/ErrorPage.d.ts +1 -12
- package/dist/components/ErrorPage/locales.d.ts +18 -3
- package/dist/components/FileUpload/FileUpload.d.ts +2 -0
- package/dist/components/MaintenancePage/locales.d.ts +18 -2
- package/dist/components/NotFoundPage/locales.d.ts +20 -4
- package/dist/components/StatusPage/StatusPage.d.ts +39 -0
- package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +13 -3
- package/dist/components/index.d.ts +3 -0
- package/dist/design-system-v3.js +126 -123
- package/dist/design-system-v3.umd.cjs +163 -163
- package/dist/{main-CuI6xaPq.js → main-CWniLr0s.js} +15191 -14668
- package/dist/style.css +1 -1
- package/dist/utils/theme/index.d.ts +6 -0
- package/package.json +7 -4
- package/src/components/ContextualMenu/ContextualMenu.stories.ts +0 -3
- package/src/components/ContextualMenu/accessibilite/Accessibility.mdx +67 -11
- package/src/components/CookieBanner/CookieBanner.stories.ts +11 -20
- package/src/components/CookieBanner/CookieBanner.vue +20 -5
- package/src/components/CookieBanner/accessibilite/Accessibility.mdx +67 -11
- package/src/components/CookieBanner/tests/CookieBanner.spec.ts +48 -4
- package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.mdx +32 -0
- package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.stories.ts +856 -0
- package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +334 -0
- package/src/components/Customs/SyCheckBoxGroup/accessibilite/Accessibility.mdx +243 -0
- package/src/components/Customs/SyCheckBoxGroup/locales.ts +3 -0
- package/src/components/Customs/SyCheckBoxGroup/tests/SyCheckBoxGroup.a11y.spec.ts +30 -0
- package/src/components/Customs/SyCheckBoxGroup/tests/SyCheckBoxGroup.spec.ts +152 -0
- package/src/components/Customs/SyCheckBoxGroup/types.ts +10 -0
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +16 -27
- package/src/components/Customs/SyCheckbox/accessibilite/Accessibility.mdx +1 -1
- package/src/components/Customs/SyForm/SyForm.a11y.spec.ts +1 -1
- package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +16 -43
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +35 -11
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +43 -2
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +48 -21
- package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +98 -0
- package/src/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.mdx +83 -0
- package/src/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.stories.ts +502 -0
- package/src/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.vue +428 -0
- package/src/components/DeclarationAccessibilityPage/accessibilite/Accessibility.mdx +75 -0
- package/src/components/DeclarationAccessibilityPage/tests/DeclarationAccessibilityPage.a11y.spec.ts +53 -0
- package/src/components/DeclarationAccessibilityPage/tests/DeclarationAccessibilityPage.spec.ts +59 -0
- package/src/components/DiacriticPicker/DiacriticPicker.vue +20 -1
- package/src/components/ErrorPage/ErrorPage.mdx +6 -16
- package/src/components/ErrorPage/ErrorPage.stories.ts +16 -87
- package/src/components/ErrorPage/ErrorPage.vue +38 -125
- package/src/components/ErrorPage/accessibilite/Accessibility.mdx +68 -6
- package/src/components/ErrorPage/assets/error-ap.svg +1774 -0
- package/src/components/ErrorPage/locales.ts +21 -3
- package/src/components/ErrorPage/tests/ErrorPage.a11y.spec.ts +5 -13
- package/src/components/ErrorPage/tests/ErrorPage.spec.ts +2 -41
- package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +8 -266
- package/src/components/FileUpload/FileUpload.vue +5 -0
- package/src/components/FooterBar/FooterBar.stories.ts +18 -14
- package/src/components/FooterBar/defaultSocialMediaLinks.ts +6 -4
- package/src/components/MaintenancePage/MaintenancePage.mdx +1 -1
- package/src/components/MaintenancePage/MaintenancePage.vue +15 -7
- package/src/components/MaintenancePage/accessibilite/Accessibility.mdx +61 -6
- package/src/components/MaintenancePage/assets/maintenance-ap.svg +1718 -0
- package/src/components/MaintenancePage/locales.ts +24 -3
- package/src/components/MaintenancePage/tests/MaintenancePage.a11y.spec.ts +75 -3
- package/src/components/MaintenancePage/tests/MaintenancePage.spec.ts +42 -2
- package/src/components/MaintenancePage/tests/__snapshots__/MaintenancePage.spec.ts.snap +3 -2
- package/src/components/NotFoundPage/NotFoundPage.mdx +1 -1
- package/src/components/NotFoundPage/NotFoundPage.stories.ts +3 -3
- package/src/components/NotFoundPage/NotFoundPage.vue +16 -11
- package/src/components/NotFoundPage/accessibilite/Accessibility.mdx +78 -6
- package/src/components/NotFoundPage/assets/not-found-ap.svg +2061 -0
- package/src/components/NotFoundPage/locales.ts +24 -4
- package/src/components/NotFoundPage/tests/NotFoundPage.a11y.spec.ts +168 -4
- package/src/components/NotFoundPage/tests/NotFoundPage.spec.ts +100 -12
- package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +2 -2
- package/src/components/NotificationBar/NotificationBar.mdx +2 -2
- package/src/components/NotificationBar/accessibilite/Accessibility.mdx +68 -8
- package/src/components/PageContainer/tests/PageContainer.a11y.spec.ts +14 -7
- package/src/components/PhoneField/PhoneField.stories.ts +46 -38
- package/src/components/SocialMediaLinks/DefaultSocialMediaLinks.ts +6 -4
- package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +7 -5
- package/src/components/SocialMediaLinks/SocialMediaLinks.stories.ts +17 -13
- package/src/components/SocialMediaLinks/SocialMediaLinks.vue +9 -1
- package/src/components/SocialMediaLinks/accessibilite/Accessibility.mdx +63 -11
- package/src/components/SocialMediaLinks/tests/DefaultSocialMediaLinks.spec.ts +5 -5
- package/src/components/SocialMediaLinks/tests/SocialMediaLinks.a11y.spec.ts +59 -0
- package/src/components/SocialMediaLinks/tests/SocialMediaLinks.spec.ts +9 -7
- package/src/components/StatusPage/StatusPage.mdx +22 -0
- package/src/components/StatusPage/StatusPage.stories.ts +193 -0
- package/src/components/StatusPage/StatusPage.vue +145 -0
- package/src/components/StatusPage/accessibilite/Accessibility.mdx +81 -0
- package/src/components/StatusPage/tests/StatusPage.a11y.spec.ts +29 -0
- package/src/components/StatusPage/tests/StatusPage.spec.ts +50 -0
- package/src/components/StatusPage/tests/__snapshots__/StatusPage.spec.ts.snap +270 -0
- package/src/components/TableToolbar/TableToolbar.stories.ts +6 -6
- package/src/components/TableToolbar/TableToolbar.vue +1 -1
- package/src/components/TableToolbar/tests/__snapshots__/TableToolbar.spec.ts.snap +0 -5
- package/src/components/UploadWorkflow/UploadWorkflow.mdx +11 -1
- package/src/components/UploadWorkflow/UploadWorkflow.stories.ts +107 -3
- package/src/components/UploadWorkflow/UploadWorkflow.vue +35 -24
- package/src/components/UploadWorkflow/tests/UploadWorkflow.spec.ts +48 -0
- package/src/components/UploadWorkflow/tests/__snapshots__/UploadWorkflow.spec.ts.snap +9 -5
- package/src/components/UploadWorkflow/useFileList.ts +7 -0
- package/src/components/index.ts +3 -0
- package/src/composables/rules/tests/useFieldValidation.spec.ts +39 -3
- package/src/composables/rules/useFieldValidation.ts +24 -9
- package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +7 -0
- package/src/utils/theme/index.ts +19 -0
- package/src/utils/theme/tests/useThemeLocales.spec.ts +245 -0
- package/dist/components/MaintenancePage/index.d.ts +0 -2
- package/src/components/Customs/SyPagination/tests/SyPagination.a11y.spec.ts +0 -27
- package/src/components/Customs/SyTabs/tests/SyTabs.a11y.spec.ts +0 -51
- package/src/components/DataListItem/tests/DataListItem.a11y.spec.ts +0 -31
- package/src/components/DatePicker/CalendarMode/tests/DatePicker.a11y.spec.ts +0 -27
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.a11y.spec.ts +0 -26
- package/src/components/DatePicker/DateTextInput/tests/DateTextInput.a11y.spec.ts +0 -27
- package/src/components/DownloadBtn/tests/DownloadBtn.a11y.spec.ts +0 -26
- package/src/components/ExternalLinks/tests/ExternalLinks.a11y.spec.ts +0 -39
- package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.a11y.spec.ts +0 -45
- package/src/components/HeaderToolbar/tests/HeaderToolbar.a11y.spec.ts +0 -25
- package/src/components/LunarCalendar/tests/LunarCalendar.a11y.spec.ts +0 -31
- package/src/components/MaintenancePage/index.ts +0 -3
- package/src/components/PageContainer/Accessibilite/AccessibilityGuide.mdx +0 -0
- package/src/components/PaginatedTable/tests/PaginatedTable.a11y.spec.ts +0 -43
- package/src/components/PhoneField/tests/PhoneField.a11y.spec.ts +0 -34
- /package/src/components/NotFoundPage/assets/{not-found.svg → not-found-cnam.svg} +0 -0
- /package/src/components/PageContainer/{Accessibilite → accessibilite}/Accessibility.mdx +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import SyCheckBoxGroup from '../SyCheckBoxGroup.vue'
|
|
2
|
+
import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue'
|
|
3
|
+
import { mount } from '@vue/test-utils'
|
|
4
|
+
import { describe, it, expect } from 'vitest'
|
|
5
|
+
import { nextTick } from 'vue'
|
|
6
|
+
|
|
7
|
+
describe('SyCheckBoxGroup', () => {
|
|
8
|
+
it('should render correctly', () => {
|
|
9
|
+
const wrapper = mount(SyCheckBoxGroup, {
|
|
10
|
+
props: {
|
|
11
|
+
label: 'Test checkbox group',
|
|
12
|
+
options: [
|
|
13
|
+
{ label: 'A', value: 'A', id: 'opt-a' },
|
|
14
|
+
{ label: 'B', value: 'B', id: 'opt-b' },
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
expect(wrapper.find('.sy-checkbox-group').exists()).toBe(true)
|
|
20
|
+
expect(wrapper.text()).toContain('Test checkbox group')
|
|
21
|
+
expect(wrapper.findAll('input[type="checkbox"]').length).toBe(2)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should handle v-model correctly (single)', async () => {
|
|
25
|
+
const wrapper = mount(SyCheckBoxGroup, {
|
|
26
|
+
props: {
|
|
27
|
+
'modelValue': null,
|
|
28
|
+
'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
|
|
29
|
+
'options': [
|
|
30
|
+
{ label: 'Option A', value: 'A', id: 'opt-a' },
|
|
31
|
+
{ label: 'Option B', value: 'B', id: 'opt-b' },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const checkboxes = wrapper.findAllComponents(SyCheckbox)
|
|
37
|
+
expect(checkboxes.length).toBe(2)
|
|
38
|
+
|
|
39
|
+
await checkboxes[0]?.find('input').setValue(true)
|
|
40
|
+
|
|
41
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['A'])
|
|
42
|
+
expect(wrapper.emitted('change')?.[0]).toEqual(['A'])
|
|
43
|
+
|
|
44
|
+
// Uncheck
|
|
45
|
+
await checkboxes[0]?.find('input').setValue(false)
|
|
46
|
+
expect(wrapper.emitted('update:modelValue')?.[1]).toEqual([null])
|
|
47
|
+
expect(wrapper.emitted('change')?.[1]).toEqual([null])
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should handle v-model correctly (multiple)', async () => {
|
|
51
|
+
const wrapper = mount(SyCheckBoxGroup, {
|
|
52
|
+
props: {
|
|
53
|
+
'multiple': true,
|
|
54
|
+
'modelValue': [],
|
|
55
|
+
'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
|
|
56
|
+
'options': [
|
|
57
|
+
{ label: 'Option A', value: 'A', id: 'opt-a' },
|
|
58
|
+
{ label: 'Option B', value: 'B', id: 'opt-b' },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const checkboxes = wrapper.findAllComponents(SyCheckbox)
|
|
64
|
+
expect(checkboxes.length).toBe(2)
|
|
65
|
+
|
|
66
|
+
await checkboxes[0]?.find('input').setValue(true)
|
|
67
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([['A']])
|
|
68
|
+
|
|
69
|
+
await checkboxes[1]?.find('input').setValue(true)
|
|
70
|
+
expect(wrapper.emitted('update:modelValue')?.[1]).toEqual([['A', 'B']])
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should handle validation correctly (required)', async () => {
|
|
74
|
+
const wrapper = mount(SyCheckBoxGroup, {
|
|
75
|
+
props: {
|
|
76
|
+
'modelValue': null,
|
|
77
|
+
'label': 'Required CheckBoxGroup',
|
|
78
|
+
'required': true,
|
|
79
|
+
'isValidateOnBlur': false,
|
|
80
|
+
'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
|
|
81
|
+
'options': [{ label: 'X', value: 'X', id: 'opt-x' }],
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
await wrapper.vm.validateOnSubmit()
|
|
86
|
+
await nextTick()
|
|
87
|
+
expect(wrapper.vm.validation.hasError.value).toBe(true)
|
|
88
|
+
expect(wrapper.vm.validation.errors.value[0]).toContain('est requis')
|
|
89
|
+
|
|
90
|
+
await wrapper.find('input').setValue(true)
|
|
91
|
+
|
|
92
|
+
await wrapper.vm.validateOnSubmit()
|
|
93
|
+
await nextTick()
|
|
94
|
+
|
|
95
|
+
expect(wrapper.vm.validation.hasError.value).toBe(false)
|
|
96
|
+
expect(wrapper.props('modelValue')).toBe('X')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should handle readonly and disabled states', async () => {
|
|
100
|
+
const wrapper = mount(SyCheckBoxGroup, {
|
|
101
|
+
props: {
|
|
102
|
+
modelValue: null,
|
|
103
|
+
readonly: true,
|
|
104
|
+
options: [{ label: 'X', value: 'X', id: 'opt-x' }],
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
wrapper.findComponent(SyCheckbox).vm.$emit('update:modelValue', true)
|
|
109
|
+
await nextTick()
|
|
110
|
+
expect(wrapper.emitted('update:modelValue')).toBeFalsy()
|
|
111
|
+
|
|
112
|
+
await wrapper.setProps({ readonly: false, disabled: true })
|
|
113
|
+
wrapper.findComponent(SyCheckbox).vm.$emit('update:modelValue', true)
|
|
114
|
+
await nextTick()
|
|
115
|
+
expect(wrapper.emitted('update:modelValue')).toBeFalsy()
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('should handle custom validation rules', async () => {
|
|
119
|
+
const customRule = {
|
|
120
|
+
type: 'custom',
|
|
121
|
+
options: {
|
|
122
|
+
validate: (value: unknown) => value === 'OK',
|
|
123
|
+
message: 'Vous devez sélectionner une option.',
|
|
124
|
+
fieldIdentifier: 'Custom CheckBoxGroup',
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const wrapper = mount(SyCheckBoxGroup, {
|
|
129
|
+
props: {
|
|
130
|
+
'modelValue': null,
|
|
131
|
+
'required': true,
|
|
132
|
+
'customRules': [customRule],
|
|
133
|
+
'isValidateOnBlur': false,
|
|
134
|
+
'options': [
|
|
135
|
+
{ label: 'Non', value: 'NO', id: 'opt-no' },
|
|
136
|
+
{ label: 'Oui', value: 'OK', id: 'opt-ok' },
|
|
137
|
+
],
|
|
138
|
+
'onUpdate:modelValue': e => wrapper.setProps({ modelValue: e }),
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
const isValidInitial = await wrapper.vm.validateOnSubmit()
|
|
143
|
+
expect(isValidInitial).toBe(false)
|
|
144
|
+
expect(wrapper.vm.validation.errors.value).toContain('Vous devez sélectionner une option.')
|
|
145
|
+
|
|
146
|
+
await wrapper.setProps({ modelValue: 'OK' })
|
|
147
|
+
|
|
148
|
+
const isValidCorrect = await wrapper.vm.validateOnSubmit()
|
|
149
|
+
expect(isValidCorrect).toBe(true)
|
|
150
|
+
expect(wrapper.vm.validation.errors.value).toHaveLength(0)
|
|
151
|
+
})
|
|
152
|
+
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computed, ref, watch, onMounted, nextTick } from 'vue'
|
|
2
|
+
import { computed, ref, watch, onMounted, onUpdated, nextTick } from 'vue'
|
|
3
|
+
import type { VCheckbox } from 'vuetify/components'
|
|
3
4
|
import { useValidation, type ValidationRule } from '@/composables/validation/useValidation'
|
|
4
5
|
import { useValidatable } from '@/composables/validation/useValidatable'
|
|
5
6
|
import { locales } from './locales'
|
|
@@ -70,6 +71,8 @@
|
|
|
70
71
|
|
|
71
72
|
const emit = defineEmits(['update:modelValue', 'update:indeterminate', 'change'])
|
|
72
73
|
|
|
74
|
+
const checkboxRef = ref<VCheckbox | null>(null)
|
|
75
|
+
|
|
73
76
|
const internalIndeterminate = ref(props.indeterminate)
|
|
74
77
|
|
|
75
78
|
const generatedLabel = computed(() => {
|
|
@@ -239,39 +242,24 @@
|
|
|
239
242
|
// Fonction pour supprimer les attributs ARIA non désirés des éléments input
|
|
240
243
|
const removeAriaAttributes = () => {
|
|
241
244
|
nextTick(() => {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Configurer un MutationObserver pour surveiller les changements futurs
|
|
250
|
-
const observer = new MutationObserver((mutations) => {
|
|
251
|
-
mutations.forEach(() => {
|
|
252
|
-
// Pour aria-disabled
|
|
253
|
-
const newCheckboxInputsDisabled = document.querySelectorAll('input[type="checkbox"][aria-disabled="false"]')
|
|
254
|
-
newCheckboxInputsDisabled.forEach((input) => {
|
|
255
|
-
input.removeAttribute('aria-disabled')
|
|
256
|
-
})
|
|
257
|
-
})
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
// Observer le document pour les changements
|
|
261
|
-
observer.observe(document.body, {
|
|
262
|
-
subtree: true,
|
|
263
|
-
childList: true,
|
|
264
|
-
attributes: true,
|
|
265
|
-
attributeFilter: ['aria-disabled'],
|
|
266
|
-
})
|
|
245
|
+
if (checkboxRef.value) {
|
|
246
|
+
const checkboxInput = checkboxRef.value.$el.querySelector('input[type="checkbox"][aria-disabled="false"]')
|
|
247
|
+
if (checkboxInput) {
|
|
248
|
+
checkboxInput.removeAttribute('aria-disabled')
|
|
249
|
+
}
|
|
250
|
+
}
|
|
267
251
|
})
|
|
268
252
|
}
|
|
269
253
|
|
|
270
|
-
// Appliquer la correction lors du montage du composant
|
|
254
|
+
// Appliquer la correction lors du montage et de la mise à jour du composant
|
|
271
255
|
onMounted(() => {
|
|
272
256
|
removeAriaAttributes()
|
|
273
257
|
})
|
|
274
258
|
|
|
259
|
+
onUpdated(() => {
|
|
260
|
+
removeAriaAttributes()
|
|
261
|
+
})
|
|
262
|
+
|
|
275
263
|
// Intégration avec le système de validation du formulaire
|
|
276
264
|
useValidatable(validateOnSubmit)
|
|
277
265
|
|
|
@@ -317,6 +305,7 @@
|
|
|
317
305
|
<div>
|
|
318
306
|
<VCheckbox
|
|
319
307
|
:id="props.id"
|
|
308
|
+
ref="checkboxRef"
|
|
320
309
|
v-model="model"
|
|
321
310
|
:name="props.name"
|
|
322
311
|
:label="generatedLabel"
|
|
@@ -3,7 +3,7 @@ import * as SyCheckboxStories from '../SyCheckbox.stories';
|
|
|
3
3
|
import AccessibilityIcon from '@/common/imgs/accessibility-svgrepo-com.svg';
|
|
4
4
|
import '@/stories/styles/shared.css';
|
|
5
5
|
|
|
6
|
-
<Meta of={SyCheckboxStories} />
|
|
6
|
+
<Meta of={SyCheckboxStories} name="Accessibility" />
|
|
7
7
|
|
|
8
8
|
<div className="accessibility-guide">
|
|
9
9
|
<div className="header">
|
|
@@ -4,7 +4,7 @@ import { describe, it } from 'vitest'
|
|
|
4
4
|
import { mount } from '@vue/test-utils'
|
|
5
5
|
import { axe } from 'vitest-axe'
|
|
6
6
|
import { assertNoA11yViolations } from '@tests/unit/accessibility/axeUtils'
|
|
7
|
-
import SyForm from '
|
|
7
|
+
import SyForm from './SyForm.vue'
|
|
8
8
|
|
|
9
9
|
// Scénario d’accessibilité : formulaire contenant un champ et un bouton de soumission.
|
|
10
10
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
|
|
3
|
-
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
|
3
|
+
import { computed, nextTick, onMounted, onUpdated, ref, watch } from 'vue'
|
|
4
|
+
import type { VRadioGroup } from 'vuetify/components'
|
|
4
5
|
import { useValidation, type ValidationRule } from '@/composables/validation/useValidation'
|
|
5
6
|
import { useValidatable } from '@/composables/validation/useValidatable'
|
|
6
7
|
import { locales } from './locales'
|
|
@@ -61,6 +62,7 @@
|
|
|
61
62
|
)
|
|
62
63
|
|
|
63
64
|
const emit = defineEmits(['update:modelValue', 'change'])
|
|
65
|
+
const radioGroupRef = ref<VRadioGroup | null>(null)
|
|
64
66
|
const model = computed({
|
|
65
67
|
get() {
|
|
66
68
|
return props.modelValue
|
|
@@ -139,24 +141,10 @@
|
|
|
139
141
|
|
|
140
142
|
watch(model, (newValue) => {
|
|
141
143
|
if (!props.isValidateOnBlur) {
|
|
142
|
-
|
|
143
|
-
if (isSubmitted.value) {
|
|
144
|
-
const isValid = validateField(newValue)
|
|
145
|
-
if (isValid) {
|
|
146
|
-
// La validation a réussi, effacer les erreurs
|
|
147
|
-
validation.clearValidation()
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
// Comportement normal (hors soumission)
|
|
152
|
-
const isValid = validateField(newValue)
|
|
153
|
-
// Si la validation réussit, s'assurer que les erreurs sont effacées
|
|
154
|
-
if (isValid && validation.hasError.value) {
|
|
155
|
-
validation.clearValidation()
|
|
156
|
-
}
|
|
157
|
-
}
|
|
144
|
+
validateField(newValue)
|
|
158
145
|
}
|
|
159
146
|
})
|
|
147
|
+
|
|
160
148
|
const hasError = computed(() => validation.hasError.value)
|
|
161
149
|
const hasWarning = computed(() => validation.hasWarning.value)
|
|
162
150
|
const hasSuccess = computed(() => validation.hasSuccess.value)
|
|
@@ -184,36 +172,16 @@
|
|
|
184
172
|
|
|
185
173
|
const removeAriaAttributesForRadio = () => {
|
|
186
174
|
nextTick(() => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
radioInputsDisabled.forEach((input) => {
|
|
192
|
-
input.removeAttribute('aria-disabled')
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
// Observer les futurs changements
|
|
196
|
-
const observer = new MutationObserver((mutations) => {
|
|
197
|
-
mutations.forEach(() => {
|
|
198
|
-
const newRadioInputsDisabled = document.querySelectorAll(
|
|
199
|
-
'input[type="radio"][aria-disabled="false"]',
|
|
200
|
-
)
|
|
201
|
-
newRadioInputsDisabled.forEach((input) => {
|
|
202
|
-
input.removeAttribute('aria-disabled')
|
|
203
|
-
})
|
|
175
|
+
if (radioGroupRef.value) {
|
|
176
|
+
const radioInputs = radioGroupRef.value.$el.querySelectorAll('input[type="radio"][aria-disabled="false"]')
|
|
177
|
+
radioInputs.forEach((input: Element) => {
|
|
178
|
+
input.removeAttribute('aria-disabled')
|
|
204
179
|
})
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
observer.observe(document.body, {
|
|
208
|
-
subtree: true,
|
|
209
|
-
childList: true,
|
|
210
|
-
attributes: true,
|
|
211
|
-
attributeFilter: ['aria-disabled'],
|
|
212
|
-
})
|
|
180
|
+
}
|
|
213
181
|
})
|
|
214
182
|
}
|
|
215
183
|
|
|
216
|
-
// Appliquer la correction lors du montage du composant
|
|
184
|
+
// Appliquer la correction lors du montage et de la mise à jour du composant
|
|
217
185
|
onMounted(() => {
|
|
218
186
|
removeAriaAttributesForRadio()
|
|
219
187
|
if (!props.isValidateOnBlur && !props.required) {
|
|
@@ -221,6 +189,10 @@
|
|
|
221
189
|
}
|
|
222
190
|
})
|
|
223
191
|
|
|
192
|
+
onUpdated(() => {
|
|
193
|
+
removeAriaAttributesForRadio()
|
|
194
|
+
})
|
|
195
|
+
|
|
224
196
|
// Intégration avec le système de validation du formulaire
|
|
225
197
|
useValidatable(validateOnSubmit)
|
|
226
198
|
|
|
@@ -235,6 +207,7 @@
|
|
|
235
207
|
<template>
|
|
236
208
|
<v-radio-group
|
|
237
209
|
:id="props.id"
|
|
210
|
+
ref="radioGroupRef"
|
|
238
211
|
v-model="model"
|
|
239
212
|
:class="{
|
|
240
213
|
'warning-field': hasWarning && !hasError,
|
|
@@ -188,16 +188,39 @@
|
|
|
188
188
|
warningRules: props.customWarningRules,
|
|
189
189
|
disableErrorHandling: props.disableErrorHandling,
|
|
190
190
|
})
|
|
191
|
-
const { errors, warnings, successes, validateField, clearValidation } =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
191
|
+
const { errors, warnings, successes, validateField: baseValidateField, clearValidation: baseClearValidation } = validation
|
|
192
|
+
|
|
193
|
+
const clearValidation = () => baseClearValidation()
|
|
194
|
+
|
|
195
|
+
watch(() => props.readonly, () => {
|
|
196
|
+
// When toggling readonly, reset validation state to avoid stale success/errors
|
|
197
|
+
errors.value = []
|
|
198
|
+
warnings.value = []
|
|
199
|
+
successes.value = []
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
const validateField = (
|
|
203
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- compat signature with useDateValidation
|
|
204
|
+
value: any,
|
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- compat signature with useDateValidation
|
|
206
|
+
rules: any[] = [],
|
|
207
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- compat signature with useDateValidation
|
|
208
|
+
warningRules: any[] = [],
|
|
209
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- compat signature with useDateValidation
|
|
210
|
+
successRules: any[] = [],
|
|
211
|
+
): ValidationResult => {
|
|
212
|
+
if (props.readonly) {
|
|
213
|
+
return {
|
|
214
|
+
hasError: false,
|
|
215
|
+
hasWarning: false,
|
|
216
|
+
hasSuccess: false,
|
|
217
|
+
state: { errors: [], warnings: [], successes: [] },
|
|
218
|
+
}
|
|
199
219
|
}
|
|
200
220
|
|
|
221
|
+
return baseValidateField(value, rules, warningRules, successRules) as ValidationResult
|
|
222
|
+
}
|
|
223
|
+
|
|
201
224
|
const validateFieldForDateValidation = (
|
|
202
225
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- compat signature with useDateValidation
|
|
203
226
|
value: any,
|
|
@@ -580,10 +603,11 @@
|
|
|
580
603
|
}
|
|
581
604
|
|
|
582
605
|
// Valider les dates au montage, mais sans afficher d'erreur pour le required
|
|
583
|
-
// Forcer la validation si il y a des
|
|
584
|
-
const
|
|
606
|
+
// Forcer la validation si il y a des règles (erreur ou warning) et que le champ est rempli
|
|
607
|
+
const hasValidationRules = (props.customRules && props.customRules.length > 0)
|
|
608
|
+
|| (props.customWarningRules && props.customWarningRules.length > 0)
|
|
585
609
|
const hasValue = selectedDates.value !== null && selectedDates.value !== undefined
|
|
586
|
-
validateDates(
|
|
610
|
+
validateDates(hasValidationRules && hasValue)
|
|
587
611
|
|
|
588
612
|
// Après la validation initiale, désactiver le flag
|
|
589
613
|
nextTick(() => {
|