@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.
Files changed (135) hide show
  1. package/dist/{DateFilter-XURUmpMl.js → DateFilter-uN8OURoP.js} +1 -1
  2. package/dist/{NumberFilter-BZc0O8wV.js → NumberFilter-sm1dQNQi.js} +1 -1
  3. package/dist/{PeriodFilter-ZNdXcl3p.js → PeriodFilter-Cklsxnh9.js} +1 -1
  4. package/dist/{SelectFilter-DshYU5OK.js → SelectFilter-CWefj27Z.js} +1 -1
  5. package/dist/{TextFilter-D_c5dRPl.js → TextFilter-Ddyj885L.js} +1 -1
  6. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +160 -0
  7. package/dist/components/Customs/SyCheckBoxGroup/locales.d.ts +3 -0
  8. package/dist/components/Customs/SyCheckBoxGroup/types.d.ts +10 -0
  9. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +1545 -2
  10. package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +1495 -2
  11. package/dist/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.d.ts +60 -0
  12. package/dist/components/ErrorPage/ErrorPage.d.ts +1 -12
  13. package/dist/components/ErrorPage/locales.d.ts +18 -3
  14. package/dist/components/FileUpload/FileUpload.d.ts +2 -0
  15. package/dist/components/MaintenancePage/locales.d.ts +18 -2
  16. package/dist/components/NotFoundPage/locales.d.ts +20 -4
  17. package/dist/components/StatusPage/StatusPage.d.ts +39 -0
  18. package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +13 -3
  19. package/dist/components/index.d.ts +3 -0
  20. package/dist/design-system-v3.js +126 -123
  21. package/dist/design-system-v3.umd.cjs +163 -163
  22. package/dist/{main-CuI6xaPq.js → main-CWniLr0s.js} +15191 -14668
  23. package/dist/style.css +1 -1
  24. package/dist/utils/theme/index.d.ts +6 -0
  25. package/package.json +7 -4
  26. package/src/components/ContextualMenu/ContextualMenu.stories.ts +0 -3
  27. package/src/components/ContextualMenu/accessibilite/Accessibility.mdx +67 -11
  28. package/src/components/CookieBanner/CookieBanner.stories.ts +11 -20
  29. package/src/components/CookieBanner/CookieBanner.vue +20 -5
  30. package/src/components/CookieBanner/accessibilite/Accessibility.mdx +67 -11
  31. package/src/components/CookieBanner/tests/CookieBanner.spec.ts +48 -4
  32. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.mdx +32 -0
  33. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.stories.ts +856 -0
  34. package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +334 -0
  35. package/src/components/Customs/SyCheckBoxGroup/accessibilite/Accessibility.mdx +243 -0
  36. package/src/components/Customs/SyCheckBoxGroup/locales.ts +3 -0
  37. package/src/components/Customs/SyCheckBoxGroup/tests/SyCheckBoxGroup.a11y.spec.ts +30 -0
  38. package/src/components/Customs/SyCheckBoxGroup/tests/SyCheckBoxGroup.spec.ts +152 -0
  39. package/src/components/Customs/SyCheckBoxGroup/types.ts +10 -0
  40. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +16 -27
  41. package/src/components/Customs/SyCheckbox/accessibilite/Accessibility.mdx +1 -1
  42. package/src/components/Customs/SyForm/SyForm.a11y.spec.ts +1 -1
  43. package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +16 -43
  44. package/src/components/DatePicker/CalendarMode/DatePicker.vue +35 -11
  45. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +43 -2
  46. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +48 -21
  47. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +98 -0
  48. package/src/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.mdx +83 -0
  49. package/src/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.stories.ts +502 -0
  50. package/src/components/DeclarationAccessibilityPage/DeclarationAccessibilityPage.vue +428 -0
  51. package/src/components/DeclarationAccessibilityPage/accessibilite/Accessibility.mdx +75 -0
  52. package/src/components/DeclarationAccessibilityPage/tests/DeclarationAccessibilityPage.a11y.spec.ts +53 -0
  53. package/src/components/DeclarationAccessibilityPage/tests/DeclarationAccessibilityPage.spec.ts +59 -0
  54. package/src/components/DiacriticPicker/DiacriticPicker.vue +20 -1
  55. package/src/components/ErrorPage/ErrorPage.mdx +6 -16
  56. package/src/components/ErrorPage/ErrorPage.stories.ts +16 -87
  57. package/src/components/ErrorPage/ErrorPage.vue +38 -125
  58. package/src/components/ErrorPage/accessibilite/Accessibility.mdx +68 -6
  59. package/src/components/ErrorPage/assets/error-ap.svg +1774 -0
  60. package/src/components/ErrorPage/locales.ts +21 -3
  61. package/src/components/ErrorPage/tests/ErrorPage.a11y.spec.ts +5 -13
  62. package/src/components/ErrorPage/tests/ErrorPage.spec.ts +2 -41
  63. package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +8 -266
  64. package/src/components/FileUpload/FileUpload.vue +5 -0
  65. package/src/components/FooterBar/FooterBar.stories.ts +18 -14
  66. package/src/components/FooterBar/defaultSocialMediaLinks.ts +6 -4
  67. package/src/components/MaintenancePage/MaintenancePage.mdx +1 -1
  68. package/src/components/MaintenancePage/MaintenancePage.vue +15 -7
  69. package/src/components/MaintenancePage/accessibilite/Accessibility.mdx +61 -6
  70. package/src/components/MaintenancePage/assets/maintenance-ap.svg +1718 -0
  71. package/src/components/MaintenancePage/locales.ts +24 -3
  72. package/src/components/MaintenancePage/tests/MaintenancePage.a11y.spec.ts +75 -3
  73. package/src/components/MaintenancePage/tests/MaintenancePage.spec.ts +42 -2
  74. package/src/components/MaintenancePage/tests/__snapshots__/MaintenancePage.spec.ts.snap +3 -2
  75. package/src/components/NotFoundPage/NotFoundPage.mdx +1 -1
  76. package/src/components/NotFoundPage/NotFoundPage.stories.ts +3 -3
  77. package/src/components/NotFoundPage/NotFoundPage.vue +16 -11
  78. package/src/components/NotFoundPage/accessibilite/Accessibility.mdx +78 -6
  79. package/src/components/NotFoundPage/assets/not-found-ap.svg +2061 -0
  80. package/src/components/NotFoundPage/locales.ts +24 -4
  81. package/src/components/NotFoundPage/tests/NotFoundPage.a11y.spec.ts +168 -4
  82. package/src/components/NotFoundPage/tests/NotFoundPage.spec.ts +100 -12
  83. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +2 -2
  84. package/src/components/NotificationBar/NotificationBar.mdx +2 -2
  85. package/src/components/NotificationBar/accessibilite/Accessibility.mdx +68 -8
  86. package/src/components/PageContainer/tests/PageContainer.a11y.spec.ts +14 -7
  87. package/src/components/PhoneField/PhoneField.stories.ts +46 -38
  88. package/src/components/SocialMediaLinks/DefaultSocialMediaLinks.ts +6 -4
  89. package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +7 -5
  90. package/src/components/SocialMediaLinks/SocialMediaLinks.stories.ts +17 -13
  91. package/src/components/SocialMediaLinks/SocialMediaLinks.vue +9 -1
  92. package/src/components/SocialMediaLinks/accessibilite/Accessibility.mdx +63 -11
  93. package/src/components/SocialMediaLinks/tests/DefaultSocialMediaLinks.spec.ts +5 -5
  94. package/src/components/SocialMediaLinks/tests/SocialMediaLinks.a11y.spec.ts +59 -0
  95. package/src/components/SocialMediaLinks/tests/SocialMediaLinks.spec.ts +9 -7
  96. package/src/components/StatusPage/StatusPage.mdx +22 -0
  97. package/src/components/StatusPage/StatusPage.stories.ts +193 -0
  98. package/src/components/StatusPage/StatusPage.vue +145 -0
  99. package/src/components/StatusPage/accessibilite/Accessibility.mdx +81 -0
  100. package/src/components/StatusPage/tests/StatusPage.a11y.spec.ts +29 -0
  101. package/src/components/StatusPage/tests/StatusPage.spec.ts +50 -0
  102. package/src/components/StatusPage/tests/__snapshots__/StatusPage.spec.ts.snap +270 -0
  103. package/src/components/TableToolbar/TableToolbar.stories.ts +6 -6
  104. package/src/components/TableToolbar/TableToolbar.vue +1 -1
  105. package/src/components/TableToolbar/tests/__snapshots__/TableToolbar.spec.ts.snap +0 -5
  106. package/src/components/UploadWorkflow/UploadWorkflow.mdx +11 -1
  107. package/src/components/UploadWorkflow/UploadWorkflow.stories.ts +107 -3
  108. package/src/components/UploadWorkflow/UploadWorkflow.vue +35 -24
  109. package/src/components/UploadWorkflow/tests/UploadWorkflow.spec.ts +48 -0
  110. package/src/components/UploadWorkflow/tests/__snapshots__/UploadWorkflow.spec.ts.snap +9 -5
  111. package/src/components/UploadWorkflow/useFileList.ts +7 -0
  112. package/src/components/index.ts +3 -0
  113. package/src/composables/rules/tests/useFieldValidation.spec.ts +39 -3
  114. package/src/composables/rules/useFieldValidation.ts +24 -9
  115. package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +7 -0
  116. package/src/utils/theme/index.ts +19 -0
  117. package/src/utils/theme/tests/useThemeLocales.spec.ts +245 -0
  118. package/dist/components/MaintenancePage/index.d.ts +0 -2
  119. package/src/components/Customs/SyPagination/tests/SyPagination.a11y.spec.ts +0 -27
  120. package/src/components/Customs/SyTabs/tests/SyTabs.a11y.spec.ts +0 -51
  121. package/src/components/DataListItem/tests/DataListItem.a11y.spec.ts +0 -31
  122. package/src/components/DatePicker/CalendarMode/tests/DatePicker.a11y.spec.ts +0 -27
  123. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.a11y.spec.ts +0 -26
  124. package/src/components/DatePicker/DateTextInput/tests/DateTextInput.a11y.spec.ts +0 -27
  125. package/src/components/DownloadBtn/tests/DownloadBtn.a11y.spec.ts +0 -26
  126. package/src/components/ExternalLinks/tests/ExternalLinks.a11y.spec.ts +0 -39
  127. package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.a11y.spec.ts +0 -45
  128. package/src/components/HeaderToolbar/tests/HeaderToolbar.a11y.spec.ts +0 -25
  129. package/src/components/LunarCalendar/tests/LunarCalendar.a11y.spec.ts +0 -31
  130. package/src/components/MaintenancePage/index.ts +0 -3
  131. package/src/components/PageContainer/Accessibilite/AccessibilityGuide.mdx +0 -0
  132. package/src/components/PaginatedTable/tests/PaginatedTable.a11y.spec.ts +0 -43
  133. package/src/components/PhoneField/tests/PhoneField.a11y.spec.ts +0 -34
  134. /package/src/components/NotFoundPage/assets/{not-found.svg → not-found-cnam.svg} +0 -0
  135. /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
