@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,193 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import StatusPage from './StatusPage.vue'
3
+
4
+ const meta = {
5
+ title: 'Templates/StatusPage',
6
+ component: StatusPage,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ argTypes: {
11
+ 'code': {
12
+ description: 'Code d\'erreur affiché en premier plan',
13
+ },
14
+ 'codeErrorText': {
15
+ description: 'Text affiché avant le code d\'erreur pour les outils d\'accessibilité',
16
+ table: {
17
+ defaultValue: {
18
+ summary: 'Code d\'erreur\xa0: ',
19
+ },
20
+ },
21
+ },
22
+ 'additional-content': {
23
+ control: {
24
+ type: 'text',
25
+ },
26
+ table: {
27
+ type: {
28
+ summary: '{}',
29
+ },
30
+ },
31
+ },
32
+ 'action': {
33
+ control: {
34
+ type: 'text',
35
+ },
36
+ table: {
37
+ type: {
38
+ summary: '{}',
39
+ },
40
+ },
41
+ },
42
+ 'illustration': {
43
+ control: {
44
+ type: 'text',
45
+ },
46
+ table: {
47
+ type: {
48
+ summary: '{}',
49
+ },
50
+ },
51
+ },
52
+ },
53
+ } satisfies Meta<typeof StatusPage>
54
+
55
+ export default meta
56
+
57
+ type Story = StoryObj<typeof StatusPage>
58
+
59
+ export const Default: Story = {
60
+ args: {
61
+ pageTitle: 'une erreur est survenue',
62
+ code: '500',
63
+ message: 'Une erreur est survenue de notre côté, veuillez réessayer plus tard. Si le problème persiste veuillez nous contacter par téléphone au 3646',
64
+ },
65
+ parameters: {
66
+ sourceCode: [
67
+ {
68
+ name: 'Template',
69
+ code: `
70
+ <template>
71
+ <div style="padding: 20px; background: rgb(231, 236, 245)">
72
+ <StatusPage
73
+ page-title="une erreur est survenue"
74
+ code="500"
75
+ message="Une erreur est survenue de notre côté, veuillez réessayer plus tard. Si le problème persiste veuillez nous contacter par téléphone au 3646"
76
+ >
77
+ </div>
78
+ </template>
79
+ `,
80
+ }, {
81
+ name: 'Script',
82
+ code: `
83
+ <script setup lang="ts">
84
+ import { StatusPage } from '@cnamts/synapse'
85
+ </script>
86
+
87
+ `,
88
+ },
89
+ ],
90
+ },
91
+ decorators: [
92
+ () => ({ template: '<div style="padding: 20px; background: rgb(231, 236, 245)"><story /></div>' }),
93
+ ],
94
+ }
95
+
96
+ export const WithLink: Story = {
97
+ args: {
98
+ ...Default.args,
99
+ btnHref: '/',
100
+ btnText: 'Retour à l\'accueil',
101
+ },
102
+ parameters: {
103
+ sourceCode: [
104
+ {
105
+ name: 'Template',
106
+ code: `
107
+ <template>
108
+ <div style="padding: 20px; background: rgb(231, 236, 245)">
109
+ <StatusPage
110
+ page-title="une erreur est survenue"
111
+ code="500"
112
+ message="Une erreur est survenue de notre côté, veuillez réessayer plus tard. Si le problème persiste veuillez nous contacter par téléphone au 3646"
113
+ btn-href=""
114
+ btn-text="Retour à l'accueil"
115
+ >
116
+ </div>
117
+ </template>
118
+ `,
119
+ }, {
120
+ name: 'Script',
121
+ code: `
122
+ <script setup lang="ts">
123
+ import { StatusPage } from '@cnamts/synapse'
124
+ </script>
125
+
126
+ `,
127
+ },
128
+ ],
129
+ },
130
+ decorators: [
131
+ () => ({ template: '<div style="padding: 20px; background: rgb(231, 236, 245)"><story /></div>' }),
132
+ ],
133
+ }
134
+
135
+ export const CustomIllustration: Story = {
136
+ args: {
137
+ ...Default.args,
138
+ btnHref: '/',
139
+ btnText: 'Retour à l\'accueil',
140
+ },
141
+ parameters: {
142
+ sourceCode: [
143
+ {
144
+ name: 'Template',
145
+ code: `
146
+ <template>
147
+ <div style="padding: 20px; background: rgb(231, 236, 245)">
148
+ <StatusPage
149
+ page-title="une erreur est survenue"
150
+ code="500"
151
+ message="Une erreur est survenue de notre côté, veuillez réessayer plus tard."
152
+ btn-href="/"
153
+ btn-text="Retour à l'accueil"
154
+ >
155
+ <template #illustration>
156
+ <div style="width: 260px; height: 200px; display: grid; place-items: center; border-radius: 12px; background: white; border: 2px dashed #0D419A;">
157
+ <span style="font-weight: 700; color: #0D419A;">Illustration</span>
158
+ </div>
159
+ </template>
160
+ </StatusPage>
161
+ </div>
162
+ </template>
163
+ `,
164
+ },
165
+ {
166
+ name: 'Script',
167
+ code: `
168
+ <script setup lang="ts">
169
+ import { StatusPage } from '@cnamts/synapse'
170
+ </script>
171
+ `,
172
+ },
173
+ ],
174
+ },
175
+ decorators: [
176
+ () => ({ template: '<div style="padding: 20px; background: rgb(231, 236, 245)"><story /></div>' }),
177
+ ],
178
+ render: args => ({
179
+ components: { StatusPage },
180
+ setup() {
181
+ return { args }
182
+ },
183
+ template: `
184
+ <StatusPage v-bind="args">
185
+ <template #illustration>
186
+ <div style="width: 260px; height: 200px; display: grid; place-items: center; border-radius: 12px; background: white; border: 2px dashed #0D419A;">
187
+ <span style="font-weight: 700; color: #0D419A;">Illustration</span>
188
+ </div>
189
+ </template>
190
+ </StatusPage>
191
+ `,
192
+ }),
193
+ }
@@ -0,0 +1,145 @@
1
+ <script setup lang="ts">
2
+ import type { RouteRecordRaw } from 'vue-router'
3
+ import PageContainer from '../PageContainer/PageContainer.vue'
4
+
5
+ type MessagePart =
6
+ | { type: 'text', value: string }
7
+ | { type: 'phone', value: string }
8
+
9
+ // Fonction pour formater le message et ajouter des liens tel: aux numéros de téléphone
10
+ const splitMessage = (message?: string): MessagePart[] => {
11
+ // Regex pour détecter les numéros de téléphone
12
+ if (!message)
13
+ return []
14
+
15
+ const regex = /\b(\d{4}|\d{10})\b/g
16
+ const parts: MessagePart[] = []
17
+ let lastIndex = 0
18
+ let match: RegExpExecArray | null
19
+
20
+ while ((match = regex.exec(message)) !== null) {
21
+ if (match.index > lastIndex) {
22
+ parts.push({
23
+ type: 'text',
24
+ value: message.slice(lastIndex, match.index),
25
+ })
26
+ }
27
+
28
+ parts.push({
29
+ type: 'phone',
30
+ value: match[1]!,
31
+ })
32
+
33
+ lastIndex = regex.lastIndex
34
+ }
35
+
36
+ if (lastIndex < message.length) {
37
+ parts.push({
38
+ type: 'text',
39
+ value: message.slice(lastIndex),
40
+ })
41
+ }
42
+
43
+ return parts
44
+ }
45
+
46
+ withDefaults(defineProps<{
47
+ pageTitle?: string
48
+ message?: string
49
+ code?: string
50
+ codeErrorText?: string
51
+ btnText?: string
52
+ btnHref?: string
53
+ btnLink?: RouteRecordRaw | string
54
+ hideBtn?: boolean
55
+ }>(), {
56
+ pageTitle: undefined,
57
+ message: undefined,
58
+ code: undefined,
59
+ codeErrorText: 'Code d\'erreur\xa0: ',
60
+ btnText: undefined,
61
+ btnLink: '/',
62
+ btnHref: undefined,
63
+ hideBtn: false,
64
+ })
65
+ </script>
66
+
67
+ <template>
68
+ <PageContainer size="md">
69
+ <VCard
70
+ :elevation="0"
71
+ class="pa-6 pa-sm-16"
72
+ >
73
+ <VRow class="max-width-none">
74
+ <VCol
75
+ :sm="$slots.illustration ? 6 : 12"
76
+ cols="12"
77
+ class="order-last order-sm-first text-center text-sm-left d-flex flex-column justify-center align-sm-start"
78
+ >
79
+ <div
80
+ v-if="code"
81
+ class="sy-code text-primary mb-4"
82
+ >
83
+ <span class="d-sr-only">{{ codeErrorText }}</span>
84
+ {{ code }}
85
+ </div>
86
+
87
+ <h1
88
+ v-if="pageTitle"
89
+ class="mb-2 font-weight-bold text-h5 mb-4"
90
+ >
91
+ {{ pageTitle }}
92
+ </h1>
93
+
94
+ <p v-if="message">
95
+ <template
96
+ v-for="(part, index) in splitMessage(message)"
97
+ :key="index"
98
+ >
99
+ <span v-if="part.type === 'text'">
100
+ {{ part.value }}
101
+ </span>
102
+ <a
103
+ v-else
104
+ :href="`tel:${part.value}`"
105
+ >
106
+ {{ part.value }}
107
+ </a>
108
+ </template>
109
+ </p>
110
+
111
+ <slot name="additional-content" />
112
+
113
+ <slot name="action">
114
+ <VBtn
115
+ v-if="!hideBtn && btnText && (btnLink || btnHref)"
116
+ :to="btnHref ? undefined : btnLink"
117
+ :href="btnHref"
118
+ color="primary"
119
+ class="mt-6"
120
+ >
121
+ {{ btnText }}
122
+ </VBtn>
123
+ </slot>
124
+ </VCol>
125
+
126
+ <VCol
127
+ v-if="$slots.illustration"
128
+ cols="12"
129
+ sm="6"
130
+ class="d-flex align-center justify-center"
131
+ >
132
+ <slot name="illustration" />
133
+ </VCol>
134
+ </VRow>
135
+ </VCard>
136
+ </PageContainer>
137
+ </template>
138
+
139
+ <style lang="scss" scoped>
140
+ .sy-code {
141
+ font-size: 6rem;
142
+ line-height: 6rem;
143
+ font-weight: 400;
144
+ }
145
+ </style>
@@ -0,0 +1,81 @@
1
+ import { Meta, Story } from '@storybook/blocks';
2
+ import * as StatusPageStories from '../StatusPage.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
+ } from '@/stories/accessibility/AccessibilityGuideLayout.mdx';
12
+
13
+ <Meta of={StatusPageStories} />
14
+
15
+ <AccessibilityGuideLayout
16
+ componentName="StatusPage"
17
+ iconSrc={AccessibilityIcon}
18
+ >
19
+
20
+ <CriteriaSection>
21
+ <CriteriaCard icon="🔍" title="Structure sémantique">
22
+ <ul>
23
+ <li><strong>Titre de page</strong> : le titre est rendu dans une balise <code>h1</code>, unique et descriptif</li>
24
+ <li><strong>Code d'erreur</strong> : le code (ex. <code>500</code>, <code>404</code>) est précédé du texte masqué visuellement <code>codeErrorText</code> (par défaut <em>"Code d'erreur : "</em>) pour les lecteurs d'écran</li>
25
+ <li><strong>Rôles ARIA hérités</strong> via <code>PageContainer</code> :</li>
26
+ <ul>
27
+ <li>exemple : <code>role="main"</code> représente le contenu principal de la page</li>
28
+ </ul>
29
+ </ul>
30
+ </CriteriaCard>
31
+
32
+ <CriteriaCard icon="🔗" title="Liens et boutons">
33
+ <ul>
34
+ <li><strong>Numéros de téléphone</strong> : les numéros de 4 ou 10 chiffres (ex. <code>3646</code>) sont automatiquement transformés en liens <code>tel:</code> cliquables et vocalisables</li>
35
+ <li><strong>Bouton de retour</strong> : rendu via <code>btn-href</code> (balise <code>a</code>) ou <code>btn-link</code> (balise <code>router-link</code>)</li>
36
+ <li><strong>Texte du bouton</strong> : doit être explicite et décrire la destination, ex. <em>"Retour à l'accueil"</em></li>
37
+ <li><strong>Masquage du bouton</strong> : la prop <code>hide-btn</code> permet de masquer le bouton si une alternative de navigation est présente</li>
38
+ </ul>
39
+ </CriteriaCard>
40
+
41
+ <CriteriaCard icon="🖼️" title="Illustration">
42
+ <ul>
43
+ <li><strong>Image décorative</strong> : l'illustration doit avoir <code>alt=""</code> et <code>aria-hidden="true"</code> car elle est purement décorative</li>
44
+ <li><strong>Slot illustration</strong> : si une illustration personnalisée est fournie via le slot <code>#illustration</code>, les mêmes règles s'appliquent</li>
45
+ <li><strong>Mise en page adaptive</strong> : la colonne illustration n'est affichée que si le slot est fourni, évitant des zones vides</li>
46
+ </ul>
47
+ </CriteriaCard>
48
+
49
+ <CriteriaCard icon="📝" title="Contenu additionnel">
50
+ <ul>
51
+ <li><strong>Slot <code>additional-content</code></strong> : destiné à du contenu textuel complémentaire (ex. identifiant de support), doit rester lisible par les lecteurs d'écran</li>
52
+ <li><strong>Slot <code>action</code></strong> : permet d'ajouter des actions supplémentaires accessibles au clavier</li>
53
+ </ul>
54
+ </CriteriaCard>
55
+ </CriteriaSection>
56
+
57
+ <DemoSection title="Avec illustration personnalisée" componentName="StatusPage">
58
+ <Story of={StatusPageStories.CustomIllustration} />
59
+ </DemoSection>
60
+
61
+ <BestPracticesSection>
62
+ <ul>
63
+ <li>Toujours renseigner <code>page-title</code> avec un titre clair et unique décrivant l'erreur</li>
64
+ <li>Personnaliser <code>code-error-text</code> si nécessaire pour un contexte métier spécifique</li>
65
+ <li>Fournir un <code>btn-text</code> explicite — éviter les libellés génériques comme <em>"Cliquez ici"</em></li>
66
+ <li>Ne pas masquer le bouton (<code>hide-btn</code>) sans proposer une alternative de navigation claire</li>
67
+ <li>Les illustrations doivent toujours être décoratives (<code>aria-hidden="true"</code>) — ne jamais y placer d'information essentielle</li>
68
+ <li>Le contenu dans <code>additional-content</code> doit être lisible par les lecteurs d'écran : éviter le contenu purement visuel</li>
69
+ </ul>
70
+ </BestPracticesSection>
71
+
72
+ <ResourcesSection>
73
+ <ul>
74
+ <li><a href="https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html" target="_blank" style={{ color: '#0C41BD' }}>WCAG 1.3.1 – Info and Relationships</a></li>
75
+ <li><a href="https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-in-context.html" target="_blank" style={{ color: '#0C41BD' }}>WCAG 2.4.4 – Link Purpose</a></li>
76
+ <li><a href="https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html" target="_blank" style={{ color: '#0C41BD' }}>WCAG 1.1.1 – Non-text Content</a></li>
77
+ <li><a href="https://www.w3.org/WAI/ARIA/apg/patterns/" target="_blank" style={{ color: '#0C41BD' }}>ARIA Authoring Practices Guide</a></li>
78
+ </ul>
79
+ </ResourcesSection>
80
+
81
+ </AccessibilityGuideLayout>
@@ -0,0 +1,29 @@
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 StatusPage from '../StatusPage.vue'
8
+
9
+ // Scénario d’accessibilité : page d’erreur avec titre, message, code
10
+ // et bouton de retour vers la page d’accueil.
11
+
12
+ describe('StatusPage – accessibility (axe)', () => {
13
+ it('has no obvious axe violations with title, message and action button', async () => {
14
+ const wrapper = mount(StatusPage, {
15
+ props: {
16
+ pageTitle: 'Une erreur est survenue',
17
+ message: 'Un problème technique est survenu. Merci de réessayer plus tard.',
18
+ code: '500',
19
+ btnText: 'Retour à l\'accueil',
20
+ btnHref: 'https://www.ameli.fr',
21
+ },
22
+ })
23
+
24
+ const results = await axe(wrapper.element as HTMLElement)
25
+ assertNoA11yViolations(results, 'StatusPage – default page', {
26
+ ignoreRules: ['region'],
27
+ })
28
+ })
29
+ })
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import StatusPage from '../StatusPage.vue'
4
+
5
+ describe('StatusPage', () => {
6
+ it('renders correctly', () => {
7
+ const wrapper = mount(StatusPage, {
8
+ props: {
9
+ pageTitle: 'Something went wrong',
10
+ message: 'Error message',
11
+ },
12
+ })
13
+
14
+ expect(wrapper.text()).toContain('Something went wrong')
15
+ expect(wrapper.text()).toContain('Error message')
16
+ expect(wrapper.html()).toMatchSnapshot()
17
+ })
18
+
19
+ it('renders correctly with undefined route', () => {
20
+ const wrapper = mount(StatusPage, {
21
+ props: {
22
+ code: '501',
23
+ pageTitle: 'Error',
24
+ message: 'Error message',
25
+ btnText: 'Go to...',
26
+ btnHref: 'https://google.com',
27
+ },
28
+ })
29
+
30
+ expect(wrapper.find('a').exists()).toBe(true)
31
+ expect(wrapper.html()).toMatchSnapshot()
32
+ })
33
+
34
+ it('uses href without router navigation when only btnHref is provided', () => {
35
+ const wrapper = mount(StatusPage, {
36
+ props: {
37
+ code: '401',
38
+ pageTitle: 'Auth error',
39
+ message: 'You are not authorized',
40
+ btnText: 'Logout',
41
+ btnHref: 'https://google.com',
42
+ },
43
+ })
44
+
45
+ const link = wrapper.find('a')
46
+ expect(link.exists()).toBe(true)
47
+ expect(link.attributes('href')).toBe('https://google.com')
48
+ expect(link.attributes('to')).toBeUndefined()
49
+ })
50
+ })