@cnamts/synapse 0.0.8-alpha → 0.0.10-alpha

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 (156) hide show
  1. package/dist/design-system-v3.d.ts +1152 -127
  2. package/dist/design-system-v3.js +4888 -2605
  3. package/dist/design-system-v3.umd.cjs +1 -1
  4. package/dist/style.css +1 -1
  5. package/package.json +1 -1
  6. package/src/assets/settings.scss +1 -1
  7. package/src/components/ContextualMenu/Accessibilite.mdx +14 -0
  8. package/src/components/ContextualMenu/Accessibilite.stories.ts +191 -0
  9. package/src/components/ContextualMenu/AccessibiliteItems.ts +89 -0
  10. package/src/components/ContextualMenu/constants/ExpertiseLevelEnum.ts +4 -0
  11. package/src/components/Customs/SySelect/SySelect.stories.ts +7 -7
  12. package/src/components/Customs/SySelect/SySelect.vue +9 -4
  13. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +2 -2
  14. package/src/components/Customs/SyTextField/SyTextField.stories.ts +187 -2
  15. package/src/components/Customs/SyTextField/SyTextField.vue +185 -16
  16. package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +2 -4
  17. package/src/components/Customs/SyTextField/tests/__snapshots__/SyTextField.spec.ts.snap +18 -16
  18. package/src/components/Customs/SyTextField/types.d.ts +2 -2
  19. package/src/components/DatePicker/Accessibilite.mdx +14 -0
  20. package/src/components/DatePicker/Accessibilite.stories.ts +191 -0
  21. package/src/components/DatePicker/AccessibiliteItems.ts +233 -0
  22. package/src/components/DatePicker/DatePicker.mdx +186 -0
  23. package/src/components/DatePicker/DatePicker.stories.ts +787 -0
  24. package/src/components/DatePicker/DatePicker.vue +574 -0
  25. package/src/components/DatePicker/DateTextInput.vue +409 -0
  26. package/src/components/DatePicker/constants/ExpertiseLevelEnum.ts +4 -0
  27. package/src/components/DatePicker/tests/DatePicker.spec.ts +266 -0
  28. package/src/components/DialogBox/DialogBox.stories.ts +1 -1
  29. package/src/components/ExternalLinks/Accessibilite.mdx +14 -0
  30. package/src/components/ExternalLinks/Accessibilite.stories.ts +191 -0
  31. package/src/components/ExternalLinks/AccessibiliteItems.ts +197 -0
  32. package/src/components/ExternalLinks/constants/ExpertiseLevelEnum.ts +4 -0
  33. package/src/components/ExternalLinks/tests/__snapshots__/ExternalLinks.spec.ts.snap +9 -9
  34. package/src/components/FileList/FileList.mdx +103 -0
  35. package/src/components/FileList/FileList.stories.ts +562 -0
  36. package/src/components/FileList/FileList.vue +78 -0
  37. package/src/components/FileList/UploadItem/UploadItem.vue +270 -0
  38. package/src/components/FileList/UploadItem/locales.ts +9 -0
  39. package/src/components/FileList/tests/FileList.spec.ts +176 -0
  40. package/src/components/FilePreview/FilePreview.mdx +82 -0
  41. package/src/components/FilePreview/FilePreview.stories.ts +242 -0
  42. package/src/components/FilePreview/FilePreview.vue +68 -0
  43. package/src/components/FilePreview/config.ts +10 -0
  44. package/src/components/FilePreview/locales.ts +4 -0
  45. package/src/components/FilePreview/tests/FilePreview.spec.ts +124 -0
  46. package/src/components/FilePreview/tests/__snapshots__/FilePreview.spec.ts.snap +11 -0
  47. package/src/components/FileUpload/FileUpload.mdx +165 -0
  48. package/src/components/FileUpload/FileUpload.stories.ts +429 -0
  49. package/src/components/FileUpload/FileUpload.vue +195 -0
  50. package/src/components/FileUpload/FileUploadContent.vue +109 -0
  51. package/src/components/FileUpload/locales.ts +10 -0
  52. package/src/components/FileUpload/tests/FileUpload.spec.ts +332 -0
  53. package/src/components/FileUpload/tests/__snapshots__/FileUpload.spec.ts.snap +7 -0
  54. package/src/components/FileUpload/useFileDrop.ts +23 -0
  55. package/src/components/FileUpload/validateFiles.ts +39 -0
  56. package/src/components/NirField/NirField.stories.ts +1 -1
  57. package/src/components/NirField/NirField.vue +2 -1
  58. package/src/components/PasswordField/Accessibilite.mdx +14 -0
  59. package/src/components/PasswordField/Accessibilite.stories.ts +191 -0
  60. package/src/components/PasswordField/AccessibiliteItems.ts +184 -0
  61. package/src/components/PasswordField/PasswordField.vue +3 -3
  62. package/src/components/PasswordField/constants/ExpertiseLevelEnum.ts +4 -0
  63. package/src/components/PeriodField/PeriodField.mdx +32 -0
  64. package/src/components/PeriodField/PeriodField.stories.ts +807 -0
  65. package/src/components/PeriodField/PeriodField.vue +355 -0
  66. package/src/components/PeriodField/tests/PeriodField.spec.ts +348 -0
  67. package/src/components/PhoneField/PhoneField.vue +44 -60
  68. package/src/components/PhoneField/tests/PhoneField.spec.ts +0 -15
  69. package/src/components/RangeField/Accessibilite.mdx +14 -0
  70. package/src/components/RangeField/Accessibilite.stories.ts +191 -0
  71. package/src/components/RangeField/AccessibiliteItems.ts +179 -0
  72. package/src/components/RangeField/RangeField.mdx +54 -0
  73. package/src/components/RangeField/RangeField.stories.ts +189 -0
  74. package/src/components/RangeField/RangeField.vue +157 -0
  75. package/src/components/RangeField/RangeSlider/RangeSlider.vue +387 -0
  76. package/src/components/RangeField/RangeSlider/Tooltip/Tooltip.vue +64 -0
  77. package/src/components/RangeField/RangeSlider/tests/__snapshots__/rangeSlider.spec.ts.snap +27 -0
  78. package/src/components/RangeField/RangeSlider/tests/rangeSlider.spec.ts +100 -0
  79. package/src/components/RangeField/RangeSlider/tests/useDoubleSlider.spec.ts +246 -0
  80. package/src/components/RangeField/RangeSlider/tests/useMouseSlide.spec.ts +204 -0
  81. package/src/components/RangeField/RangeSlider/tests/useThumb.spec.ts +22 -0
  82. package/src/components/RangeField/RangeSlider/tests/useThumbKeyboard.spec.ts +233 -0
  83. package/src/components/RangeField/RangeSlider/tests/useTooltipsNudge.spec.ts +150 -0
  84. package/src/components/RangeField/RangeSlider/tests/useTrack.spec.ts +314 -0
  85. package/src/components/RangeField/RangeSlider/tests/vAnimateClick.spec.ts +32 -0
  86. package/src/components/RangeField/RangeSlider/types.ts +15 -0
  87. package/src/components/RangeField/RangeSlider/useMouseSlide.ts +109 -0
  88. package/src/components/RangeField/RangeSlider/useRangeSlider.ts +126 -0
  89. package/src/components/RangeField/RangeSlider/useThumb.ts +18 -0
  90. package/src/components/RangeField/RangeSlider/useThumbKeyboard.ts +84 -0
  91. package/src/components/RangeField/RangeSlider/useTooltipsNudge.ts +92 -0
  92. package/src/components/RangeField/RangeSlider/useTrack.ts +116 -0
  93. package/src/components/RangeField/RangeSlider/vAnimateClick.ts +19 -0
  94. package/src/components/RangeField/config.ts +7 -0
  95. package/src/components/RangeField/constants/ExpertiseLevelEnum.ts +4 -0
  96. package/src/components/RangeField/locales.ts +4 -0
  97. package/src/components/RangeField/tests/RangeField.spec.ts +224 -0
  98. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +379 -0
  99. package/src/components/RatingPicker/Accessibilite.mdx +14 -0
  100. package/src/components/RatingPicker/Accessibilite.stories.ts +191 -0
  101. package/src/components/RatingPicker/AccessibiliteItems.ts +208 -0
  102. package/src/components/RatingPicker/EmotionPicker/EmotionPicker.vue +205 -0
  103. package/src/components/RatingPicker/EmotionPicker/locales.ts +3 -0
  104. package/src/components/RatingPicker/EmotionPicker/tests/EmotionPicker.spec.ts +104 -0
  105. package/src/components/RatingPicker/EmotionPicker/tests/__snapshots__/EmotionPicker.spec.ts.snap +66 -0
  106. package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +159 -0
  107. package/src/components/RatingPicker/NumberPicker/locales.ts +4 -0
  108. package/src/components/RatingPicker/NumberPicker/tests/NumberPicker.spec.ts +73 -0
  109. package/src/components/RatingPicker/NumberPicker/tests/__snapshots__/NumberPicker.spec.ts.snap +105 -0
  110. package/src/components/RatingPicker/Rating.ts +45 -0
  111. package/src/components/RatingPicker/RatingPicker.mdx +56 -0
  112. package/src/components/RatingPicker/RatingPicker.stories.ts +515 -0
  113. package/src/components/RatingPicker/RatingPicker.vue +122 -0
  114. package/src/components/RatingPicker/StarsPicker/StarsPicker.vue +116 -0
  115. package/src/components/RatingPicker/StarsPicker/tests/StarsPicker.spec.ts +95 -0
  116. package/src/components/RatingPicker/StarsPicker/tests/__snapshots__/StarsPicker.spec.ts.snap +36 -0
  117. package/src/components/RatingPicker/constants/ExpertiseLevelEnum.ts +4 -0
  118. package/src/components/RatingPicker/locales.ts +3 -0
  119. package/src/components/RatingPicker/tests/Rating.spec.ts +104 -0
  120. package/src/components/RatingPicker/tests/RatingPicker.spec.ts +187 -0
  121. package/src/components/RatingPicker/tests/__snapshots__/RatingPicker.spec.ts.snap +108 -0
  122. package/src/components/SearchListField/Accessibilite.mdx +14 -0
  123. package/src/components/SearchListField/Accessibilite.stories.ts +191 -0
  124. package/src/components/SearchListField/AccessibiliteItems.ts +310 -0
  125. package/src/components/SearchListField/SearchListField.mdx +74 -0
  126. package/src/components/SearchListField/SearchListField.stories.ts +126 -0
  127. package/src/components/SearchListField/SearchListField.vue +194 -0
  128. package/src/components/SearchListField/constants/ExpertiseLevelEnum.ts +4 -0
  129. package/src/components/SearchListField/locales.ts +5 -0
  130. package/src/components/SearchListField/tests/SearchListField.spec.ts +323 -0
  131. package/src/components/SearchListField/types.d.ts +4 -0
  132. package/src/components/SelectBtnField/Accessibilite.mdx +14 -0
  133. package/src/components/SelectBtnField/Accessibilite.stories.ts +191 -0
  134. package/src/components/SelectBtnField/AccessibiliteItems.ts +191 -0
  135. package/src/components/SelectBtnField/SelectBtnField.mdx +50 -0
  136. package/src/components/SelectBtnField/SelectBtnField.stories.ts +763 -0
  137. package/src/components/SelectBtnField/SelectBtnField.vue +283 -0
  138. package/src/components/SelectBtnField/config.ts +11 -0
  139. package/src/components/SelectBtnField/constants/ExpertiseLevelEnum.ts +4 -0
  140. package/src/components/SelectBtnField/tests/SelectBtnField.spec.ts +327 -0
  141. package/src/components/SelectBtnField/tests/__snapshots__/SelectBtnField.spec.ts.snap +125 -0
  142. package/src/components/SelectBtnField/types.d.ts +11 -0
  143. package/src/components/SyAlert/SyAlert.vue +11 -9
  144. package/src/components/TableToolbar/TableToolbar.mdx +130 -0
  145. package/src/components/TableToolbar/TableToolbar.stories.ts +935 -0
  146. package/src/components/TableToolbar/TableToolbar.vue +168 -0
  147. package/src/components/TableToolbar/config.ts +24 -0
  148. package/src/components/TableToolbar/locales.ts +6 -0
  149. package/src/components/TableToolbar/tests/TableToolbar.spec.ts +166 -0
  150. package/src/components/TableToolbar/tests/__snapshots__/TableToolbar.spec.ts.snap +359 -0
  151. package/src/components/index.ts +11 -1
  152. package/src/composables/rules/useFieldValidation.ts +174 -44
  153. package/src/designTokens/index.ts +3 -3
  154. package/src/stories/Fondamentaux/CustomisationEtThemes.mdx +52 -2
  155. package/src/utils/calcHumanFileSize/index.ts +12 -0
  156. package/src/utils/calcHumanFileSize/tests/calcHumanFileSize.spec.ts +21 -0