+ })
@@ -0,0 +1,10 @@
1
+ export type Option = {
2
+ label: string
3
+ value: string | number
4
+ disabled?: boolean
5
+ readonly?: boolean
6
+ id?: string
7
+ name?: string
8
+ ariaLabel?: string
9
+ title?: string
10
+ }
@@ -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
- // Sélectionner tous les inputs de type checkbox dans le composant
243
- // Pour aria-disabled
244
- const checkboxInputsDisabled = document.querySelectorAll('input[type="checkbox"][aria-disabled="false"]')
245
- checkboxInputsDisabled.forEach((input) => {
246
- input.removeAttribute('aria-disabled')
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 '../SyForm.vue'
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
- // Si le formulaire a été soumis et que la valeur change, on valide à nouveau
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
- // Pour aria-disabled sur les radios
188
- const radioInputsDisabled = document.querySelectorAll(
189
- 'input[type="radio"][aria-disabled="false"]',
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 } = !props.readonly
192
- ? validation
193
- : {
194
- errors: ref<string[]>([]),
195
- warnings: ref<string[]>([]),
196
- successes: ref<string[]>([]),
197
- validateField: () => {},
198
- clearValidation: () => {},
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 custom rules et que le champ est rempli
584
- const hasCustomRules = props.customRules && props.customRules.length > 0
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(hasCustomRules && hasValue)
610
+ validateDates(hasValidationRules && hasValue)
587
611
 
588
612
  // Après la validation initiale, désactiver le flag
589
613
  nextTick(() => {