@cnamts/synapse 1.0.22 → 1.0.23

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 (190) hide show
  1. package/dist/{DateFilter-B5n-ZkLi.js → DateFilter-Dc-gSGwk.js} +1 -1
  2. package/dist/{NumberFilter-CtiZ9uj8.js → NumberFilter-vP38Wp6j.js} +1 -1
  3. package/dist/{PeriodFilter-DzqiMb-b.js → PeriodFilter-Ba1uYUnT.js} +1 -1
  4. package/dist/{SelectFilter-BOYlF7rX.js → SelectFilter-BioGT6Nn.js} +1 -1
  5. package/dist/{TextFilter-BOFRNfcX.js → TextFilter-B84dpnoq.js} +1 -1
  6. package/dist/components/Accordion/Accordion.d.ts +13 -2
  7. package/dist/components/Accordion/composables/useAccordionState.d.ts +2 -1
  8. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +7 -7
  9. package/dist/components/Amelipro/AmeliproCheckbox/AmeliproCheckbox.d.ts +1 -1
  10. package/dist/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.d.ts +1 -1
  11. package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +1 -1
  12. package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +7 -7
  13. package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +16 -16
  14. package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +1 -1
  15. package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +1 -1
  16. package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +22 -1
  17. package/dist/components/Customs/Selects/SyAutocomplete/locales.d.ts +5 -0
  18. package/dist/components/Customs/Selects/SyInputSelect/SyInputSelect.d.ts +1 -1
  19. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +1 -1
  20. package/dist/components/Customs/Selects/SySelect/locales.d.ts +1 -0
  21. package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +1 -1
  22. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +1 -1
  23. package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +1 -1
  24. package/dist/components/Customs/SyTextField/SyTextField.d.ts +5 -2
  25. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +13 -9
  26. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +7 -5
  27. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +2 -1
  28. package/dist/components/ErrorPage/ErrorPage.d.ts +3 -1
  29. package/dist/components/FileList/UploadItem/UploadItem.d.ts +6 -0
  30. package/dist/components/FileList/UploadItem/locales.d.ts +1 -4
  31. package/dist/components/FileUpload/FileUploadContent.d.ts +2 -0
  32. package/dist/components/FileUpload/validateFiles.d.ts +2 -1
  33. package/dist/components/HeaderBar/HeaderBar.d.ts +2 -1
  34. package/dist/components/HeaderBar/HeaderLogo/HeaderLogo.d.ts +2 -1
  35. package/dist/components/HeaderNavigationBar/HeaderNavigationBar.d.ts +2 -1
  36. package/dist/components/MonthPicker/MonthPicker.d.ts +1939 -0
  37. package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +1899 -0
  38. package/dist/components/MonthPicker/MonthPickerText/useTextField.d.ts +21 -0
  39. package/dist/components/MonthPicker/MonthPickerVisual/MonthPickerVisual.d.ts +21 -0
  40. package/dist/components/MonthPicker/MonthPickerVisual/MonthPickerVisualProps.d.ts +12 -0
  41. package/dist/components/MonthPicker/MonthPickerVisual/MonthSelector.d.ts +11 -0
  42. package/dist/components/MonthPicker/MonthPickerVisual/VisualPickerFooter.d.ts +6 -0
  43. package/dist/components/MonthPicker/MonthPickerVisual/VisualPickerHeader.d.ts +14 -0
  44. package/dist/components/MonthPicker/MonthPickerVisual/YearSelector.d.ts +14 -0
  45. package/dist/components/MonthPicker/MonthPickerVisual/useMonthGrid.d.ts +9 -0
  46. package/dist/components/MonthPicker/MonthPickerVisual/useYearGrid.d.ts +8 -0
  47. package/dist/components/MonthPicker/MonthPickerVisual/utils.d.ts +8 -0
  48. package/dist/components/MonthPicker/locales.d.ts +12 -0
  49. package/dist/components/MonthPicker/useMonthPickerValidation.d.ts +25 -0
  50. package/dist/components/NirField/NirField.d.ts +3 -1
  51. package/dist/components/NotificationBar/Notification/Notification.d.ts +3 -0
  52. package/dist/components/PasswordField/PasswordField.d.ts +1 -1
  53. package/dist/components/PeriodField/PeriodField.d.ts +29 -21
  54. package/dist/components/PhoneField/PhoneField.d.ts +2 -1
  55. package/dist/components/SyBtnMenu/SyBtnMenu.d.ts +1 -1
  56. package/dist/components/SyHeading/SyHeading.a11y.test.d.ts +1 -0
  57. package/dist/components/SyHeading/SyHeading.d.ts +4 -2
  58. package/dist/components/SyHeading/SyHeading.test.d.ts +1 -0
  59. package/dist/components/SyTextArea/SyTextArea.d.ts +1 -1
  60. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +4 -4
  61. package/dist/components/Tables/SyTable/SyTable.d.ts +4 -4
  62. package/dist/components/Tables/common/SyTablePagination.d.ts +6 -6
  63. package/dist/components/index.d.ts +1 -0
  64. package/dist/design-system-v3.js +102 -99
  65. package/dist/design-system-v3.umd.cjs +126 -126
  66. package/dist/designTokens/tokens/cnam/cnamContextual.d.ts +5 -0
  67. package/dist/{main-CEl4J8_T.js → main-aLKwdMi1.js} +11167 -10522
  68. package/dist/main.d.ts +1 -0
  69. package/dist/style.css +1 -1
  70. package/package.json +10 -4
  71. package/src/assets/apTokens.scss +2 -2
  72. package/src/assets/overrides/_btns.scss +8 -0
  73. package/src/assets/overrides/_forms.scss +9 -0
  74. package/src/assets/overrides/_icons.scss +38 -9
  75. package/src/assets/overrides/_tables.scss +19 -0
  76. package/src/components/Accordion/Accordion.mdx +23 -9
  77. package/src/components/Accordion/Accordion.stories.ts +153 -3
  78. package/src/components/Accordion/Accordion.vue +7 -6
  79. package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +40 -12
  80. package/src/components/Accordion/composables/useAccordionState.ts +3 -4
  81. package/src/components/Accordion/tests/accordion.spec.ts +131 -19
  82. package/src/components/Amelipro/AmeliproPagination/AmeliproPagination.mdx +3 -1
  83. package/src/components/Amelipro/AmeliproPagination/AmeliproPagination.stories.ts +8 -0
  84. package/src/components/BackBtn/accessibilite/Accessibility.mdx +62 -10
  85. package/src/components/BackToTopBtn/BackToTopBtn.stories.ts +9 -3
  86. package/src/components/BackToTopBtn/accessibilite/Accessibility.mdx +86 -6
  87. package/src/components/Captcha/tests/Captcha.spec.ts +0 -29
  88. package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +2 -110
  89. package/src/components/Customs/Selects/SelectBtnField/accessibilite/Accessibility.mdx +133 -10
  90. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.stories.ts +379 -93
  91. package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +144 -83
  92. package/src/components/Customs/Selects/SyAutocomplete/accessibilite/Accessibilite.stories.ts +40 -1
  93. package/src/components/Customs/Selects/SyAutocomplete/accessibilite/Accessibility.mdx +7 -1
  94. package/src/components/Customs/Selects/SyAutocomplete/locales.ts +5 -0
  95. package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.a11y.spec.ts +96 -0
  96. package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.spec.ts +234 -9
  97. package/src/components/Customs/Selects/SyAutocomplete/utils/ariaManager.ts +13 -3
  98. package/src/components/Customs/Selects/SyAutocomplete/utils/useSelectionLogic.ts +9 -10
  99. package/src/components/Customs/Selects/SySelect/SySelect.vue +46 -3
  100. package/src/components/Customs/Selects/SySelect/locales.ts +1 -0
  101. package/src/components/Customs/SyIcon/SyIcon.vue +1 -1
  102. package/src/components/Customs/SyIcon/tests/SyIcon.a11y.spec.ts +20 -0
  103. package/src/components/Customs/SyIconButton/SyIconButton.mdx +46 -0
  104. package/src/components/Customs/SyIconButton/SyIconButton.stories.ts +184 -0
  105. package/src/components/Customs/SyIconButton/SyIconButton.vue +38 -0
  106. package/src/components/Customs/SyIconButton/accessibilite/Accessibility.mdx +64 -0
  107. package/src/components/Customs/SyIconButton/tests/SyIconButton.a11y.spec.ts +87 -0
  108. package/src/components/Customs/SyIconButton/tests/SyIconButton.spec.ts +152 -0
  109. package/src/components/Customs/SyIconButton/tests/__snapshots__/SyIconButton.spec.ts.snap +61 -0
  110. package/src/components/Customs/SyPagination/SyPagination.vue +5 -5
  111. package/src/components/Customs/SyTextField/SyTextField.vue +20 -2
  112. package/src/components/Customs/SyTextField/accessibilite/Accessibility.mdx +67 -9
  113. package/src/components/Customs/SyTextField/tests/SyTextField.a11y.spec.ts +15 -0
  114. package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +36 -0
  115. package/src/components/DataList/accessibilite/Accessibility.mdx +79 -11
  116. package/src/components/DataListGroup/accessibilite/Accessibility.mdx +80 -11
  117. package/src/components/DownloadBtn/tests/DownloadBtn.a11y.spec.ts +25 -0
  118. package/src/components/ErrorPage/ErrorPage.stories.ts +113 -19
  119. package/src/components/ErrorPage/ErrorPage.vue +17 -2
  120. package/src/components/ErrorPage/tests/ErrorPage.a11y.spec.ts +17 -0
  121. package/src/components/ErrorPage/tests/ErrorPage.spec.ts +21 -1
  122. package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +0 -1
  123. package/src/components/ExternalLinks/tests/ExternalLinks.a11y.spec.ts +23 -0
  124. package/src/components/FileList/FileList.stories.ts +51 -1
  125. package/src/components/FileList/UploadItem/UploadItem.vue +13 -6
  126. package/src/components/FileList/UploadItem/locales.ts +3 -12
  127. package/src/components/FileList/accessibilite/Accessibility.mdx +3 -0
  128. package/src/components/FileUpload/FileUpload.vue +2 -1
  129. package/src/components/FileUpload/FileUploadContent.vue +2 -1
  130. package/src/components/FileUpload/tests/FileUpload.spec.ts +47 -0
  131. package/src/components/FileUpload/validateFiles.ts +5 -2
  132. package/src/components/FranceConnectBtn/accessibilite/Accessibility.mdx +62 -9
  133. package/src/components/HeaderBar/HeaderBar.vue +2 -1
  134. package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +2 -1
  135. package/src/components/HeaderNavigationBar/HeaderNavigationBar.vue +2 -1
  136. package/src/components/LunarCalendar/accessibilite/Accessibility.mdx +74 -8
  137. package/src/components/LunarCalendar/tests/LunarCalendar.a11y.spec.ts +163 -0
  138. package/src/components/MaintenancePage/MaintenancePage.vue +1 -1
  139. package/src/components/MaintenancePage/tests/MaintenancePage.spec.ts +4 -5
  140. package/src/components/MaintenancePage/tests/__snapshots__/MaintenancePage.spec.ts.snap +0 -1
  141. package/src/components/MonthPicker/MonthPicker.mdx +35 -0
  142. package/src/components/MonthPicker/MonthPicker.stories.ts +527 -0
  143. package/src/components/MonthPicker/MonthPicker.vue +79 -0
  144. package/src/components/MonthPicker/MonthPickerText/MonthPickerInput.vue +89 -0
  145. package/src/components/MonthPicker/MonthPickerText/useTextField.ts +27 -0
  146. package/src/components/MonthPicker/MonthPickerVisual/MonthPickerVisual.vue +154 -0
  147. package/src/components/MonthPicker/MonthPickerVisual/MonthPickerVisualProps.ts +13 -0
  148. package/src/components/MonthPicker/MonthPickerVisual/MonthSelector.vue +137 -0
  149. package/src/components/MonthPicker/MonthPickerVisual/VisualPickerFooter.vue +60 -0
  150. package/src/components/MonthPicker/MonthPickerVisual/VisualPickerHeader.vue +149 -0
  151. package/src/components/MonthPicker/MonthPickerVisual/YearSelector.vue +143 -0
  152. package/src/components/MonthPicker/MonthPickerVisual/useMonthGrid.ts +45 -0
  153. package/src/components/MonthPicker/MonthPickerVisual/useYearGrid.ts +45 -0
  154. package/src/components/MonthPicker/MonthPickerVisual/utils.ts +17 -0
  155. package/src/components/MonthPicker/accessibilite/Accessibility.mdx +59 -0
  156. package/src/components/MonthPicker/locales.ts +12 -0
  157. package/src/components/MonthPicker/tests/MonthPicker.a11y.spec.ts +71 -0
  158. package/src/components/MonthPicker/tests/MonthPicker.spec.ts +1248 -0
  159. package/src/components/MonthPicker/tests/__snapshots__/MonthPicker.spec.ts.snap +2545 -0
  160. package/src/components/MonthPicker/useMonthPickerValidation.ts +30 -0
  161. package/src/components/NirField/NirField.mdx +1 -2
  162. package/src/components/NirField/NirField.stories.ts +66 -6
  163. package/src/components/NotFoundPage/tests/NotFoundPage.spec.ts +2 -3
  164. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +22 -14
  165. package/src/components/NotificationBar/Notification/Notification.vue +3 -1
  166. package/src/components/NotificationBar/NotificationBar.stories.ts +154 -0
  167. package/src/components/NotificationBar/tests/NotificationBar.a11y.spec.ts +26 -0
  168. package/src/components/NotificationBar/tests/NotificationBar.spec.ts +60 -0
  169. package/src/components/RangeField/accessibilite/Accessibility.mdx +79 -11
  170. package/src/components/SkipLink/tests/SkipLink.a11y.spec.ts +23 -0
  171. package/src/components/StatusPage/StatusPage.stories.ts +118 -0
  172. package/src/components/StatusPage/StatusPage.vue +5 -3
  173. package/src/components/StatusPage/tests/StatusPage.a11y.spec.ts +22 -0
  174. package/src/components/StatusPage/tests/StatusPage.spec.ts +22 -0
  175. package/src/components/StatusPage/tests/__snapshots__/StatusPage.spec.ts.snap +22 -14
  176. package/src/components/SubHeader/tests/SubHeader.a11y.spec.ts +20 -0
  177. package/src/components/SyAlert/SyAlert.vue +1 -0
  178. package/src/components/SyAlert/accessibilite/Accessibility.mdx +79 -9
  179. package/src/components/SyAlert/tests/SyAlert.a11y.spec.ts +23 -0
  180. package/src/components/SyHeading/SyHeading.a11y.test.ts +149 -0
  181. package/src/components/SyHeading/SyHeading.test.ts +115 -0
  182. package/src/components/SyHeading/SyHeading.vue +5 -3
  183. package/src/components/SyTextArea/accessibilite/Accessibility.mdx +80 -8
  184. package/src/components/SyTextArea/tests/SyTextArea.a11y.spec.ts +151 -0
  185. package/src/components/ToolbarContainer/tests/ToolbarContainer.a11y.spec.ts +126 -0
  186. package/src/components/UploadWorkflow/tests/__snapshots__/UploadWorkflow.spec.ts.snap +2 -2
  187. package/src/components/index.ts +1 -0
  188. package/src/composables/useFormFieldErrorHandling.ts +11 -2
  189. package/src/designTokens/tokens/cnam/cnamContextual.ts +6 -1
  190. package/src/main.ts +2 -0