@@ -0,0 +1,10 @@
1
+ export const locales = {
2
+ or: 'Ou',
3
+ chooseFile: (multiple: boolean) => multiple ? 'Choisir des fichiers' : 'Choisir un fichier',
4
+ infoText: (max: string, ext: string[]): string =>
5
+ `Taille max. : ${max}. ${ext.length === 1 ? 'Format accepté' : 'Formats acceptés'} : ${ext.join(', ')}`,
6
+ fileSizeUnits: ['o', 'Ko', 'Mo', 'Go', 'To'],
7
+ dropFilesHere: (multiple: boolean): string => (!multiple ? 'Déposer votre fichier ici' : 'Déposer vos fichiers ici'),
8
+ errorSize: (fileName: string, max: string): string => `Le fichier ${fileName} est trop volumineux. Taille max. : ${max}`,
9
+ errorExtension: (fileName: string, ext: string[]): string => `Le fichier ${fileName} a une extension invalide. Extensions acceptées : ${ext.join(', ')}`,
10
+ }
@@ -0,0 +1,332 @@
1
+ import { vuetify } from '@tests/unit/setup'
2
+ import { mount } from '@vue/test-utils'
3
+ import { afterEach, describe, expect, it, vi } from 'vitest'
4
+ import FileUpload from '../FileUpload.vue'
5
+
6
+ const file: File = new File([''], 'filename', { type: 'text/html' })
7
+
8
+ describe('FileUpload', () => {
9
+ const consoleMock = vi
10
+ .spyOn(console, 'warn')
11
+ .mockImplementation(() => undefined)
12
+
13
+ afterEach(() => {
14
+ consoleMock.mockReset()
15
+ })
16
+
17
+ it('renders correctly', () => {
18
+ const wrapper = mount(FileUpload, {
19
+ global: {
20
+ plugins: [vuetify],
21
+ },
22
+ })
23
+
24
+ expect(wrapper.text()).toMatchSnapshot()
25
+ })
26
+
27
+ it('renders correctly in multiple mode', () => {
28
+ const wrapper = mount(FileUpload, {
29
+ global: {
30
+ plugins: [vuetify],
31
+ },
32
+ propsData: {
33
+ multiple: true,
34
+ modelValue: [file, file],
35
+ },
36
+ })
37
+
38
+ expect(wrapper.text()).toMatchSnapshot()
39
+ })
40
+
41
+ it('renders correctly with only one extension allowed', () => {
42
+ const wrapper = mount(FileUpload, {
43
+ global: {
44
+ plugins: [vuetify],
45
+ },
46
+ propsData: {
47
+ allowedExtensions: ['pdf'],
48
+ modelValue: [file],
49
+ },
50
+ })
51
+
52
+ expect(wrapper.text()).toMatchSnapshot()
53
+ })
54
+
55
+ it('change the style when dragging', async () => {
56
+ const wrapper = mount(FileUpload, {
57
+ global: {
58
+ plugins: [vuetify],
59
+ },
60
+ })
61
+
62
+ const label = wrapper.find('label')
63
+ const labelClasses = label.classes()
64
+
65
+ await wrapper.find('input').trigger('dragover')
66
+ expect(label.classes()).not.toEqual(labelClasses)
67
+
68
+ await wrapper.find('input').trigger('dragleave')
69
+ expect(label.classes()).toEqual(labelClasses)
70
+ })
71
+
72
+ it('accepts the drop of a file with the correct extension', async () => {
73
+ const wrapper = mount(FileUpload, {
74
+ global: {
75
+ plugins: [vuetify],
76
+ },
77
+ props: {
78
+ modelValue: [],
79
+ allowedExtensions: ['pdf'],
80
+ },
81
+ })
82
+
83
+ const file: File = new File([''], 'filename.pdf', { type: 'application/pdf' })
84
+
85
+ await wrapper.find('input').trigger('drop', {
86
+ dataTransfer: {
87
+ files: [file],
88
+ },
89
+ })
90
+
91
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy()
92
+ expect(wrapper.emitted('error')).toBeFalsy()
93
+ })
94
+
95
+ it('accepts the drop of many files', async () => {
96
+ const wrapper = mount(FileUpload, {
97
+ global: {
98
+ plugins: [vuetify],
99
+ },
100
+ props: {
101
+ modelValue: [],
102
+ multiple: true,
103
+ allowedExtensions: ['pdf'],
104
+ },
105
+ })
106
+
107
+ const file: File = new File([''], 'filename.pdf', { type: 'application/pdf' })
108
+
109
+ await wrapper.find('label').trigger('drop', {
110
+ dataTransfer: {
111
+ files: [file],
112
+ },
113
+ })
114
+
115
+ await wrapper.find('label').trigger('drop', {
116
+ dataTransfer: {
117
+ files: [file, file],
118
+ },
119
+ })
120
+
121
+ expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual([[file, file, file]])
122
+ expect(wrapper.emitted('error')).toBeFalsy()
123
+ })
124
+
125
+ it('rejects the drop of a file with the wrong extension', async () => {
126
+ const wrapper = mount(FileUpload, {
127
+ global: {
128
+ plugins: [vuetify],
129
+ },
130
+ props: {
131
+ modelValue: [],
132
+ allowedExtensions: ['pdf'],
133
+ },
134
+ })
135
+
136
+ const file: File = new File([''], 'filename.jpg', { type: 'image/jpeg' })
137
+
138
+ await wrapper.find('input').trigger('drop', {
139
+ dataTransfer: {
140
+ files: [file],
141
+ },
142
+ })
143
+
144
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[]])
145
+ expect(wrapper.emitted('error')?.[0]).toEqual([['Le fichier filename.jpg a une extension invalide. Extensions acceptées : pdf']])
146
+ })
147
+
148
+ it('rejects the drop of a file with the wrong extension in multiple mode', async () => {
149
+ const pdfFile: File = new File([''], 'filename.pdf', { type: 'application/pdf' })
150
+ const jpgFile: File = new File([''], 'filename.jpg', { type: 'image/jpeg' })
151
+
152
+ const wrapper = mount(FileUpload, {
153
+ global: {
154
+ plugins: [vuetify],
155
+ },
156
+ props: {
157
+ multiple: true,
158
+ modelValue: [pdfFile],
159
+ allowedExtensions: ['pdf'],
160
+ },
161
+ })
162
+
163
+ await wrapper.find('label').trigger('drop', {
164
+ dataTransfer: {
165
+ files: [jpgFile],
166
+ },
167
+ })
168
+
169
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[pdfFile]])
170
+ expect(wrapper.emitted('error')?.[0]).toEqual([['Le fichier filename.jpg a une extension invalide. Extensions acceptées : pdf']])
171
+
172
+ await wrapper.find('label').trigger('drop', {
173
+ dataTransfer: {
174
+ files: [pdfFile],
175
+ },
176
+ })
177
+
178
+ expect(wrapper.emitted('error')?.[1]).toBeFalsy()
179
+ expect(wrapper.emitted('update:modelValue')?.[1]).toEqual([[pdfFile, pdfFile]])
180
+ })
181
+
182
+ it('rejects the drop of a file that is too big', async () => {
183
+ const wrapper = mount(FileUpload, {
184
+ global: {
185
+ plugins: [vuetify],
186
+ },
187
+ props: {
188
+ modelValue: [],
189
+ fileSizeMax: 1,
190
+ },
191
+ })
192
+
193
+ const file: File = new File(['42'], 'filename.jpg', { type: 'image/jpeg' })
194
+
195
+ await wrapper.find('label').trigger('drop', {
196
+ dataTransfer: {
197
+ files: [file],
198
+ },
199
+ })
200
+
201
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[]])
202
+ expect(wrapper.emitted('error')?.[0]).toEqual([['Le fichier filename.jpg est trop volumineux. Taille max. : 1 o']])
203
+ })
204
+
205
+ it('do nothing if no file is dropped', async () => {
206
+ const wrapper = mount(FileUpload, {
207
+ global: {
208
+ plugins: [vuetify],
209
+ },
210
+ props: {
211
+ modelValue: [],
212
+ },
213
+ })
214
+
215
+ await wrapper.find('label').trigger('drop', {
216
+ dataTransfer: {
217
+ files: [],
218
+ },
219
+ })
220
+
221
+ expect(wrapper.emitted('update:modelValue')).toBeFalsy()
222
+ expect(wrapper.emitted('error')).toBeFalsy()
223
+ })
224
+
225
+ it('allow any extension if allowedExtensions is empty', async () => {
226
+ const wrapper = mount(FileUpload, {
227
+ global: {
228
+ plugins: [vuetify],
229
+ },
230
+ props: {
231
+ modelValue: [],
232
+ allowedExtensions: [],
233
+ },
234
+ })
235
+
236
+ const file: File = new File([''], 'filename.xyz', { type: 'unknown' })
237
+
238
+ await wrapper.find('label').trigger('drop', {
239
+ dataTransfer: {
240
+ files: [file],
241
+ },
242
+ })
243
+
244
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[file]])
245
+ expect(wrapper.emitted('error')).toBeFalsy()
246
+ })
247
+
248
+ it('do nothing if the field is disabled', async () => {
249
+ const wrapper = mount(FileUpload, {
250
+ global: {
251
+ plugins: [vuetify],
252
+ },
253
+ props: {
254
+ modelValue: [],
255
+ disabled: true,
256
+ },
257
+ })
258
+
259
+ await wrapper.find('label').trigger('drop', {
260
+ dataTransfer: {
261
+ files: [file],
262
+ },
263
+ })
264
+
265
+ expect(wrapper.emitted('update:modelValue')).toBeFalsy()
266
+ expect(wrapper.emitted('error')).toBeFalsy()
267
+ })
268
+
269
+ it('if many files are dropped in single mode, only the first one is kept', async () => {
270
+ const wrapper = mount(FileUpload, {
271
+ global: {
272
+ plugins: [vuetify],
273
+ },
274
+ props: {
275
+ modelValue: [],
276
+ },
277
+ })
278
+
279
+ const file1: File = new File([''], 'filename1.jpg', { type: 'image/jpeg' })
280
+ const file2: File = new File([''], 'filename2.jpg', { type: 'image/jpeg' })
281
+
282
+ await wrapper.find('label').trigger('drop', {
283
+ dataTransfer: {
284
+ files: [file1, file2],
285
+ },
286
+ })
287
+
288
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[file1]])
289
+ expect(wrapper.emitted('error')).toBeFalsy()
290
+ })
291
+
292
+ it('update the field when the input changes', async () => {
293
+ const file1 = new File([''], 'filename1.jpg', { type: 'image/jpeg' })
294
+ const file2 = new File([''], 'filename2.jpg', { type: 'image/jpeg' })
295
+ const wrapper = mount(FileUpload, {
296
+ global: {
297
+ plugins: [vuetify],
298
+ },
299
+ props: {
300
+ modelValue: [file1],
301
+ },
302
+ })
303
+
304
+ const input = wrapper.find('input')
305
+ input.element.files = [file2] as unknown as FileList
306
+ await input.trigger('change')
307
+
308
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[file2]])
309
+ expect(wrapper.emitted('error')).toBeFalsy()
310
+ })
311
+
312
+ it('add the new files to the existing ones when the input changes in multiple mode', async () => {
313
+ const file1 = new File([''], 'filename1.jpg', { type: 'image/jpeg' })
314
+ const file2 = new File([''], 'filename2.jpg', { type: 'image/jpeg' })
315
+ const wrapper = mount(FileUpload, {
316
+ global: {
317
+ plugins: [vuetify],
318
+ },
319
+ props: {
320
+ modelValue: [file1],
321
+ multiple: true,
322
+ },
323
+ })
324
+
325
+ const input = wrapper.find('input')
326
+ input.element.files = [file2] as unknown as FileList
327
+ await input.trigger('change')
328
+
329
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([[file1, file2]])
330
+ expect(wrapper.emitted('error')).toBeFalsy()
331
+ })
332
+ })
@@ -0,0 +1,7 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`FileUpload > renders correctly 1`] = `"Déposer votre fichier iciOuChoisir un fichierTaille max. : 10 Mo. Formats acceptés : pdf, jpg, jpeg, png"`;
4
+
5
+ exports[`FileUpload > renders correctly in multiple mode 1`] = `"Déposer vos fichiers iciOuChoisir des fichiersTaille max. : 10 Mo. Formats acceptés : pdf, jpg, jpeg, png"`;
6
+
7
+ exports[`FileUpload > renders correctly with only one extension allowed 1`] = `"Déposer votre fichier iciOuChoisir un fichierTaille max. : 10 Mo. Format accepté : pdf"`;
@@ -0,0 +1,23 @@
1
+ import { onMounted, toValue, type MaybeRef } from 'vue'
2
+
3
+ export default function useFileDrop(
4
+ dropZone: MaybeRef<HTMLElement | null>,
5
+ callback: (files: File[]) => void,
6
+ ) {
7
+ onMounted(() => {
8
+ const inputEl = toValue(dropZone)
9
+
10
+ if (!inputEl) return
11
+
12
+ inputEl.addEventListener('drop', (e) => {
13
+ e.preventDefault()
14
+ e.stopPropagation()
15
+
16
+ const droppedFiles = e.dataTransfer?.files
17
+
18
+ if (!droppedFiles?.length) return
19
+
20
+ callback(Array.from(droppedFiles))
21
+ })
22
+ })
23
+ }
@@ -0,0 +1,39 @@
1
+ import { calcHumanFileSize } from '@/utils/calcHumanFileSize'
2
+ import { locales } from './locales'
3
+
4
+ export default function validateFiles(
5
+ files: File[],
6
+ maxFileSize: number,
7
+ allowedExtensions: string[],
8
+ fileSizeUnits: string[],
9
+ ) {
10
+ const errors: string[] = []
11
+ const validFiles: File[] = []
12
+ for (const file of files) {
13
+ let isValid = true
14
+ if (file.size > maxFileSize) {
15
+ errors.push(
16
+ locales.errorSize(file.name, calcHumanFileSize(maxFileSize, fileSizeUnits)),
17
+ )
18
+ isValid = false
19
+ }
20
+
21
+ if (
22
+ !allowedExtensions.includes(file.name.split('.').pop() || '')
23
+ && allowedExtensions.length > 0
24
+ ) {
25
+ errors.push(
26
+ locales.errorExtension(file.name, allowedExtensions),
27
+ )
28
+ isValid = false
29
+ }
30
+
31
+ if (isValid) {
32
+ validFiles.push(file)
33
+ }
34
+ }
35
+ return {
36
+ errors,
37
+ validFiles,
38
+ }
39
+ }
@@ -1,7 +1,7 @@
1
1
  import type { StoryObj, Meta } from '@storybook/vue3'
