@cnamts/synapse 0.0.9-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 +631 -62
- package/dist/design-system-v3.js +3451 -2650
- package/dist/design-system-v3.umd.cjs +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- 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 +1 -6
- package/src/components/DatePicker/DatePicker.stories.ts +16 -16
- package/src/components/DatePicker/DatePicker.vue +20 -6
- package/src/components/DatePicker/constants/ExpertiseLevelEnum.ts +4 -0
- 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/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/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/constants/ExpertiseLevelEnum.ts +4 -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/constants/ExpertiseLevelEnum.ts +4 -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/constants/ExpertiseLevelEnum.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/constants/ExpertiseLevelEnum.ts +4 -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 +3 -0
- package/src/composables/rules/useFieldValidation.ts +17 -15
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import UploadItem from '@/components/FileList/UploadItem/UploadItem.vue'
|
|
3
|
+
import { useWidthable, type Widthable } from '@/composables/widthable'
|
|
4
|
+
import { locales as defaultLocales } from './UploadItem/locales'
|
|
5
|
+
|
|
6
|
+
export interface Item {
|
|
7
|
+
id: string
|
|
8
|
+
title: string
|
|
9
|
+
state: string // 'initial' | 'success' | 'error' | 'loading'
|
|
10
|
+
fileName?: string
|
|
11
|
+
optional?: boolean
|
|
12
|
+
progress?: number
|
|
13
|
+
showUploadBtn?: boolean
|
|
14
|
+
showPreviewBtn?: boolean
|
|
15
|
+
showDeleteBtn?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const props = withDefaults(defineProps<{
|
|
19
|
+
uploadList: Item[]
|
|
20
|
+
locales?: typeof defaultLocales
|
|
21
|
+
} & Widthable>(), {
|
|
22
|
+
locales: () => defaultLocales,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const { widthStyles } = useWidthable(props)
|
|
26
|
+
|
|
27
|
+
defineEmits<{
|
|
28
|
+
(e: 'upload', item: Item): void
|
|
29
|
+
(e: 'preview', item: Item): void
|
|
30
|
+
(e: 'delete', item: Item): void
|
|
31
|
+
}>()
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<ul
|
|
36
|
+
class="upload-list"
|
|
37
|
+
:style="widthStyles"
|
|
38
|
+
>
|
|
39
|
+
<UploadItem
|
|
40
|
+
v-for="item in props.uploadList"
|
|
41
|
+
:key="item.id"
|
|
42
|
+
:item-id="item.id"
|
|
43
|
+
:title="item.title"
|
|
44
|
+
:file-name="item.fileName"
|
|
45
|
+
:optional="item.optional"
|
|
46
|
+
:state="(item.state as 'initial' | 'success' | 'error' | 'loading')"
|
|
47
|
+
:progress="item.progress"
|
|
48
|
+
:show-upload-btn="item.showUploadBtn"
|
|
49
|
+
:show-preview-btn="item.showPreviewBtn"
|
|
50
|
+
:show-delete-btn="item.showDeleteBtn"
|
|
51
|
+
tag="li"
|
|
52
|
+
:locales="locales"
|
|
53
|
+
@upload="() => $emit('upload', uploadList.find((i) => i.id === item.id) as Item)"
|
|
54
|
+
@preview="() => $emit('preview', uploadList.find((i) => i.id === item.id) as Item)"
|
|
55
|
+
@delete="() => $emit('delete', uploadList.find((i) => i.id === item.id) as Item)"
|
|
56
|
+
>
|
|
57
|
+
<template #file-icon="slotProps">
|
|
58
|
+
<slot
|
|
59
|
+
:name="`file-icon-${item.id}`"
|
|
60
|
+
v-bind="slotProps"
|
|
61
|
+
/>
|
|
62
|
+
</template>
|
|
63
|
+
</UploadItem>
|
|
64
|
+
</ul>
|
|
65
|
+
</template>
|
|
66
|
+
|
|
67
|
+
<style lang="scss" scoped>
|
|
68
|
+
@use '@/assets/tokens';
|
|
69
|
+
|
|
70
|
+
.upload-list {
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: column;
|
|
73
|
+
margin: 0;
|
|
74
|
+
padding: 0;
|
|
75
|
+
list-style: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
</style>
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
mdiFile,
|
|
4
|
+
mdiTrayArrowUp,
|
|
5
|
+
mdiDeleteOutline,
|
|
6
|
+
mdiEyeOutline,
|
|
7
|
+
mdiAlertCircle,
|
|
8
|
+
mdiCheckCircle,
|
|
9
|
+
} from '@mdi/js'
|
|
10
|
+
import { cnamContextualTokens } from '@/designTokens/tokens/cnam/cnamContextual'
|
|
11
|
+
import { locales as defaultLocales } from './locales'
|
|
12
|
+
|
|
13
|
+
type FileState = 'initial' | 'success' | 'error' | 'loading'
|
|
14
|
+
|
|
15
|
+
defineEmits<{
|
|
16
|
+
(e: 'upload', item: string): void
|
|
17
|
+
(e: 'preview', item: string): void
|
|
18
|
+
(e: 'delete', item: string): void
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
withDefaults(defineProps<{
|
|
22
|
+
itemId: string
|
|
23
|
+
title: string
|
|
24
|
+
fileName?: string
|
|
25
|
+
message?: string
|
|
26
|
+
optional?: boolean
|
|
27
|
+
state?: FileState
|
|
28
|
+
progress?: number
|
|
29
|
+
showUploadBtn?: boolean
|
|
30
|
+
showDeleteBtn?: boolean
|
|
31
|
+
showPreviewBtn?: boolean
|
|
32
|
+
tag?: string
|
|
33
|
+
locales?: typeof defaultLocales
|
|
34
|
+
}>(), {
|
|
35
|
+
fileName: undefined,
|
|
36
|
+
message: undefined,
|
|
37
|
+
optional: false,
|
|
38
|
+
state: 'initial',
|
|
39
|
+
progress: undefined,
|
|
40
|
+
showUploadBtn: true,
|
|
41
|
+
showDeleteBtn: true,
|
|
42
|
+
showPreviewBtn: false,
|
|
43
|
+
tag: 'div',
|
|
44
|
+
locales: () => defaultLocales,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
defineSlots<{
|
|
48
|
+
'file-icon'(props: { state: FileState }): void
|
|
49
|
+
}>()
|
|
50
|
+
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<component
|
|
55
|
+
:is="tag"
|
|
56
|
+
class="file-item"
|
|
57
|
+
>
|
|
58
|
+
<div class="file-item__description">
|
|
59
|
+
<div class="file-item__content">
|
|
60
|
+
<span
|
|
61
|
+
class="file-item__icon"
|
|
62
|
+
>
|
|
63
|
+
<slot
|
|
64
|
+
name="file-icon"
|
|
65
|
+
:state
|
|
66
|
+
>
|
|
67
|
+
<span
|
|
68
|
+
v-if="state === 'success'"
|
|
69
|
+
class="d-sr-only"
|
|
70
|
+
>
|
|
71
|
+
{{ locales.success }}
|
|
72
|
+
</span>
|
|
73
|
+
|
|
74
|
+
<span
|
|
75
|
+
v-else-if="state === 'error'"
|
|
76
|
+
class="d-sr-only"
|
|
77
|
+
>
|
|
78
|
+
{{ locales.error }}
|
|
79
|
+
</span>
|
|
80
|
+
|
|
81
|
+
<VIcon
|
|
82
|
+
v-if="state === 'error'"
|
|
83
|
+
:size="cnamContextualTokens.iconSize.default"
|
|
84
|
+
:aria-label="locales.error"
|
|
85
|
+
color="error"
|
|
86
|
+
>{{ mdiAlertCircle }}</VIcon>
|
|
87
|
+
|
|
88
|
+
<VIcon
|
|
89
|
+
v-else-if="state === 'success'"
|
|
90
|
+
:size="cnamContextualTokens.iconSize.default"
|
|
91
|
+
:aria-label="locales.success"
|
|
92
|
+
color="success"
|
|
93
|
+
>{{ mdiCheckCircle }}</VIcon>
|
|
94
|
+
|
|
95
|
+
<VIcon
|
|
96
|
+
v-else
|
|
97
|
+
:size="cnamContextualTokens.iconSize.default"
|
|
98
|
+
color="primary"
|
|
99
|
+
>{{ mdiFile }}</VIcon>
|
|
100
|
+
</slot>
|
|
101
|
+
</span>
|
|
102
|
+
<div>
|
|
103
|
+
<div class="file-item__title">
|
|
104
|
+
{{ title }}
|
|
105
|
+
</div>
|
|
106
|
+
<div class="file-item__name text-base">
|
|
107
|
+
{{ fileName }}
|
|
108
|
+
</div>
|
|
109
|
+
<div
|
|
110
|
+
v-if="message || optional"
|
|
111
|
+
class="file-item__message text-base"
|
|
112
|
+
>
|
|
113
|
+
{{ message ?? locales.optionalDocument }}
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
<div class="file-item__actions">
|
|
118
|
+
<VBtn
|
|
119
|
+
v-if="(state === 'initial' || state == 'error') && showUploadBtn"
|
|
120
|
+
class="file-item__action file-item__action-upload text-primary"
|
|
121
|
+
variant="text"
|
|
122
|
+
@click="$emit('upload', itemId)"
|
|
123
|
+
>
|
|
124
|
+
<span>Importer</span>
|
|
125
|
+
<template #prepend>
|
|
126
|
+
<VIcon
|
|
127
|
+
color="primary"
|
|
128
|
+
>
|
|
129
|
+
{{ mdiTrayArrowUp }}
|
|
130
|
+
</VIcon>
|
|
131
|
+
</template>
|
|
132
|
+
</VBtn>
|
|
133
|
+
<VBtn
|
|
134
|
+
v-if="state === 'success' && showPreviewBtn"
|
|
135
|
+
class="file-item__action file-item__action-preview text-primary"
|
|
136
|
+
variant="text"
|
|
137
|
+
@click="$emit('preview', itemId)"
|
|
138
|
+
>
|
|
139
|
+
<span>{{ locales.see }}</span>
|
|
140
|
+
<template #prepend>
|
|
141
|
+
<VIcon
|
|
142
|
+
color="primary"
|
|
143
|
+
>
|
|
144
|
+
{{ mdiEyeOutline }}
|
|
145
|
+
</VIcon>
|
|
146
|
+
</template>
|
|
147
|
+
</VBtn>
|
|
148
|
+
<VBtn
|
|
149
|
+
v-if="state === 'success' && showDeleteBtn"
|
|
150
|
+
class="file-item__action file-item__action-delete text-error"
|
|
151
|
+
variant="text"
|
|
152
|
+
@click="$emit('delete', itemId)"
|
|
153
|
+
>
|
|
154
|
+
<span>{{ locales.delete }}</span>
|
|
155
|
+
<template #prepend>
|
|
156
|
+
<VIcon
|
|
157
|
+
color="error"
|
|
158
|
+
>
|
|
159
|
+
{{ mdiDeleteOutline }}
|
|
160
|
+
</VIcon>
|
|
161
|
+
</template>
|
|
162
|
+
</VBtn>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<div
|
|
167
|
+
v-if="state === 'loading'"
|
|
168
|
+
class="file-item__message-progress"
|
|
169
|
+
>
|
|
170
|
+
<p class="d-sr-only">
|
|
171
|
+
{{ locales.uploading }}
|
|
172
|
+
</p>
|
|
173
|
+
<VProgressLinear
|
|
174
|
+
:indeterminate="progress === undefined"
|
|
175
|
+
:model-value="progress"
|
|
176
|
+
:progress="progress"
|
|
177
|
+
height="7"
|
|
178
|
+
color="primary"
|
|
179
|
+
rounded="true"
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
</component>
|
|
183
|
+
</template>
|
|
184
|
+
|
|
185
|
+
<style lang="scss" scoped>
|
|
186
|
+
@use '@/assets/tokens';
|
|
187
|
+
|
|
188
|
+
.file-item {
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
gap: tokens.$gap-3;
|
|
192
|
+
padding-block: tokens.$padding-4;
|
|
193
|
+
border-bottom: 1px solid tokens.$colors-border-subdued;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.file-item__title {
|
|
197
|
+
font-size: tokens.$font-size-body-text;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.file-item__name {
|
|
201
|
+
font-size: 0.875rem;
|
|
202
|
+
color: tokens.$colors-text-base;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.file-item__description {
|
|
206
|
+
display: flex;
|
|
207
|
+
justify-content: space-between;
|
|
208
|
+
align-items: center;
|
|
209
|
+
flex-wrap: wrap;
|
|
210
|
+
|
|
211
|
+
> * {
|
|
212
|
+
grid-column: 1 / -1;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
> *:nth-child(1),
|
|
216
|
+
> *:nth-child(2) {
|
|
217
|
+
grid-column: 1 / 2;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
> .file-item__actions {
|
|
221
|
+
grid-column-start: 2;
|
|
222
|
+
grid-row: span 2;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.file-item__content {
|
|
227
|
+
display: flex;
|
|
228
|
+
gap: tokens.$gap-4;
|
|
229
|
+
align-items: center;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.file-item__actions {
|
|
233
|
+
display: flex;
|
|
234
|
+
flex-direction: column;
|
|
235
|
+
align-items: end;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
margin-left: auto;
|
|
238
|
+
height: 100%;
|
|
239
|
+
gap: tokens.$gap-1;
|
|
240
|
+
|
|
241
|
+
@media screen and (min-width: tokens.$container-tablet-max-width) {
|
|
242
|
+
flex-direction: row;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.file-item__action {
|
|
247
|
+
display: flex;
|
|
248
|
+
justify-content: end;
|
|
249
|
+
text-transform: unset;
|
|
250
|
+
padding: 0.625rem 1.25rem;
|
|
251
|
+
font-weight: bold;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.file-item__message {
|
|
255
|
+
font-size: 0.875rem;
|
|
256
|
+
color: tokens.$colors-text-subdued;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.file-item__message-success,
|
|
260
|
+
.file-item__message-error {
|
|
261
|
+
margin-top: tokens.$gap-3;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.file-item__message-error {
|
|
265
|
+
display: flex;
|
|
266
|
+
align-items: center;
|
|
267
|
+
gap: tokens.$gap-4;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
</style>
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import FileList from '../FileList.vue'
|
|
4
|
+
import { vuetify } from '@tests/unit/setup'
|
|
5
|
+
import { locales } from '../UploadItem/locales'
|
|
6
|
+
|
|
7
|
+
describe('FileList', () => {
|
|
8
|
+
it('renders many file items', () => {
|
|
9
|
+
const wrapper = mount(FileList, {
|
|
10
|
+
props: {
|
|
11
|
+
uploadList: [
|
|
12
|
+
{
|
|
13
|
+
id: 'residenceCertificate',
|
|
14
|
+
title: 'Attestation de domicile',
|
|
15
|
+
state: 'initial',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'identityCard',
|
|
19
|
+
title: 'Carte d\'identité',
|
|
20
|
+
state: 'initial',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
global: {
|
|
25
|
+
plugins: [vuetify],
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
expect(wrapper.findAll('.file-item').length).toBe(2)
|
|
29
|
+
const item1 = wrapper.findAll('.file-item').at(0)
|
|
30
|
+
expect(item1!.text()).toContain('Attestation de domicile')
|
|
31
|
+
const item2 = wrapper.findAll('.file-item').at(1)
|
|
32
|
+
expect(item2!.text()).toContain('Carte d\'identité')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('shows the right action for each state and item preference', async () => {
|
|
36
|
+
const wrapper = mount(FileList, {
|
|
37
|
+
props: {
|
|
38
|
+
uploadList: [
|
|
39
|
+
{
|
|
40
|
+
id: 'file1',
|
|
41
|
+
title: 'file1',
|
|
42
|
+
state: 'initial',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'file2',
|
|
46
|
+
title: 'file2',
|
|
47
|
+
state: 'initial',
|
|
48
|
+
showUploadBtn: false,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'file3',
|
|
52
|
+
title: 'file3',
|
|
53
|
+
state: 'success',
|
|
54
|
+
showDeleteBtn: true,
|
|
55
|
+
showPreviewBtn: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'file4',
|
|
59
|
+
title: 'file4',
|
|
60
|
+
state: 'success',
|
|
61
|
+
showDeleteBtn: false,
|
|
62
|
+
showPreviewBtn: false,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'file5',
|
|
66
|
+
title: 'file5',
|
|
67
|
+
state: 'error',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'file6',
|
|
71
|
+
title: 'file6',
|
|
72
|
+
state: 'error',
|
|
73
|
+
showUploadBtn: false,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
global: {
|
|
78
|
+
plugins: [vuetify],
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const item1 = wrapper.findAll('.file-item').at(0)
|
|
83
|
+
expect(item1!.findAll('button').length).toBe(1)
|
|
84
|
+
const item1UploadBtn = item1!.find('.file-item__action-upload')
|
|
85
|
+
expect(item1UploadBtn.exists()).toBe(true)
|
|
86
|
+
|
|
87
|
+
const item2 = wrapper.findAll('.file-item').at(1)
|
|
88
|
+
expect(item2!.findAll('button').length).toBe(0)
|
|
89
|
+
|
|
90
|
+
const item3 = wrapper.findAll('.file-item').at(2)
|
|
91
|
+
expect(item3!.findAll('button').length).toBe(2)
|
|
92
|
+
const item3DeleteBtn = item3!.find('.file-item__action-delete')
|
|
93
|
+
expect(item3DeleteBtn.exists()).toBe(true)
|
|
94
|
+
const item3PreviewBtn = item3!.find('.file-item__action-preview')
|
|
95
|
+
expect(item3PreviewBtn.exists()).toBe(true)
|
|
96
|
+
|
|
97
|
+
const item4 = wrapper.findAll('.file-item').at(3)
|
|
98
|
+
expect(item4!.findAll('button').length).toBe(0)
|
|
99
|
+
|
|
100
|
+
const item5 = wrapper.findAll('.file-item').at(4)
|
|
101
|
+
expect(item5!.findAll('button').length).toBe(1)
|
|
102
|
+
const item5UploadBtn = item5!.find('.file-item__action-upload')
|
|
103
|
+
expect(item5UploadBtn.exists()).toBe(true)
|
|
104
|
+
|
|
105
|
+
const item6 = wrapper.findAll('.file-item').at(5)
|
|
106
|
+
expect(item6!.findAll('button').length).toBe(0)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('emits the right event when clicking on an action button', async () => {
|
|
110
|
+
const fileItem1 = {
|
|
111
|
+
id: 'file1',
|
|
112
|
+
title: 'file1',
|
|
113
|
+
state: 'initial',
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fileItem2 = {
|
|
117
|
+
id: 'file2',
|
|
118
|
+
title: 'file2',
|
|
119
|
+
state: 'success',
|
|
120
|
+
showDeleteBtn: true,
|
|
121
|
+
showPreviewBtn: true,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const wrapper = mount(FileList, {
|
|
125
|
+
props: {
|
|
126
|
+
uploadList: [fileItem1, fileItem2],
|
|
127
|
+
},
|
|
128
|
+
global: {
|
|
129
|
+
plugins: [vuetify],
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const item1 = wrapper.findAll('.file-item').at(0)
|
|
134
|
+
const item1UploadBtn = item1!.find('.file-item__action-upload')
|
|
135
|
+
await item1UploadBtn!.trigger('click')
|
|
136
|
+
expect(wrapper.emitted('upload')?.[0][0]).toEqual(fileItem1)
|
|
137
|
+
|
|
138
|
+
const item2 = wrapper.findAll('.file-item').at(1)
|
|
139
|
+
const item2DeleteBtn = item2!.find('.file-item__action-delete')
|
|
140
|
+
await item2DeleteBtn!.trigger('click')
|
|
141
|
+
expect(wrapper.emitted('delete')?.[0][0]).toEqual(fileItem2)
|
|
142
|
+
|
|
143
|
+
const item2PreviewBtn = item2!.find('.file-item__action-preview')
|
|
144
|
+
await item2PreviewBtn!.trigger('click')
|
|
145
|
+
expect(wrapper.emitted('preview')?.[0][0]).toEqual(fileItem2)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('shows when a file is optional', () => {
|
|
149
|
+
const wrapper = mount(FileList, {
|
|
150
|
+
props: {
|
|
151
|
+
uploadList: [
|
|
152
|
+
{
|
|
153
|
+
id: 'file1',
|
|
154
|
+
title: 'file1',
|
|
155
|
+
state: 'initial',
|
|
156
|
+
optional: true,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: 'file2',
|
|
160
|
+
title: 'file2',
|
|
161
|
+
state: 'initial',
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
global: {
|
|
166
|
+
plugins: [vuetify],
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const item1 = wrapper.findAll('.file-item').at(0)
|
|
171
|
+
expect(item1!.text()).toContain(locales.optionalDocument)
|
|
172
|
+
|
|
173
|
+
const item2 = wrapper.findAll('.file-item').at(1)
|
|
174
|
+
expect(item2!.text()).not.toContain(locales.optionalDocument)
|
|
175
|
+
})
|
|
176
|
+
})
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {Controls, Canvas, Meta, Source} from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import * as FilePreviewStories from './FilePreview.stories.ts'
|
|
4
|
+
|
|
5
|
+
<Meta of={FilePreviewStories} />
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# FilePreview
|
|
9
|
+
|
|
10
|
+
L'élément `FilePreview` est utilisé pour afficher l'aperçu d'un fichier.
|
|
11
|
+
|
|
12
|
+
<Canvas of={FilePreviewStories.Default} />
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# API
|
|
16
|
+
|
|
17
|
+
<Controls of={FilePreviewStories.Default} />
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Exemple
|
|
21
|
+
|
|
22
|
+
## Afficher un fichier depuis une API
|
|
23
|
+
|
|
24
|
+
Vous pouvez afficher une image ou un fichier PDF récupéré depuis une API sous forme de `Blob`.
|
|
25
|
+
|
|
26
|
+
<Canvas
|
|
27
|
+
of={FilePreviewStories.FromApi}
|
|
28
|
+
source={{
|
|
29
|
+
language: 'html',
|
|
30
|
+
format: 'dedent',
|
|
31
|
+
code: `
|
|
32
|
+
<script lang="ts" setup>
|
|
33
|
+
import { onMounted, ref } from 'vue'
|
|
34
|
+
import { FilePreview } from '@cnamts/synapse'
|
|
35
|
+
|
|
36
|
+
const file = ref<File | Blob | undefined>()
|
|
37
|
+
|
|
38
|
+
onMounted(() => {
|
|
39
|
+
fetch('https://picsum.photos/seed/picsum/750/350')
|
|
40
|
+
.then(res => res.blob())
|
|
41
|
+
.then(blob => file.value = blob)
|
|
42
|
+
})
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<FilePreview :file="file" />
|
|
47
|
+
</template>
|
|
48
|
+
`,
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
|
|
52
|
+
## Fichier non supporté
|
|
53
|
+
|
|
54
|
+
Lorsque le fichier n'est pas supporté, un message d'erreur est affiché.
|
|
55
|
+
|
|
56
|
+
<Canvas of={FilePreviewStories.UnsupportedFile} />
|
|
57
|
+
|
|
58
|
+
## Usage avec `FileUpload`
|
|
59
|
+
|
|
60
|
+
Vous pouvez utiliser ce composant en combinaison avec `FileUpload` pour afficher un aperçu du fichier avant de l'envoyer.
|
|
61
|
+
|
|
62
|
+
<Canvas
|
|
63
|
+
of={FilePreviewStories.WithFileUpload}
|
|
64
|
+
source={{
|
|
65
|
+
language: 'html',
|
|
66
|
+
format: 'dedent',
|
|
67
|
+
code: `
|
|
68
|
+
<script lang="ts" setup>
|
|
69
|
+
import { ref } from 'vue'
|
|
70
|
+
import { FilePreview, FileUpload } from '@cnamts/synapse'
|
|
71
|
+
|
|
72
|
+
const files = ref<File[]>([])
|
|
73
|
+
</script>
|
|
74
|
+
<template>
|
|
75
|
+
<div>
|
|
76
|
+
<FileUpload v-model="files" class="mb-4"/>
|
|
77
|
+
<FilePreview :file="files[0]"/>
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
80
|
+
`,
|
|
81
|
+
}}
|
|
82
|
+
/>
|