@@ -0,0 +1,23 @@
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 ExternalLinks from '../ExternalLinks.vue'
8
+
9
+ describe('ExternalLinks – accessibility (axe)', () => {
10
+ it('has no obvious axe violations', async () => {
11
+ const wrapper = mount(ExternalLinks, {
12
+ props: {
13
+ items: [
14
+ { text: 'ameli.fr', href: 'https://ameli.fr' },
15
+ { text: 'Legifrance', href: 'https://legifrance.gouv.fr' },
16
+ ],
17
+ },
18
+ })
19
+
20
+ const results = await axe(wrapper.element as HTMLElement)
21
+ assertNoA11yViolations(results, 'ExternalLinks – default state')
22
+ })
23
+ })
@@ -161,6 +161,44 @@ const meta = {
161
161
  },
162
162
  },
163
163
  },
164
+ 'seeLabel': {
165
+ description: 'Label du bouton de prévisualisation',
166
+ control: 'text',
167
+ table: {
168
+ category: 'props',
169
+ type: {
170
+ summary: 'string',
171
+ },
172
+ defaultValue: {
173
+ summary: 'Voir le fichier',
174
+ },
175
+ },
176
+ },
177
+ 'deleteLabel': {
178
+ description: 'Label du bouton de suppression',
179
+ control: 'text',
180
+ table: {
181
+ category: 'props',
182
+ type: { summary: 'string',
183
+ },
184
+ defaultValue: {
185
+ summary: 'Supprimer le fichier',
186
+ },
187
+ },
188
+ },
189
+ 'importLabel': {
190
+ description: 'Label du bouton d\'upload',
191
+ control: 'text',
192
+ table: {
193
+ category: 'props',
194
+ type: {
195
+ summary: 'string',
196
+ },
197
+ defaultValue: {
198
+ summary: 'Importer le fichier',
199
+ },
200
+ },
201
+ },
164
202
  },