2
2
  import NirField from './NirField.vue'
3
3
 
4
- const meta = {
4
+ const meta: Meta<typeof NirField> = {
5
5
  title: 'Composants/Formulaires/NirField',
6
6
  component: NirField,
7
7
  decorators: [
@@ -233,7 +233,7 @@
233
233
 
234
234
  function validateOnSubmit() {
235
235
  isValidating.value = true
236
- validateFields()
236
+ validateFields(true)
237
237
  return errors.value.length === 0
238
238
  }
239
239
 
@@ -372,6 +372,7 @@
372
372
  .vd-key-field {
373
373
  width: 104px;
374
374
  flex: none;
375
+ margin-left: 2%;
375
376
  }
376
377
 
377
378
  .custom-counter {
@@ -0,0 +1,14 @@
1
+ import { Meta, Story } from '@storybook/addon-docs';
2
+ import * as AccessStories from './Accessibilite.stories.ts';
3
+
4
+ <Meta of={AccessStories} />
5
+
6
+ Accessibilité
7
+ =============
8
+ <Story of={AccessStories.Legende} />
9
+ <br />
10
+
11
+ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12
+
13
+ <Story of={AccessStories.AccessibilitePanel} />
14
+ <br />
@@ -0,0 +1,191 @@
1
+ import { VExpansionPanels, VExpansionPanel, VExpansionPanelTitle, VExpansionPanelText, VDataTable, VIcon } from 'vuetify/components'
2
+ import type { StoryObj } from '@storybook/vue3'
3
+ import { AccessibiliteItemsIndeterminate, AccessibiliteItemsValidated } from './AccessibiliteItems'
4
+ import { mdiCheckboxMarkedCircle, mdiLink, mdiEye } from '@mdi/js'
5
+
6
+ const checkIcon = mdiCheckboxMarkedCircle
7
+ const iconEye = mdiEye
8
+ const linkICon = mdiLink
9
+
10
+ export default {
11
+ title: 'Composants/Formulaires/PasswordField/Accessibilité',
12
+ }
13
+
14
+ export const AccessibilitePanel: StoryObj = {
15
+
16
+ render: () => {
17
+ return {
18
+ components: { VExpansionPanels, VExpansionPanel, VExpansionPanelTitle, VExpansionPanelText, VDataTable, VIcon },
19
+
20
+ setup() {
21
+ const icon = checkIcon
22
+
23
+ return { AccessibiliteItemsIndeterminate, AccessibiliteItemsValidated, icon, linkICon, iconEye }
24
+ },
25
+ template: `
26
+ <div class="accessibiliteItems" style="display:flex; max-width: none !important;">
27
+ <v-col cols="6">
28
+ <div style="display:flex; margin-bottom: 10px; justify-content: space-between; align-items: center;">
29
+ <h5>{{ AccessibiliteItemsIndeterminate.length }} critères à prendre en charge par le projet</h5>
30
+ <div style="display: flex; align-items: center;">
31
+ <v-btn variant="tonal" color="red" size="x-small" style="margin: 4px;font-size: 8px;"
32
+ rounded>Tanaguru
33
+ </v-btn>
34
+ </div>
35
+ </div>
36
+
37
+ <v-expansion-panels value="opened" multiple>
38
+ <v-expansion-panel v-for="(item, index) in AccessibiliteItemsIndeterminate" :key="index" style="background-color: rgba(42, 96, 158, 0.1); margin-bottom: 10px;">
39
+ <v-expansion-panel-title>
40
+ <VIcon :icon="iconEye" style="margin-right: 5px; color:#5778b7;"/>
41
+ {{ item.title }}
42
+ </v-expansion-panel-title>
43
+ <v-expansion-panel-text>
44
+ <v-expansion-panels>
45
+ <v-expansion-panel v-for="(i, index) in item.items2" :key="i" style="margin-bottom: 10px;">
46
+ <v-expansion-panel-title
47
+ style="font-weight: bold; font-size: 13px; line-height: 16px;">
48
+ {{ i.subtitle}}
49
+ </v-expansion-panel-title>
50
+ <v-expansion-panel-text>
51
+ <div>
52
+ <p style="font-size: 13px;line-height: 16px;">
53
+ {{ i.precision }}
54
+ </p>
55
+ <div v-for="(value, index) in i.solution"
56
+ style="margin-top:15px; font-size: 13px;line-height: 16px;">
57
+ <p style="font-weight: bold;">Méthodologie du test : <a
58
+ href="{{i.link}}" target="blank">
59
+ <VIcon :icon="linkICon"/>
60
+ </a></p>
61
+ <p>{{ value.info1 }}</p>
62
+ <p>{{ value.info2 }}</p>
63
+ <p>{{ value.info3 }}</p>
64
+ <p>{{ value.info4 }}</p>
65
+
66
+ </div>
67
+ <span style="display:flex; justify-content:center; margin-bottom:5px;">______</span>
68
+ </div>
69
+ </v-expansion-panel-text>
70
+ </v-expansion-panel>
71
+ <v-expansion-panel >
72
+ <v-expansion-panel-title
73
+ style="font-weight: bold; font-size: 13px; line-height: 16px;">
74
+ {{ item.subtitle }}
75
+ </v-expansion-panel-title>
76
+ <v-expansion-panel-text>
77
+ <div v-for="(value, i) in item.items" :key="i">
78
+ <p style="font-size: 13px;line-height: 16px;">
79
+ {{ value.precision }}
80
+ </p>
81
+ <div v-for="element in value.solution"
82
+ style="margin-top:15px; font-size: 13px;line-height: 16px;">
83
+ <p style="font-weight: bold;">Méthodologie du test : <a
84
+ href="value.link" target="blank">
85
+ <VIcon :icon="linkICon"/>
86
+ </a></p>
87
+ <p>{{ element.info1 }}</p>
88
+ <p>{{ element.info2 }}</p>
89
+ <p>{{ element.info3 }}</p>
90
+ </div>
91
+ <span style="display:flex; justify-content:center; margin-bottom:5px;">______</span>
92
+ </div>
93
+ </v-expansion-panel-text>
94
+ </v-expansion-panel>
95
+ </v-expansion-panels>
96
+ </v-expansion-panel-text>
97
+ </v-expansion-panel>
98
+ </v-expansion-panels>
99
+ </v-col>
100
+ <v-col cols="6">
101
+ <div style="display:flex; margin-bottom: 10px; justify-content: space-between; align-items: center;">
102
+ <h5>{{ AccessibiliteItemsValidated.length }} critères pris en charge par l'équipe Design System</h5>
103
+ <div style="display: flex; align-items: center;">
104
+ <v-btn variant="tonal" color="red" size="x-small" style="margin: 4px;font-size: 8px;"
105
+ rounded>Tanaguru
106
+ </v-btn>
107
+ </div>
108
+ </div>
109
+ <v-expansion-panels v-if="AccessibiliteItemsValidated.length > 0" value="opened" multiple>
110
+ <v-expansion-panel
111
+ v-for="(item, index) in AccessibiliteItemsValidated"
112
+ :key="index" style="background-color: rgba(53,135,0,0.1); margin-bottom: 10px;">
113
+ <v-expansion-panel-title>
114
+ <VIcon color="green" :icon="icon" style="margin-right: 5px;"/>
115
+ {{ item.title }}
116
+ </v-expansion-panel-title>
117
+ <v-expansion-panel-text>
118
+ <v-expansion-panels>
119
+ <v-expansion-panel>
120
+ <v-expansion-panel-title style="font-weight: bold;font-size: 13px; line-height: 16px;">
121
+ {{ item.subtitle }}
122
+ </v-expansion-panel-title>
123
+ <v-expansion-panel-text>
124
+ <div v-for="(value, i) in item.items" :key="i">
125
+ <p style="font-size: 13px;line-height: 16px;">
126
+ {{ value.precision }}
127
+ </p>
128
+ <div v-for="element in value.solution"
129
+ style="margin-top:15px; font-size: 13px;line-height: 16px;">
130
+ <p style="font-weight: bold;">Méthodologie du test : <a
131
+ href="value.link" target="blank">
132
+ <VIcon :icon="linkICon"/>
133
+ </a></p>
134
+ <p>{{ element.info1 }}</p>
135
+ <p>{{ element.info2 }}</p>
136
+ <p>{{ element.info3 }}</p>
137
+ </div>
138
+ <span style="display:flex; justify-content:center; margin-bottom:5px;">______</span>
139
+ </div>
140
+ </v-expansion-panel-text>
141
+ </v-expansion-panel>
142
+ </v-expansion-panels>
143
+ </v-expansion-panel-text>
144
+ </v-expansion-panel>
145
+ </v-expansion-panels>
146
+ <div v-else style="display: flex;justify-content: center;"><span style="text-align:center;" >Pas de critère d'accessibilité bloquant</span></div>
147
+ </v-col>
148
+ </div>
149
+ `,
150
+ }
151
+ },
152
+ tags: ['!dev'],
153
+ }
154
+
155
+ export const Legende: StoryObj = {
156
+ args: {
157
+ icon: checkIcon,
158
+ },
159
+ render: (args) => {
160
+ return {
161
+ components: { VIcon },
162
+ setup() {
163
+ return { args }
164
+ },
165
+ template: `
166
+ <p style="color: grey;font-size: 11px; margin-bottom: 12px;">Date de conception: 20/11/2024</p>
167
+ <div>
168
+ <p>Le tableau ci-dessous liste nos recommandations suivant les <a target="blank" style="color:#0C41BD;" href="https://www.numerique.gouv.fr/publications/rgaa-accessibilite/#contenu">catégories du RGAA</a>.</p>
169
+ <p style="margin-bottom: 12px;font-weight:bold;">Pour rappel le composant seul ne garantie pas
170
+ l'accessibilité du site.</p>
171
+ <div style="font-size: 14px">
172
+ <p>Nous avons deux façons de relever les problèmes d'accessibilité des composants :</p>
173
+ <div>
174
+ <v-btn variant="tonal" color="grey" size="x-small" style="margin: 2px;font-size: 8px;" rounded>
175
+ Audit
176
+ </v-btn>
177
+ Problèmes relevés par le projet
178
+ </div>
179
+ <div>
180
+ <v-btn variant="tonal" color="red" size="x-small" style="margin: 2px;font-size: 8px;" rounded>
181
+ Tanaguru
182
+ </v-btn>
183
+ Problèmes relevés par Tanaguru
184
+ </div>
185
+ </div>
186
+ </div>
187
+ `,
188
+ }
189
+ },
190
+ tags: ['!dev'],
191
+ }