@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.
- package/dist/design-system-v3.d.ts +1152 -127
- package/dist/design-system-v3.js +4888 -2605
- package/dist/design-system-v3.umd.cjs +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/assets/settings.scss +1 -1
- package/src/components/ContextualMenu/Accessibilite.mdx +14 -0
- package/src/components/ContextualMenu/Accessibilite.stories.ts +191 -0
- package/src/components/ContextualMenu/AccessibiliteItems.ts +89 -0
- package/src/components/ContextualMenu/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/Customs/SySelect/SySelect.stories.ts +7 -7
- package/src/components/Customs/SySelect/SySelect.vue +9 -4
- package/src/components/Customs/SySelect/tests/SySelect.spec.ts +2 -2
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +187 -2
- package/src/components/Customs/SyTextField/SyTextField.vue +185 -16
- package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +2 -4
- package/src/components/Customs/SyTextField/tests/__snapshots__/SyTextField.spec.ts.snap +18 -16
- package/src/components/Customs/SyTextField/types.d.ts +2 -2
- package/src/components/DatePicker/Accessibilite.mdx +14 -0
- package/src/components/DatePicker/Accessibilite.stories.ts +191 -0
- package/src/components/DatePicker/AccessibiliteItems.ts +233 -0
- package/src/components/DatePicker/DatePicker.mdx +186 -0
- package/src/components/DatePicker/DatePicker.stories.ts +787 -0
- package/src/components/DatePicker/DatePicker.vue +574 -0
- package/src/components/DatePicker/DateTextInput.vue +409 -0
- package/src/components/DatePicker/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/DatePicker/tests/DatePicker.spec.ts +266 -0
- package/src/components/DialogBox/DialogBox.stories.ts +1 -1
- package/src/components/ExternalLinks/Accessibilite.mdx +14 -0
- package/src/components/ExternalLinks/Accessibilite.stories.ts +191 -0
- package/src/components/ExternalLinks/AccessibiliteItems.ts +197 -0
- package/src/components/ExternalLinks/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/ExternalLinks/tests/__snapshots__/ExternalLinks.spec.ts.snap +9 -9
- package/src/components/FileList/FileList.mdx +103 -0
- package/src/components/FileList/FileList.stories.ts +562 -0
- package/src/components/FileList/FileList.vue +78 -0
- package/src/components/FileList/UploadItem/UploadItem.vue +270 -0
- package/src/components/FileList/UploadItem/locales.ts +9 -0
- package/src/components/FileList/tests/FileList.spec.ts +176 -0
- package/src/components/FilePreview/FilePreview.mdx +82 -0
- package/src/components/FilePreview/FilePreview.stories.ts +242 -0
- package/src/components/FilePreview/FilePreview.vue +68 -0
- package/src/components/FilePreview/config.ts +10 -0
- package/src/components/FilePreview/locales.ts +4 -0
- package/src/components/FilePreview/tests/FilePreview.spec.ts +124 -0
- package/src/components/FilePreview/tests/__snapshots__/FilePreview.spec.ts.snap +11 -0
- package/src/components/FileUpload/FileUpload.mdx +165 -0
- package/src/components/FileUpload/FileUpload.stories.ts +429 -0
- package/src/components/FileUpload/FileUpload.vue +195 -0
- package/src/components/FileUpload/FileUploadContent.vue +109 -0
- package/src/components/FileUpload/locales.ts +10 -0
- package/src/components/FileUpload/tests/FileUpload.spec.ts +332 -0
- package/src/components/FileUpload/tests/__snapshots__/FileUpload.spec.ts.snap +7 -0
- package/src/components/FileUpload/useFileDrop.ts +23 -0
- package/src/components/FileUpload/validateFiles.ts +39 -0
- package/src/components/NirField/NirField.stories.ts +1 -1
- package/src/components/NirField/NirField.vue +2 -1
- package/src/components/PasswordField/Accessibilite.mdx +14 -0
- package/src/components/PasswordField/Accessibilite.stories.ts +191 -0
- package/src/components/PasswordField/AccessibiliteItems.ts +184 -0
- package/src/components/PasswordField/PasswordField.vue +3 -3
- package/src/components/PasswordField/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/PeriodField/PeriodField.mdx +32 -0
- package/src/components/PeriodField/PeriodField.stories.ts +807 -0
- package/src/components/PeriodField/PeriodField.vue +355 -0
- package/src/components/PeriodField/tests/PeriodField.spec.ts +348 -0
- package/src/components/PhoneField/PhoneField.vue +44 -60
- package/src/components/PhoneField/tests/PhoneField.spec.ts +0 -15
- package/src/components/RangeField/Accessibilite.mdx +14 -0
- package/src/components/RangeField/Accessibilite.stories.ts +191 -0
- package/src/components/RangeField/AccessibiliteItems.ts +179 -0
- package/src/components/RangeField/RangeField.mdx +54 -0
- package/src/components/RangeField/RangeField.stories.ts +189 -0
- package/src/components/RangeField/RangeField.vue +157 -0
- package/src/components/RangeField/RangeSlider/RangeSlider.vue +387 -0
- package/src/components/RangeField/RangeSlider/Tooltip/Tooltip.vue +64 -0
- package/src/components/RangeField/RangeSlider/tests/__snapshots__/rangeSlider.spec.ts.snap +27 -0
- package/src/components/RangeField/RangeSlider/tests/rangeSlider.spec.ts +100 -0
- package/src/components/RangeField/RangeSlider/tests/useDoubleSlider.spec.ts +246 -0
- package/src/components/RangeField/RangeSlider/tests/useMouseSlide.spec.ts +204 -0
- package/src/components/RangeField/RangeSlider/tests/useThumb.spec.ts +22 -0
- package/src/components/RangeField/RangeSlider/tests/useThumbKeyboard.spec.ts +233 -0
- package/src/components/RangeField/RangeSlider/tests/useTooltipsNudge.spec.ts +150 -0
- package/src/components/RangeField/RangeSlider/tests/useTrack.spec.ts +314 -0
- package/src/components/RangeField/RangeSlider/tests/vAnimateClick.spec.ts +32 -0
- package/src/components/RangeField/RangeSlider/types.ts +15 -0
- package/src/components/RangeField/RangeSlider/useMouseSlide.ts +109 -0
- package/src/components/RangeField/RangeSlider/useRangeSlider.ts +126 -0
- package/src/components/RangeField/RangeSlider/useThumb.ts +18 -0
- package/src/components/RangeField/RangeSlider/useThumbKeyboard.ts +84 -0
- package/src/components/RangeField/RangeSlider/useTooltipsNudge.ts +92 -0
- package/src/components/RangeField/RangeSlider/useTrack.ts +116 -0
- package/src/components/RangeField/RangeSlider/vAnimateClick.ts +19 -0
- package/src/components/RangeField/config.ts +7 -0
- package/src/components/RangeField/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/RangeField/locales.ts +4 -0
- package/src/components/RangeField/tests/RangeField.spec.ts +224 -0
- package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +379 -0
- package/src/components/RatingPicker/Accessibilite.mdx +14 -0
- package/src/components/RatingPicker/Accessibilite.stories.ts +191 -0
- package/src/components/RatingPicker/AccessibiliteItems.ts +208 -0
- package/src/components/RatingPicker/EmotionPicker/EmotionPicker.vue +205 -0
- package/src/components/RatingPicker/EmotionPicker/locales.ts +3 -0
- package/src/components/RatingPicker/EmotionPicker/tests/EmotionPicker.spec.ts +104 -0
- package/src/components/RatingPicker/EmotionPicker/tests/__snapshots__/EmotionPicker.spec.ts.snap +66 -0
- package/src/components/RatingPicker/NumberPicker/NumberPicker.vue +159 -0
- package/src/components/RatingPicker/NumberPicker/locales.ts +4 -0
- package/src/components/RatingPicker/NumberPicker/tests/NumberPicker.spec.ts +73 -0
- package/src/components/RatingPicker/NumberPicker/tests/__snapshots__/NumberPicker.spec.ts.snap +105 -0
- package/src/components/RatingPicker/Rating.ts +45 -0
- package/src/components/RatingPicker/RatingPicker.mdx +56 -0
- package/src/components/RatingPicker/RatingPicker.stories.ts +515 -0
- package/src/components/RatingPicker/RatingPicker.vue +122 -0
- package/src/components/RatingPicker/StarsPicker/StarsPicker.vue +116 -0
- package/src/components/RatingPicker/StarsPicker/tests/StarsPicker.spec.ts +95 -0
- package/src/components/RatingPicker/StarsPicker/tests/__snapshots__/StarsPicker.spec.ts.snap +36 -0
- package/src/components/RatingPicker/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/RatingPicker/locales.ts +3 -0
- package/src/components/RatingPicker/tests/Rating.spec.ts +104 -0
- package/src/components/RatingPicker/tests/RatingPicker.spec.ts +187 -0
- package/src/components/RatingPicker/tests/__snapshots__/RatingPicker.spec.ts.snap +108 -0
- package/src/components/SearchListField/Accessibilite.mdx +14 -0
- package/src/components/SearchListField/Accessibilite.stories.ts +191 -0
- package/src/components/SearchListField/AccessibiliteItems.ts +310 -0
- package/src/components/SearchListField/SearchListField.mdx +74 -0
- package/src/components/SearchListField/SearchListField.stories.ts +126 -0
- package/src/components/SearchListField/SearchListField.vue +194 -0
- package/src/components/SearchListField/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/SearchListField/locales.ts +5 -0
- package/src/components/SearchListField/tests/SearchListField.spec.ts +323 -0
- package/src/components/SearchListField/types.d.ts +4 -0
- package/src/components/SelectBtnField/Accessibilite.mdx +14 -0
- package/src/components/SelectBtnField/Accessibilite.stories.ts +191 -0
- package/src/components/SelectBtnField/AccessibiliteItems.ts +191 -0
- package/src/components/SelectBtnField/SelectBtnField.mdx +50 -0
- package/src/components/SelectBtnField/SelectBtnField.stories.ts +763 -0
- package/src/components/SelectBtnField/SelectBtnField.vue +283 -0
- package/src/components/SelectBtnField/config.ts +11 -0
- package/src/components/SelectBtnField/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/SelectBtnField/tests/SelectBtnField.spec.ts +327 -0
- package/src/components/SelectBtnField/tests/__snapshots__/SelectBtnField.spec.ts.snap +125 -0
- package/src/components/SelectBtnField/types.d.ts +11 -0
- package/src/components/SyAlert/SyAlert.vue +11 -9
- package/src/components/TableToolbar/TableToolbar.mdx +130 -0
- package/src/components/TableToolbar/TableToolbar.stories.ts +935 -0
- package/src/components/TableToolbar/TableToolbar.vue +168 -0
- package/src/components/TableToolbar/config.ts +24 -0
- package/src/components/TableToolbar/locales.ts +6 -0
- package/src/components/TableToolbar/tests/TableToolbar.spec.ts +166 -0
- package/src/components/TableToolbar/tests/__snapshots__/TableToolbar.spec.ts.snap +359 -0
- package/src/components/index.ts +11 -1
- package/src/composables/rules/useFieldValidation.ts +174 -44
- package/src/designTokens/index.ts +3 -3
- package/src/stories/Fondamentaux/CustomisationEtThemes.mdx +52 -2
- package/src/utils/calcHumanFileSize/index.ts +12 -0
- 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
|
+
}
|
|
@@ -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
|
+
}
|