@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,428 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ interface VerifiedPage {
5
+ name: string
6
+ url?: string
7
+ }
8
+
9
+ type EvaluationMethod = 'auto-evaluation' | 'audit-interne' | 'audit-externe'
10
+
11
+ interface DeclarationAccessibilityPageProps {
12
+ entityName: string
13
+ schemaUrl?: string
14
+ schemaUrlLabel?: string
15
+ actionsRealisedUrl?: string
16
+ actionsRealisedUrlLabel?: string
17
+ planActionsUrl?: string
18
+ planActionsUrlLabel?: string
19
+ siteName: string
20
+ siteUrl: string
21
+ rgaaVersion?: string
22
+ auditEntity?: string
23
+ auditDate?: string
24
+ evaluationMethod?: EvaluationMethod
25
+ overallComplianceRate?: number | null
26
+ averageComplianceRate?: number | null
27
+ auditGridUrl?: string
28
+ contactEmail: string
29
+ contactPhone?: string
30
+ nonConformities?: string[]
31
+ exemptions?: string[]
32
+ nonObligatoryContents?: string[]
33
+ declarationDate?: string
34
+ updateDate?: string
35
+ technologies?: string[]
36
+ testEnvironments?: string[]
37
+ accessibilityTools?: string[]
38
+ verifiedPages?: VerifiedPage[]
39
+ }
40
+
41
+ const props = withDefaults(defineProps<DeclarationAccessibilityPageProps>(), {
42
+ schemaUrl: undefined,
43
+ schemaUrlLabel: undefined,
44
+ actionsRealisedUrl: undefined,
45
+ actionsRealisedUrlLabel: undefined,
46
+ planActionsUrl: undefined,
47
+ planActionsUrlLabel: undefined,
48
+ rgaaVersion: '4',
49
+ auditEntity: undefined,
50
+ auditDate: undefined,
51
+ evaluationMethod: 'auto-evaluation',
52
+ overallComplianceRate: null,
53
+ averageComplianceRate: null,
54
+ auditGridUrl: undefined,
55
+ contactPhone: undefined,
56
+ nonConformities: () => [],
57
+ exemptions: () => [],
58
+ nonObligatoryContents: () => [],
59
+ technologies: () => [],
60
+ testEnvironments: () => [],
61
+ accessibilityTools: () => [],
62
+ verifiedPages: () => [],
63
+ declarationDate: undefined,
64
+ updateDate: undefined,
65
+ })
66
+
67
+ const hasAccessibilityPlan = computed(
68
+ () => !!props.schemaUrl || !!props.actionsRealisedUrl || !!props.planActionsUrl,
69
+ )
70
+
71
+ const hasItems = <T>(items?: T[] | null): items is T[] =>
72
+ Array.isArray(items) && items.length > 0
73
+
74
+ const formatDate = (date?: string) => {
75
+ if (!date) {
76
+ return ''
77
+ }
78
+
79
+ const parsedDate = new Date(date)
80
+ if (Number.isNaN(parsedDate.getTime())) {
81
+ return date
82
+ }
83
+
84
+ return new Intl.DateTimeFormat('fr-FR').format(parsedDate)
85
+ }
86
+
87
+ const conformityLabel = computed(() => {
88
+ if (props.averageComplianceRate === 100) {
89
+ return 'totalement conforme'
90
+ }
91
+
92
+ if (props.averageComplianceRate && props.averageComplianceRate >= 50) {
93
+ return 'partiellement conforme'
94
+ }
95
+
96
+ return 'non conforme'
97
+ })
98
+
99
+ const evaluationMethodLabel = computed(() => {
100
+ if (props.evaluationMethod === 'audit-interne') {
101
+ return 'un audit interne'
102
+ }
103
+
104
+ if (props.evaluationMethod === 'audit-externe') {
105
+ return 'un audit externe'
106
+ }
107
+
108
+ return 'une auto-évaluation'
109
+ })
110
+
111
+ const phoneHref = computed(() => {
112
+ if (!props.contactPhone) {
113
+ return undefined
114
+ }
115
+
116
+ const normalized = props.contactPhone.replace(/\s+/g, '')
117
+ if (!normalized) {
118
+ return undefined
119
+ }
120
+
121
+ return `tel:${normalized}`
122
+ })
123
+
124
+ const hasTestResults = computed(
125
+ () =>
126
+ !!props.auditEntity
127
+ || props.overallComplianceRate !== null
128
+ || props.averageComplianceRate !== null
129
+ || !!props.auditGridUrl,
130
+ )
131
+ </script>
132
+
133
+ <template>
134
+ <div class="accessibility-statement">
135
+ <section class="engagement">
136
+ <h2>Engagement d'accessibilité</h2>
137
+ <p>
138
+ <strong>{{ entityName }}</strong> s'engage à rendre ses sites internet, intranet, extranet et ses progiciels accessibles (et ses applications mobiles et mobilier urbain numérique) conformément à l'article 47 de la loi n°2005-102 du 11 février 2005.
139
+ </p>
140
+
141
+ <template v-if="hasAccessibilityPlan">
142
+ <p>À cette fin, <strong>{{ entityName }}</strong> met en œuvre la stratégie et les actions suivantes :</p>
143
+
144
+ <ul>
145
+ <li v-if="schemaUrl">
146
+ <a :href="schemaUrl">{{ schemaUrlLabel ?? 'Schéma pluriannuel de mise en accessibilité' }}</a> ;
147
+ </li>
148
+ <li v-if="actionsRealisedUrl">
149
+ <a :href="actionsRealisedUrl">{{ actionsRealisedUrlLabel ?? 'Actions réalisées' }}</a> ;
150
+ </li>
151
+ <li v-if="planActionsUrl">
152
+ <a :href="planActionsUrl">{{ planActionsUrlLabel ?? 'Plan d\'actions' }}</a>.
153
+ </li>
154
+ </ul>
155
+ </template>
156
+
157
+ <p>
158
+ Cette déclaration d'accessibilité s'applique à <a
159
+ :href="siteUrl"
160
+ :title="siteUrl"
161
+ >{{ siteName }}</a>.
162
+ </p>
163
+ </section>
164
+
165
+ <section class="conformity">
166
+ <h2>État de conformité</h2>
167
+ <p>
168
+ <a :href="siteUrl">{{ siteName }}</a> est <strong>{{ conformityLabel }}</strong> au référentiel général d'amélioration de l'accessibilité (RGAA), version {{ rgaaVersion }},
169
+ <span v-if="overallComplianceRate === null">
170
+ en raison d'une absence de réalisation d'audit.
171
+ </span>
172
+ <span v-else>
173
+ en raison des non-conformités et des dérogations énumérées ci-dessous.
174
+ </span>
175
+ </p>
176
+ </section>
177
+
178
+ <section
179
+ v-if="hasTestResults"
180
+ class="test-results"
181
+ >
182
+ <h2>Résultats des tests</h2>
183
+ <p v-if="auditEntity">
184
+ L'audit de conformité réalisé par {{ auditEntity }}
185
+ <span v-if="auditDate"> le {{ formatDate(auditDate) }}</span>
186
+ révèle que :
187
+ </p>
188
+ <p v-else>
189
+ Les tests de conformité réalisés conformément au RGAA version {{ rgaaVersion }} révèlent que :
190
+ </p>
191
+ <ul>
192
+ <li v-if="overallComplianceRate !== null">
193
+ {{ overallComplianceRate }}% des critères du RGAA version {{ rgaaVersion }} sont respectés ;
194
+ </li>
195
+ <li v-if="averageComplianceRate !== null">
196
+ Le taux moyen de conformité du site s'élève à {{ averageComplianceRate }}% ;
197
+ </li>
198
+ <li v-if="auditGridUrl">
199
+ <a :href="auditGridUrl">Accéder à la grille d'audit RGAA</a> pour télécharger la grille d'audit.
200
+ </li>
201
+ </ul>
202
+ </section>
203
+
204
+ <section class="non-accessible-content">
205
+ <h2 v-if="hasItems(nonConformities)">
206
+ Contenus non accessibles
207
+ </h2>
208
+
209
+ <div
210
+ v-if="hasItems(nonConformities)"
211
+ class="non-conformities"
212
+ >
213
+ <h3>Non-conformités</h3>
214
+ <ul>
215
+ <li
216
+ v-for="(item, index) in nonConformities"
217
+ :key="`non-conformity-${index}`"
218
+ >
219
+ {{ item }}
220
+ </li>
221
+ </ul>
222
+ </div>
223
+
224
+ <div
225
+ v-if="hasItems(exemptions)"
226
+ class="exemptions"
227
+ >
228
+ <h3>Dérogations pour charge disproportionnée</h3>
229
+ <ul>
230
+ <li
231
+ v-for="(item, index) in exemptions"
232
+ :key="`exemption-${index}`"
233
+ >
234
+ {{ item }}
235
+ </li>
236
+ </ul>
237
+ </div>
238
+
239
+ <div
240
+ v-if="hasItems(nonObligatoryContents)"
241
+ class="non-obligatory-contents"
242
+ >
243
+ <h3>Contenus non soumis à l'obligation d'accessibilité</h3>
244
+ <ul>
245
+ <li
246
+ v-for="(item, index) in nonObligatoryContents"
247
+ :key="`non-obligatory-${index}`"
248
+ >
249
+ {{ item }}
250
+ </li>
251
+ </ul>
252
+ </div>
253
+ </section>
254
+
255
+ <section
256
+ v-if="declarationDate || hasItems(technologies) || hasItems(testEnvironments) || hasItems(accessibilityTools) || hasItems(verifiedPages)"
257
+ class="declaration-establishment"
258
+ >
259
+ <h2>Établissement de cette déclaration d'accessibilité</h2>
260
+
261
+ <p v-if="declarationDate || updateDate">
262
+ <span v-if="declarationDate">
263
+ Cette déclaration a été établie le {{ formatDate(declarationDate) }} à partir de {{ evaluationMethodLabel }} réalisée conformément au référentiel RGAA version {{ rgaaVersion }}.
264
+ </span>
265
+ <span v-else>
266
+ Cette déclaration a été établie à partir de {{ evaluationMethodLabel }} réalisée conformément au référentiel RGAA version {{ rgaaVersion }}.
267
+ </span>
268
+ <span v-if="updateDate"> Elle a été mise à jour le {{ formatDate(updateDate) }}.</span>
269
+ </p>
270
+
271
+ <div
272
+ v-if="hasItems(technologies)"
273
+ class="technologies"
274
+ >
275
+ <h3>Technologies utilisées pour la réalisation du site</h3>
276
+ <ul>
277
+ <li
278
+ v-for="(item, index) in technologies"
279
+ :key="`technology-${index}`"
280
+ >
281
+ {{ item }}
282
+ </li>
283
+ </ul>
284
+ </div>
285
+
286
+ <div
287
+ v-if="hasItems(testEnvironments)"
288
+ class="test-environments"
289
+ >
290
+ <h3>Environnement de test</h3>
291
+ <p>Les vérifications de restitution de contenus ont été réalisées sur la base de la combinaison fournie par la base de référence du RGAA, avec les versions suivantes :</p>
292
+ <ul>
293
+ <li
294
+ v-for="(item, index) in testEnvironments"
295
+ :key="`environment-${index}`"
296
+ >
297
+ {{ item }}
298
+ </li>
299
+ </ul>
300
+ </div>
301
+
302
+ <div
303
+ v-if="hasItems(accessibilityTools)"
304
+ class="accessibility-tools"
305
+ >
306
+ <h3>Outils pour évaluer l'accessibilité</h3>
307
+ <ul>
308
+ <li
309
+ v-for="(item, index) in accessibilityTools"
310
+ :key="`tool-${index}`"
311
+ >
312
+ {{ item }}
313
+ </li>
314
+ </ul>
315
+ </div>
316
+
317
+ <div
318
+ v-if="hasItems(verifiedPages)"
319
+ class="verified-pages"
320
+ >
321
+ <h3>Pages du site ayant fait l'objet de la vérification de conformité</h3>
322
+ <ul>
323
+ <li
324
+ v-for="(item, index) in verifiedPages"
325
+ :key="`page-${index}`"
326
+ >
327
+ <span v-if="item.url"><a :href="item.url">{{ item.name }}</a></span>
328
+ <span v-else>{{ item.name }}</span>
329
+ </li>
330
+ </ul>
331
+ </div>
332
+ </section>
333
+
334
+ <section class="contact-information">
335
+ <h2>Retour d'information et contact</h2>
336
+ <p>
337
+ Si vous n'arrivez pas à accéder à un contenu ou à un service, vous pouvez contacter le ou la responsable de
338
+ <strong>{{ entityName }}</strong> pour être orienté vers une alternative accessible ou obtenir le contenu sous une autre forme.
339
+ </p>
340
+
341
+ <ul>
342
+ <li>
343
+ Envoyer un message à <a :href="`mailto:${contactEmail}`">{{ contactEmail }}</a>
344
+ </li>
345
+ <li v-if="contactPhone">
346
+ Contacter par téléphone : <a :href="phoneHref">{{ contactPhone }}</a>
347
+ </li>
348
+ </ul>
349
+ </section>
350
+
351
+ <section class="recourse">
352
+ <h2>Voies de recours</h2>
353
+ <p>
354
+ Si vous constatez un défaut d'accessibilité vous empêchant d'accéder à un contenu ou une
355
+ fonctionnalité du site, que vous nous le signalez et que vous ne parvenez pas à obtenir une réponse de notre part,
356
+ vous êtes en droit de faire parvenir vos doléances ou une demande de saisine au Défenseur des droits.
357
+ </p>
358
+
359
+ <p>Plusieurs moyens sont à votre disposition :</p>
360
+
361
+ <ul>
362
+ <li><a href="https://formulaire.defenseurdesdroits.fr/formulaire_saisine/">Écrire un message au Défenseur des droits</a></li>
363
+ <li><a href="https://www.defenseurdesdroits.fr/carte-des-delegues">Contacter le délégué du Défenseur des droits dans votre région</a></li>
364
+ <li>
365
+ Envoyer un courrier par la poste (gratuit, ne pas mettre de timbre) :
366
+ <address>
367
+ Défenseur des droits<br>
368
+ Libre réponse 71120<br>
369
+ 75342 Paris CEDEX 07
370
+ </address>
371
+ </li>
372
+ </ul>
373
+ </section>
374
+ </div>
375
+ </template>
376
+
377
+ <style scoped>
378
+ .accessibility-statement {
379
+ font-family: var(--v-font-family);
380
+ color: var(--v-text-color);
381
+ line-height: 1.5;
382
+ padding: 1rem;
383
+ }
384
+
385
+ .accessibility-statement section {
386
+ margin-bottom: 2rem;
387
+ }
388
+
389
+ .accessibility-statement h2 {
390
+ margin-top: 1.5rem;
391
+ margin-bottom: 1rem;
392
+ font-weight: 600;
393
+ }
394
+
395
+ .accessibility-statement ul {
396
+ list-style-type: disc;
397
+ margin-left: 1.5rem;
398
+ margin-bottom: 1rem;
399
+ }
400
+
401
+ .accessibility-statement ul ul {
402
+ margin-top: 0.5rem;
403
+ }
404
+
405
+ .accessibility-statement address {
406
+ margin-top: 1rem;
407
+ font-style: normal;
408
+ }
409
+
410
+ .accessibility-statement a {
411
+ color: rgb(var(--v-theme-primary));
412
+ text-decoration: underline;
413
+ }
414
+
415
+ .accessibility-statement a:hover {
416
+ text-decoration: none;
417
+ }
418
+
419
+ .accessibility-statement p {
420
+ margin-bottom: 0.75rem;
421
+ }
422
+
423
+ .accessibility-statement h3 {
424
+ margin-top: 1.25rem;
425
+ margin-bottom: 0.75rem;
426
+ font-weight: 500;
427
+ }
428
+ </style>
@@ -0,0 +1,75 @@
1
+ import { Meta, Primary } from '@storybook/blocks'
2
+ import * as Stories from '../DeclarationAccessibilityPage.stories.ts'
3
+ import AccessibilityIcon from '@/common/imgs/accessibility-svgrepo-com.svg'
4
+ import {
5
+ AccessibilityGuideLayout,
6
+ CriteriaSection,
7
+ CriteriaCard,
8
+ DemoSection,
9
+ BestPracticesSection,
10
+ ResourcesSection,
11
+ AuditSection,
12
+ } from '@/stories/accessibility/AccessibilityGuideLayout.mdx'
13
+
14
+ <Meta of={Stories} />
15
+
16
+ <AccessibilityGuideLayout
17
+ componentName="DeclarationAccessibilityPage"
18
+ iconSrc={AccessibilityIcon}
19
+ >
20
+ <CriteriaSection>
21
+ <CriteriaCard icon="📑" title="Structure et sémantique">
22
+ <ul>
23
+ <li>Sections structurées avec titres (<code>h2</code>) pour engagement, conformité, résultats de tests, contenus non accessibles, déclaration, contacts et recours.</li>
24
+ <li>Liens descriptifs vers le site, le schéma, les actions, le plan et la grille d'audit.</li>
25
+ <li>Listes ordonnées/non ordonnées pour les non-conformités, exemptions, contenus non obligatoires, technologies, environnements et outils.</li>
26
+ <li>Contact présenté sous forme de liste ; téléphone généré en <code>tel:</code> via <code>contactPhone</code> (espaces retirés).</li>
27
+ <li>Dates affichées au format localisé (FR) à partir de valeurs ISO recommandées.</li>
28
+ </ul>
29
+ </CriteriaCard>
30
+
31
+ <CriteriaCard icon="🧭" title="Visibilité conditionnelle">
32
+ <ul>
33
+ <li>Affichage conditionnel uniquement si des données sont fournies (plans d'actions, résultats, listes) pour éviter le contenu vide.</li>
34
+ <li>Étiquettes de conformité dérivées des taux fournis : totalement, partiellement ou non conforme.</li>
35
+ <li>Pages vérifiées listées avec liens cliquables quand l'URL est fournie.</li>
36
+ </ul>
37
+ </CriteriaCard>
38
+
39
+ <CriteriaCard icon="📣" title="Information utilisateur">
40
+ <ul>
41
+ <li>Voies de recours complètes (Défenseur des droits) avec liens et adresse postale.</li>
42
+ <li>Contact accessible : mailto obligatoire et téléphone optionnel.</li>
43
+ <li>Méthode d'évaluation explicite (auto, audit interne/externe) et taux de conformité.</li>
44
+ </ul>
45
+ </CriteriaCard>
46
+ </CriteriaSection>
47
+
48
+ <DemoSection componentName="DeclarationAccessibilityPage">
49
+ <Primary />
50
+ </DemoSection>
51
+
52
+ <BestPracticesSection>
53
+ <ul>
54
+ <li>Fournir au minimum <code>entityName</code>, <code>siteName</code>, <code>siteUrl</code>, <code>contactEmail</code>.</li>
55
+ <li>Préférer des URLs publiques et pérennes pour le schéma, les actions, le plan et la grille d'audit.</li>
56
+ <li>Entrer les dates en ISO (<code>YYYY-MM-DD</code>) pour un formatage fiable.</li>
57
+ <li>Renseigner les listes seulement lorsqu'elles sont disponibles (non-conformités, exemptions, contenus non obligatoires, technologies, environnements, outils, pages vérifiées).</li>
58
+ <li>Utiliser un numéro lisible (<code>contactPhone</code>) pour générer un lien téléphonique valide.</li>
59
+ </ul>
60
+ </BestPracticesSection>
61
+
62
+ <ResourcesSection>
63
+ <ul>
64
+ <li><a href="https://accessibilite.numerique.gouv.fr/methodologie/declaration-obligatoire/" target="_blank" rel="noopener noreferrer">Modèle de déclaration d’accessibilité (RGAA)</a></li>
65
+ <li><a href="https://www.w3.org/WAI/policies/" target="_blank" rel="noopener noreferrer">W3C – Accessibility Statements</a></li>
66
+ </ul>
67
+ </ResourcesSection>
68
+
69
+ <AuditSection>
70
+ <p>Rapport d’audit manuel : <em>en cours de réalisation</em>.</p>
71
+ <p style={{ color: 'grey', fontSize: '14px', marginTop: '0px' }}>
72
+ Correctifs associés : à venir (sera référencé dès publication de l’audit officiel).
73
+ </p>
74
+ </AuditSection>
75
+ </AccessibilityGuideLayout>
@@ -0,0 +1,53 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { describe, it } from 'vitest'
4
+ import { mount } from '@vue/test-utils'
5
+ import { axe } from 'vitest-axe'
6
+ import { assertNoA11yViolations } from '@tests/unit/accessibility/axeUtils'
7
+ import DeclarationAccessibilityPage from '../DeclarationAccessibilityPage.vue'
8
+
9
+ describe('DeclarationAccessibilityPage – accessibility (axe)', () => {
10
+ it('has no obvious axe violations with full data', async () => {
11
+ const wrapper = mount(DeclarationAccessibilityPage, {
12
+ props: {
13
+ entityName: 'Assurance Maladie',
14
+ siteName: 'ameli.fr',
15
+ siteUrl: 'https://www.ameli.fr',
16
+ contactEmail: 'accessibilite@ameli.fr',
17
+ contactPhone: '01 23 45 67 89',
18
+ schemaUrl: '#schema',
19
+ schemaUrlLabel: 'Schéma pluriannuel 2024-2026',
20
+ actionsRealisedUrl: '#actions',
21
+ actionsRealisedUrlLabel: 'Actions réalisées en 2024',
22
+ planActionsUrl: '#plan',
23
+ planActionsUrlLabel: 'Plan d\'actions 2025',
24
+ auditEntity: 'Atalan',
25
+ auditDate: '2024-06-15',
26
+ auditGridUrl: '#audit',
27
+ overallComplianceRate: 95,
28
+ averageComplianceRate: 82,
29
+ nonConformities: [
30
+ 'Certaines images informatives n\'ont pas d\'alternative textuelle.',
31
+ ],
32
+ exemptions: ['Les documents PDF archivés antérieurs à 2020.'],
33
+ nonObligatoryContents: ['Contenus tiers embarqués.'],
34
+ technologies: ['HTML5', 'CSS3', 'Vue.js'],
35
+ testEnvironments: ['Firefox 115 avec NVDA 2023.1'],
36
+ accessibilityTools: ['Axe DevTools', 'Wave'],
37
+ verifiedPages: [
38
+ { name: 'Accueil', url: 'https://www.ameli.fr' },
39
+ { name: 'Contact' },
40
+ ],
41
+ declarationDate: '2024-06-20',
42
+ updateDate: '2025-01-10',
43
+ },
44
+ })
45
+
46
+ await wrapper.vm.$nextTick()
47
+
48
+ const results = await axe(wrapper.element as HTMLElement)
49
+ assertNoA11yViolations(results, 'DeclarationAccessibilityPage – full data', {
50
+ ignoreRules: ['region'],
51
+ })
52
+ })
53
+ })
@@ -0,0 +1,59 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import DeclarationAccessibilityPage from '../DeclarationAccessibilityPage.vue'
4
+
5
+ const minimalProps = {
6
+ entityName: 'Assurance Maladie',
7
+ siteName: 'ameli.fr',
8
+ siteUrl: 'https://www.ameli.fr',
9
+ contactEmail: 'accessibilite@ameli.fr',
10
+ }
11
+
12
+ describe('DeclarationAccessibilityPage', () => {
13
+ it('renders required sections with minimal props', () => {
14
+ const wrapper = mount(DeclarationAccessibilityPage, {
15
+ props: minimalProps,
16
+ })
17
+
18
+ expect(wrapper.text()).toContain(minimalProps.entityName)
19
+ expect(wrapper.text()).toContain(minimalProps.siteName)
20
+ expect(wrapper.find('.contact-information').text()).toContain(minimalProps.contactEmail)
21
+
22
+ const siteLink = wrapper.get('.engagement a[href]')
23
+ expect(siteLink.attributes('href')).toBe(minimalProps.siteUrl)
24
+ expect(wrapper.text()).toContain('non conforme')
25
+ })
26
+
27
+ it('displays optional plan, tests results and non-accessible content when provided', () => {
28
+ const wrapper = mount(DeclarationAccessibilityPage, {
29
+ props: {
30
+ ...minimalProps,
31
+ schemaUrl: '#schema',
32
+ actionsRealisedUrl: '#actions',
33
+ planActionsUrl: '#plan',
34
+ auditEntity: 'Atalan',
35
+ auditDate: '2024-06-15',
36
+ overallComplianceRate: 95,
37
+ auditGridUrl: '#audit',
38
+ nonConformities: ['Formulaire sans label', 'Images sans alternative textuelle'],
39
+ exemptions: ['PDF archivés non accessibles'],
40
+ nonObligatoryContents: ['Contenus tiers'],
41
+ technologies: ['HTML', 'Vue.js'],
42
+ testEnvironments: ['Firefox 115 avec NVDA 2023.1'],
43
+ accessibilityTools: ['Axe DevTools'],
44
+ verifiedPages: [
45
+ { name: 'Accueil', url: 'https://www.ameli.fr' },
46
+ { name: 'Contact' },
47
+ ],
48
+ },
49
+ })
50
+
51
+ expect(wrapper.find('.engagement ul').exists()).toBe(true)
52
+ expect(wrapper.find('.test-results').exists()).toBe(true)
53
+ expect(wrapper.findAll('.non-conformities li')).toHaveLength(2)
54
+ expect(wrapper.find('.exemptions').exists()).toBe(true)
55
+ expect(wrapper.find('.non-obligatory-contents').exists()).toBe(true)
56
+ expect(wrapper.find('.declaration-establishment').exists()).toBe(true)
57
+ expect(wrapper.find('.verified-pages').exists()).toBe(true)
58
+ })
59
+ })
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed, nextTick, onMounted, ref } from 'vue'
2
+ import { computed, nextTick, onMounted, onUpdated, ref } from 'vue'
3
3
  import useCustomizableOptions, { type CustomizableOptions } from '@/composables/useCustomizableOptions'