165
203
  parameters: {
166
204
  controls: {
@@ -197,6 +235,9 @@ export const Default: Story = {
197
235
  onPreview: fn(),
198
236
  },
199
237
  parameters: {
238
+ a11y: {
239
+ disable: false,
240
+ },
200
241
  sourceCode: [
201
242
  {
202
243
  name: 'Template',
@@ -267,7 +308,7 @@ export const States: Story = {
267
308
  },
268
309
  parameters: {
269
310
  a11y: {
270
- disable: true,
311
+ disable: false,
271
312
  },
272
313
  sourceCode: [
273
314
  {
@@ -339,6 +380,9 @@ export const OptionalDocument: Story = {
339
380
  onPreview: fn(),
340
381
  },
341
382
  parameters: {
383
+ a11y: {
384
+ disable: false,
385
+ },
342
386
  sourceCode: [
343
387
  {
344
388
  name: 'Template',
@@ -415,6 +459,9 @@ export const Actions: Story = {
415
459
  onPreview: fn(),
416
460
  },
417
461
  parameters: {
462
+ a11y: {
463
+ disable: false,
464
+ },
418
465
  sourceCode: [
419
466
  {
420
467
  name: 'Template',
@@ -512,6 +559,9 @@ export const Customization: Story = {
512
559
  `,
513
560
  }),
514
561
  parameters: {
562
+ a11y: {
563
+ disable: false,
564
+ },
515
565
  sourceCode: [
516
566
  {
517
567
  name: 'Template',
@@ -32,6 +32,9 @@
32
32
  showPreviewBtn?: boolean
33
33
  tag?: string
34
34
  locales?: typeof defaultLocales
35
+ seeLabel?: string
36
+ deleteLabel?: string
37
+ importLabel?: string
35
38
  }>(), {
36
39
  fileName: undefined,
37
40
  message: undefined,
@@ -43,6 +46,9 @@
43
46
  showPreviewBtn: false,
44
47
  tag: 'div',
45
48
  locales: () => defaultLocales,
49
+ seeLabel: defaultLocales.see,
50
+ deleteLabel: defaultLocales.delete,
51
+ importLabel: defaultLocales.import,
46
52
  })
47
53
 
48
54
  defineSlots<{
@@ -132,10 +138,10 @@
132
138
  v-if="(state === 'initial' || state == 'error') && showUploadBtn"
133
139
  class="file-item__action file-item__action-upload text-primary"
134
140
  variant="text"
135
- :aria-label="locales.importLabel(title)"
141
+ :aria-label="`${locales.import} ${title}`"
136
142
  @click="$emit('upload', itemId)"
137
143
  >
138
- <span>{{ locales.import }}</span>
144
+ <span>{{ importLabel }}</span>
139
145
  <template #prepend>
140
146
  <SyIcon
141
147
  color="primary"
@@ -148,10 +154,10 @@
148
154
  v-if="state === 'success' && showPreviewBtn"
149
155
  class="file-item__action file-item__action-preview text-primary"
150
156
  variant="text"
151
- :aria-label="locales.seeLabel(title)"
157
+ :aria-label="`${locales.see} ${fileName}`"
152
158
  @click="$emit('preview', itemId)"
153
159
  >
154
- <span>{{ locales.see }}</span>
160
+ <span>{{ seeLabel }}</span>
155
161
  <template #prepend>
156
162
  <SyIcon
157
163
  color="primary"
@@ -164,10 +170,10 @@
164
170
  v-if="state === 'success' && showDeleteBtn"
165
171
  class="file-item__action file-item__action-delete text-error"
166
172
  variant="text"
167
- :aria-label="locales.deleteLabel(title)"
173
+ :aria-label="`${locales.delete} ${fileName}`"
168
174
  @click="$emit('delete', itemId)"
169
175
  >
170
- <span>{{ locales.delete }}</span>
176
+ <span>{{ deleteLabel }}</span>
171
177
  <template #prepend>
172
178
  <SyIcon
173
179
  color="error"
@@ -193,6 +199,7 @@
193
199
  height="7"
194
200
  color="primary"
195
201
  rounded="true"
202
+ :aria-label="title ? `Chargement de ${title}` : 'Chargement en cours'"
196
203
  />
197
204
  </div>
198
205
  </component>
@@ -1,17 +1,8 @@
1
1
  export const locales = {
2
2
  optionalDocument: 'Document facultatif',
3
- import: 'Importer',
4
- see: 'Voir',
5
- delete: 'Supprimer',
6
- importLabel(title: string) {
7
- return `Importer le fichier ${title}`
8
- },
9
- seeLabel(title: string) {
10
- return `Voir le fichier ${title}`
11
- },
12
- deleteLabel(title: string) {
13
- return `Supprimer le fichier ${title}`
14
- },
3
+ see: 'Voir le fichier',
4
+ delete: 'Supprimer le fichier',
5
+ import: 'Importer le fichier',
15
6
  uploading: 'En cours',
16
7
  success: 'Téléchargé',
17
8
  error: 'Erreur',
@@ -21,6 +21,9 @@ import {
21
21
  <ul>
22
22
  <li><strong>Formattage sous forme de liste </strong> : Utilisation de balises HTML sémantiques pour structurer les éléments de la liste de fichiers.</li>
23
23
  <li><strong>Boutons</strong> : Utilisation de <code>&lt;button&gt;</code> pour les actions associées à chaque fichier, avec des étiquettes claires qui reprennent l'action et le nom du fichier.</li>
24
+ <li><strong>Aria-label</strong>: On utilise les méthodes <code>importAriaLabel()</code> pour générer les etiquettes ARIA des champs avec le titre et <code>seeAriaLabel()</code> et <code>deleteAriaLabel()</code> pour les étiquettes ARIA avec le nom du fichier.</li>
25
+ <li><strong>SeeLabel, ImportLabel, DeleteLabel </strong> : Utilisation de ces propriétés pour fournir des étiquettes claires et descriptives pour les actions associées à chaque fichier.</li>
26
+
24
27
  </ul>
25
28
  </CriteriaCard>
26
29
 
@@ -74,7 +74,7 @@
74
74
  files = files.slice(0, 1)
75
75
  }
76
76
  const { errors, validFiles } = validateFiles(
77
- files, props.fileSizeMax, props.allowedExtensions, props.fileSizeUnits,
77
+ files, props.fileSizeMax, props.allowedExtensions, props.fileSizeUnits, props.locales,
78
78
  )
79
79
 
80
80
  if (errors.length) {
@@ -149,6 +149,7 @@
149
149
  :multiple="multiple"
150
150
  :file-size-max="fileSizeMax"
151
151
  :file-size-units="fileSizeUnits"
152
+ :locales="locales"
152
153
  >
153
154
  <template
154
155
  v-for="(_, slotName) in $slots"
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { calcHumanFileSize } from '@/utils/calcHumanFileSize'
3
- import { locales } from './locales'
3
+ import { locales as defaultLocales } from './locales'
4
4
  import { mdiCloudUpload } from '@mdi/js'
5
5
  import { computed } from 'vue'
6
6
  import SyIcon from '@/components/Customs/SyIcon/SyIcon.vue'
@@ -10,6 +10,7 @@
10
10
  fileSizeUnits: Array<string>
11
11
  fileSizeMax: number
12
12
  multiple: boolean
13
+ locales: typeof defaultLocales
13
14
  }>()
14
15
 
15
16
  export interface FileUploadContentSlots {
@@ -268,6 +268,53 @@ describe('FileUpload', () => {
268
268
  expect(wrapper.emitted('error')).toBeFalsy()
269
269
  })
270
270
 
271
+ it('accepts a file whose extension is uppercase (case-insensitive check)', async () => {
272
+ const wrapper = mount(FileUpload, {
273
+ props: {
274
+ modelValue: [],
275
+ allowedExtensions: ['png'],
276
+ },
277
+ })
278
+
279
+ const file: File = new File([''], 'image.PNG', { type: 'image/png' })
280
+
281
+ await wrapper.find('.sy-file-upload').trigger('drop', {
282
+ dataTransfer: { files: [file] },
283
+ })
284
+
285
+ expect(wrapper.emitted('error')).toBeFalsy()
286
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[file]])
287
+ })
288
+
289
+ it('uses custom locales error message when provided', async () => {
290
+ const customLocales = {
291
+ or: 'Ou',
292
+ chooseFile: (multiple: boolean) => multiple ? 'Choisir des fichiers' : 'Choisir un fichier',
293
+ infoText: (max: string, ext: string[]) => `Taille max. : ${max}. Formats : ${ext.join(', ')}`,
294
+ fileSizeUnits: ['o', 'Ko', 'Mo', 'Go', 'To'],
295
+ dropFilesHere: (multiple: boolean) => multiple ? 'Déposer vos fichiers ici' : 'Déposer votre fichier ici',
296
+ errorSize: (fileName: string, max: string) => `Fichier ${fileName} trop lourd. Max : ${max}`,
297
+ errorExtension: () => `Message erreur custom !`,
298
+ fileUploadTitle: '',
299
+ }
300
+
301
+ const wrapper = mount(FileUpload, {
302
+ props: {
303
+ modelValue: [],
304
+ allowedExtensions: ['pdf'],
305
+ locales: customLocales,
306
+ },
307
+ })
308
+
309
+ const file: File = new File([''], 'image.PNG', { type: 'image/png' })
310
+
311
+ await wrapper.find('.sy-file-upload').trigger('drop', {
312
+ dataTransfer: { files: [file] },
313
+ })
314
+
315
+ expect(wrapper.emitted('error')?.[0]).toEqual([['Message erreur custom !']])
316
+ })
317
+
271
318
  it('add the new files to the existing ones when the input changes in multiple mode', async () => {
272
319
  const file1 = new File([''], 'filename1.jpg', { type: 'image/jpeg' })
273
320
  const file2 = new File([''], 'filename2.jpg', { type: 'image/jpeg' })
@@ -1,14 +1,16 @@
1
1
  import { calcHumanFileSize } from '@/utils/calcHumanFileSize'
2
- import { locales } from './locales'
2
+ import { locales as defaultLocales } from './locales'
3
3
 
4
4
  export default function validateFiles(
5
5
  files: File[],
6
6
  maxFileSize: number,
7
7
  allowedExtensions: string[],
8
8
  fileSizeUnits: string[],
9
+ locales: typeof defaultLocales = defaultLocales,
9
10
  ) {
10
11
  const errors: string[] = []
11
12
  const validFiles: File[] = []
13
+ const normalizedExtensions = allowedExtensions.map(ext => ext.toLowerCase())
12
14
  for (const file of files) {
13
15
  let isValid = true
14
16
  if (file.size > maxFileSize) {
@@ -18,8 +20,9 @@ export default function validateFiles(
18
20
  isValid = false
19
21
  }
20
22
 
23
+ const fileExt = (file.name.split('.').pop() || '').toLowerCase()
21
24
  if (
22
- !allowedExtensions.includes(file.name.split('.').pop() || '')
25
+ !normalizedExtensions.includes(fileExt)
23
26
  && allowedExtensions.length > 0
24
27
  ) {
25
28
  errors.push(
@@ -1,15 +1,68 @@
1
- import { Meta, Story } from '@storybook/addon-docs';
1
+ import { Meta, Primary } from '@storybook/blocks';
2
2
  import * as Stories from '../FranceConnectBtn.stories.ts';
3
- import '@/stories/styles/shared.css';
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';
4
12
 
5
13
  <Meta of={Stories} />
6
14
 
7
- <div className="header">
8
- <h1>Accessibilité</h1>
9
- </div>
10
-
11
-
12
- <div class="mt-2">
13
- <p>Rapport d’audit manuel : <a href="/audits/FranceConnectBtn.xlsx" style={{ color:'#0C41BD' }}>Voir le rapport</a></p>
15
+ <AccessibilityGuideLayout
16
+ componentName="FranceConnectBtn"
17
+ iconSrc={AccessibilityIcon}
18
+ apgHref="https://www.w3.org/WAI/ARIA/apg/patterns/button/"
19
+ >
20
+ <div class="mt-8">
21
+ <p>Rapport d’audit manuel : <a href="/audits/FranceConnectBtn.xlsx" style={{ color:'#0C41BD' }}>Voir le rapport</a></p>
14
22
  <p style={{ color: 'grey', fontSize: '14px', marginTop: '0px' }}>Correctifs associés (<a href="https://github.com/assurance-maladie-digital/design-system-v3/issues/4005" target="_blank" style={{color:'#0C41BD'}}>issue #4005</a>)</p>
15
23
  </div>
24
+
25
+ <CriteriaSection>
26
+ <CriteriaCard icon="🔍" title="Structure sémantique et attributs">
27
+ <ul>
28
+ <li><strong>Liens natifs</strong> : Utilisation de balises <code>&lt;a&gt;</code> pour le bouton principal et le lien d'information, garantissant une sémantique correcte.</li>
29
+ <li><strong>Labels explicites</strong> : Utilisation de l'attribut <code>aria-label</code> sur les liens pour fournir une description claire aux lecteurs d'écran (ex: "S'identifier avec FranceConnect" ou "S'identifier avec FranceConnect+").</li>
30
+ <li><strong>SVG masqué</strong> : Le logo SVG complexe est masqué aux technologies d'assistance avec <code>aria-hidden="true"</code> et <code>role="presentation"</code> car l'information est déjà portée par l'attribut <code>aria-label</code> du lien parent.</li>
31
+ <li><strong>Ouverture de fenêtre</strong> : Le lien externe informe l'utilisateur de l'ouverture d'un nouvel onglet, avec une icône explicitement masquée (<code>decorative=true</code>).</li>
32
+ </ul>
33
+ </CriteriaCard>
34
+
35
+ <CriteriaCard icon="⌨️" title="Navigation et interaction clavier">
36
+ <ul>
37
+ <li><strong>Focus natif</strong> : Les liens sont naturellement accessibles via la touche <kbd>Tab</kbd>.</li>
38
+ <li><strong>Indicateur de focus</strong> : Un style de focus clair, visible et avec un décalage (<code>outline-offset</code>) est implémenté pour garantir une bonne visibilité lors de la navigation au clavier.</li>
39
+ </ul>
40
+ </CriteriaCard>
41
+
42
+ <CriteriaCard icon="🎨" title="Styles et contrastes">
43
+ <ul>
44
+ <li><strong>Couleurs institutionnelles</strong> : Respect strict des couleurs et contrastes de la charte FranceConnect (Bleu France), garantissant un ratio de contraste suffisant.</li>
45
+ <li><strong>Adaptation au thème sombre</strong> : Ajustement des couleurs de fond (ex: <code>#8585f6</code>) et de texte en mode sombre pour maintenir la lisibilité et l'accessibilité visuelle.</li>
46
+ </ul>
47
+ </CriteriaCard>
48
+ </CriteriaSection>
49
+
50
+ <DemoSection componentName="FranceConnectBtn">
51
+ <Primary />
52
+ </DemoSection>
53
+
54
+ <BestPracticesSection>
55
+ <ul>
56
+ <li><strong>Positionnement</strong> : Placez toujours ce bouton dans un contexte de connexion ou d'authentification.</li>
57
+ <li><strong>Respect de la charte</strong> : Ne modifiez pas les proportions, les couleurs (en dehors du mode sombre) ou les libellés de ce bouton, car ils sont soumis aux règles strictes de la direction interministérielle du numérique (DINUM).</li>
58
+ <li>Assurez-vous que le lien <code>href</code> fourni pointe vers la véritable interface de redirection d'authentification.</li>
59
+ </ul>
60
+ </BestPracticesSection>
61
+
62
+ <ResourcesSection>
63
+ <ul>
64
+ <li><a href="https://franceconnect.gouv.fr/partenaires" target="_blank" rel="noopener noreferrer">Documentation et charte FranceConnect</a></li>
65
+ <li><a href="https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#6.1" target="_blank" rel="noopener noreferrer">RGAA : Liens et navigation</a></li>
66
+ </ul>
67
+ </ResourcesSection>
68
+ </AccessibilityGuideLayout>
@@ -23,7 +23,7 @@
23
23
  to?: RouteLocationRaw
24
24
  href?: string
25
25
  }
26
- headingLevelTitle: 1 | 2 | 3 | 4 | 5 | 6
26
+ headingLevelTitle?: 1 | 2 | 3 | 4 | 5 | 6
27
27
  }
28
28
 
29
29
  defineSlots<{
@@ -58,6 +58,7 @@
58
58
  serviceSubtitle: undefined,
59
59
  homeLink: undefined,
60
60
  width: '1712px',
61
+ headingLevelTitle: 1,
61
62
  })
62
63
 
63
64
  function registerHeaderMenu(childMenuStatus: DeepReadonly<Ref<boolean>>) {
@@ -17,7 +17,7 @@
17
17
  to?: RouteLocationRaw
18
18
  href?: string
19
19
  }
20
- headingLevelTitle: 1 | 2 | 3 | 4 | 5 | 6
20
+ headingLevelTitle?: 1 | 2 | 3 | 4 | 5 | 6
21
21
  }>(), {
22
22
  ariaLabel: locales.ariaLabel,
23
23
  serviceTitle: undefined,
@@ -25,6 +25,7 @@
25
25
  homeLink: () => ({
26
26
  href: '/',
27
27
  }),
28
+ headingLevelTitle: 1,
28
29
  })
29
30
 
30
31
  defineSlots<{
@@ -41,7 +41,7 @@
41
41
  confirmationMessage?: boolean
42
42
  /** Largeur interne */
43
43
  width?: string
44
- headingLevelTitle: 1 | 2 | 3 | 4 | 5 | 6
44
+ headingLevelTitle?: 1 | 2 | 3 | 4 | 5 | 6
45
45
  }>(),
46
46
  {
47
47
  // Confirmation related defaults
@@ -57,6 +57,7 @@
57
57
  maxHorizontalMenuItems: 6,
58
58
  items: undefined,
59
59
  width: '1712px',
60
+ headingLevelTitle: 1,
60
61
  })
61
62
 
62
63
  // Définition des événements émis
@@ -1,10 +1,76 @@
1
- import { Meta, Story } from '@storybook/addon-docs';
2
- import * as LunarCalendar from '../LunarCalendar.stories';
3
- import '@/stories/styles/shared.css';
1
+ import { Meta, Primary } from '@storybook/blocks';
2
+ import * as Stories from '../LunarCalendar.stories';
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';
4
12
 
5
- <Meta of={LunarCalendar} />
13
+ <Meta of={Stories}/>
6
14
 
7
- <div className="header">
8
- <h1>Accessibilité</h1>
9
- <p>Cette page sera bientôt disponible</p>
10
- </div>
15
+ <AccessibilityGuideLayout
16
+ componentName="LunarCalendar"
17
+ iconSrc={AccessibilityIcon}
18
+ apgHref="https://www.w3.org/WAI/ARIA/apg/patterns/textfield/"
19
+ >
20
+
21
+ <CriteriaSection>
22
+
23
+ <CriteriaCard title="Structure sémantique">
24
+ - **Champ de saisie natif** : Utilise un élément `input` de type texte avec masque de formatage
25
+ - **Label associé** : Le label est correctement associé au champ via le composant SyTextField
26
+ - **Masque de saisie** : Le format `JJ/MM/AAAA` est appliqué via la directive `v-maska`
27
+ - **Icônes décoratives** : Les icônes calendrier sont marquées comme décoratives
28
+ </CriteriaCard>
29
+
30
+ <CriteriaCard title="États et feedback">
31
+ - **Messages d'erreur** : Les erreurs de validation sont annoncées via `aria-describedby`
32
+ - **Messages de succès** : Les confirmations sont également annoncées aux lecteurs d'écran
33
+ - **Champ requis** : L'attribut `required` est correctement appliqué quand nécessaire
34
+ - **Contraintes de dates** : Validation des années min/max avec feedback approprié
35
+ </CriteriaCard>
36
+
37
+ <CriteriaCard title="Navigation au clavier">
38
+ - **Tabulation** : Navigation au clavier standard via le composant SyTextField
39
+ - **Saisie guidée** : Le masque facilite la saisie en indiquant le format attendu
40
+ - **Effacement** : Support du bouton d'effacement quand `isClearable` est activé
41
+ - **Focus visible** : Indication claire du focus pour les utilisateurs clavier
42
+ </CriteriaCard>
43
+
44
+ </CriteriaSection>
45
+
46
+ <DemoSection componentName="LunarCalendar">
47
+ <Primary />
48
+ </DemoSection>
49
+
50
+ ## Bonnes pratiques
51
+
52
+ <BestPracticesSection>
53
+ <ul>
54
+ <li><strong>Label descriptif</strong> : Utiliser un label qui explique clairement qu'il s'agit d'une date lunaire et indiquer le format attendu JJ/MM/AAAA.</li>
55
+ <li><strong>Messages clairs</strong> : Fournir des messages d'erreur qui expliquent le format attendu et les contraintes de validité.</li>
56
+ <li><strong>Contraintes pertinentes</strong> : Définir des plages d'années logiques pour le contexte d'utilisation.</li>
57
+ <li><strong>Feedback immédiat</strong> : Valider dès la perte du focus pour guider l'utilisateur dans sa saisie.</li>
58
+ <li><strong>Placeholder utile</strong> : Utiliser JJ/MM/AAAA comme placeholder pour renforcer le format attendu.</li>
59
+ <li><strong>Icônes appropriées</strong> : Les icônes calendrier aident à identifier visuellement le type de saisie attendue.</li>
60
+ <li><strong>Effacement facilité</strong> : Activer isClearable pour permettre aux utilisateurs de corriger facilement leur saisie.</li>
61
+ </ul>
62
+ </BestPracticesSection>
63
+
64
+ ## Ressources
65
+
66
+ <ResourcesSection>
67
+ <ul>
68
+ <li><a href="https://www.w3.org/WAI/ARIA/apg/patterns/textfield/" target="_blank" rel="noopener noreferrer">WAI-ARIA Authoring Practices - Text Input</a></li>
69
+ <li><a href="https://developer.mozilla.org/fr/docs/Web/HTML/Element/input" target="_blank" rel="noopener noreferrer">MDN Web Docs - input element</a></li>
70
+ <li><a href="https://developer.mozilla.org/fr/docs/Web/Accessibility/ARIA/Roles/textbox_role" target="_blank" rel="noopener noreferrer">MDN Web Docs - ARIA: textbox role</a></li>
71
+ <li><a href="https://www.numerique.gouv.fr/publications/rgaa-accessibilite/#critere-118-champs-de-saisie" target="_blank" rel="noopener noreferrer">RGAA - Critère 11.8 - Champs de saisie</a></li>
72
+ <li><a href="/docs/components-customs-sytextfield--docs" target="_blank" rel="noopener noreferrer">Documentation SyTextField</a></li>
73
+ </ul>
74
+ </ResourcesSection>
75
+
76
+ </AccessibilityGuideLayout>