4
4
  import { config } from './config'
5
5
  import { locales } from './locales'
@@ -74,6 +74,18 @@
74
74
  return wrapperRef.value?.querySelector('input, textarea') ?? null
75
75
  }
76
76
 
77
+ function ensureInputAccessibilityLabel() {
78
+ const input = getNativeInput()
79
+ if (!input) return
80
+
81
+ const hasAriaLabel = input.hasAttribute('aria-label')
82
+ const hasLabelledBy = input.hasAttribute('aria-labelledby')
83
+
84
+ if (!hasAriaLabel && !hasLabelledBy) {
85
+ input.setAttribute('aria-label', props.inputAriaLabel)
86
+ }
87
+ }
88
+
77
89
  function insertChar(char: string) {
78
90
  const el = getNativeInput()
79
91
  if (!el) return
@@ -146,6 +158,13 @@
146
158
  onMounted(() => {
147
159
  nextTick(() => {
148
160
  updateInputMessageHeight()
161
+ ensureInputAccessibilityLabel()
162
+ })
163
+ })
164
+
165
+ onUpdated(() => {
166
+ nextTick(() => {
167
+ ensureInputAccessibilityLabel()
149
168
  })
150
169
  })
151
170
  </script>
@@ -1,23 +1,13 @@
1
- import {Controls, Canvas, Meta, Source} from '@storybook/blocks';
2
-
3
- import * as ErrorPageStories from './ErrorPage.stories'
1
+ import { Controls, Canvas, Meta, Source } from "@storybook/blocks";
2
+ import '../../stories/styles/shared.css';
3
+ import * as ErrorPageStories from "./ErrorPage.stories";
4
4
 
5
5
  <Meta of={ErrorPageStories} />
6
- import '../../stories/styles/shared.css';
7
6
 
8
7
  <div className="header">
9
8
  <h1>ErrorPage</h1>
10
- <p>Le composant `ErrorPage` sert à afficher une page d'erreur.</p>
9
+ <p>Le composant `ErrorPage` permet d'afficher une page d'error.
10
+ Il est basé sur le composant `StatusPage` du design system.</p>
11
11
  </div>
12
12
 
13
- <Canvas of={ErrorPageStories.Default} />
14
-
15
- # API
16
-
17
- <Controls of={ErrorPageStories.Default} />
18
-
19
- ## Lien de retour
20
-
21
- Vous pouvez mettre un lien vers une autre page avec les props `btn-text` et `btn-link` ou `btn-href`.
22
-
23
- <Canvas of={ErrorPageStories.WithLink} />
13
+ <Canvas of={ErrorPageStories.Default} />