@weni/unnnic-system 1.24.21 → 1.25.0
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/CHANGELOG.md +16 -0
- package/dist/unnnic.common.js +486 -281
- package/dist/unnnic.common.js.map +1 -1
- package/dist/unnnic.css +1 -1
- package/dist/unnnic.umd.js +486 -281
- package/dist/unnnic.umd.js.map +1 -1
- package/dist/unnnic.umd.min.js +23 -23
- package/dist/unnnic.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/DropArea/DropArea.vue +362 -0
- package/src/components/ImportCard/ImportCard.vue +82 -33
- package/src/components/Slider/Slider.vue +43 -9
- package/src/components/UploadArea/UploadArea.vue +26 -271
- package/src/components/index.js +3 -0
- package/src/stories/DropArea.stories.js +80 -0
|
@@ -1,63 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
+
<UnnnicDropArea
|
|
4
|
+
:currentFiles.sync="currentFiles"
|
|
5
|
+
:acceptMultiple="acceptMultiple"
|
|
6
|
+
:supportedFormats="supportedFormats"
|
|
7
|
+
:maxFileSize="maxFileSize"
|
|
8
|
+
:shouldReplace="shouldReplace"
|
|
9
|
+
:maximumUploads="maximumUploads"
|
|
10
|
+
:subtitle="subtitle"
|
|
11
|
+
@file-change="$emit('fileChange', $event)"
|
|
12
|
+
/>
|
|
13
|
+
|
|
3
14
|
<div
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
'unnnic-upload-area__dropzone': true,
|
|
7
|
-
'unnnic-upload-area__dropzone__is-dragover': isDragging,
|
|
8
|
-
'unnnic-upload-area__dropzone__has-error': hasError,
|
|
9
|
-
}"
|
|
10
|
-
v-on:dragenter.stop.prevent="dragenter"
|
|
11
|
-
v-on:dragover.stop.prevent="dragover"
|
|
12
|
-
v-on:dragleave.stop.prevent="dragleave"
|
|
13
|
-
v-on:dragend.stop.prevent="dragend"
|
|
14
|
-
v-on:drop.stop.prevent="drop"
|
|
15
|
-
@click="() => this.$refs.file.click()"
|
|
15
|
+
v-if="currentFiles.length > 0"
|
|
16
|
+
class="unnnic-upload-area__cards"
|
|
16
17
|
>
|
|
17
|
-
<
|
|
18
|
-
class="unnnic-upload-area__dropzone__icon"
|
|
19
|
-
icon="upload-bottom-1"
|
|
20
|
-
:scheme="hasError ? 'feedback-red' : 'brand-weni'"
|
|
21
|
-
size="xl"
|
|
22
|
-
/>
|
|
23
|
-
|
|
24
|
-
<div class="unnnic-upload-area__dropzone__content">
|
|
25
|
-
<span class="unnnic-upload-area__dropzone__content__title">
|
|
26
|
-
{{ $t('upload_area.title.text') }}
|
|
27
|
-
<span
|
|
28
|
-
:class="`unnnic-upload-area__dropzone__content__title__${
|
|
29
|
-
hasError ? 'error' : 'search'
|
|
30
|
-
}`"
|
|
31
|
-
>
|
|
32
|
-
{{ $t('upload_area.title.highlight') }}
|
|
33
|
-
</span>
|
|
34
|
-
</span>
|
|
35
|
-
<span
|
|
36
|
-
:class="[
|
|
37
|
-
'unnnic-upload-area__dropzone__content__subtitle',
|
|
38
|
-
{ 'unnnic-upload-area__dropzone__content__subtitle__error': hasError },
|
|
39
|
-
]"
|
|
40
|
-
:title='formattedSupportedFormats'
|
|
41
|
-
>
|
|
42
|
-
{{
|
|
43
|
-
subtitle ||
|
|
44
|
-
`${$t(
|
|
45
|
-
`upload_area${hasError ? '.invalid' : ''}.subtitle`
|
|
46
|
-
)} ${formattedSupportedFormats}`
|
|
47
|
-
}}
|
|
48
|
-
</span>
|
|
49
|
-
</div>
|
|
50
|
-
<input
|
|
51
|
-
type="file"
|
|
52
|
-
ref="file"
|
|
53
|
-
:accept="supportedFormats"
|
|
54
|
-
:multiple="acceptMultiple"
|
|
55
|
-
@input="handleFileChange"
|
|
56
|
-
style="display: none;"
|
|
57
|
-
/>
|
|
58
|
-
</div>
|
|
59
|
-
<div v-if="currentFiles.length > 0" class="unnnic-upload-area__cards">
|
|
60
|
-
<unnnic-import-card
|
|
18
|
+
<UnnnicImportCard
|
|
61
19
|
v-for="(file, index) in currentFiles"
|
|
62
20
|
:key="index"
|
|
63
21
|
:title="file.name"
|
|
@@ -69,24 +27,26 @@
|
|
|
69
27
|
:acceptedFormats="supportedFormats"
|
|
70
28
|
uploadIcon="button-refresh-arrows-1"
|
|
71
29
|
@delete="removeFile(index)"
|
|
72
|
-
@
|
|
30
|
+
@modified-file="modifyFile(index, $event)"
|
|
73
31
|
/>
|
|
74
32
|
</div>
|
|
75
33
|
</div>
|
|
76
34
|
</template>
|
|
77
35
|
|
|
78
36
|
<script>
|
|
79
|
-
import
|
|
80
|
-
|
|
81
|
-
import UnnnicIconSvg from '../Icon.vue';
|
|
37
|
+
import UnnnicDropArea from '../DropArea/DropArea.vue';
|
|
82
38
|
import UnnnicImportCard from '../ImportCard/ImportCard.vue';
|
|
83
39
|
|
|
84
40
|
export default {
|
|
85
|
-
name: '
|
|
41
|
+
name: 'UnnnicUploadArea',
|
|
86
42
|
components: {
|
|
87
|
-
|
|
43
|
+
UnnnicDropArea,
|
|
88
44
|
UnnnicImportCard,
|
|
89
45
|
},
|
|
46
|
+
model: {
|
|
47
|
+
prop: 'files',
|
|
48
|
+
event: 'fileChange',
|
|
49
|
+
},
|
|
90
50
|
props: {
|
|
91
51
|
files: {
|
|
92
52
|
type: Array,
|
|
@@ -134,152 +94,26 @@ export default {
|
|
|
134
94
|
default: '',
|
|
135
95
|
},
|
|
136
96
|
},
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
},
|
|
97
|
+
|
|
98
|
+
emits: ['fileChange'],
|
|
99
|
+
|
|
141
100
|
data() {
|
|
142
101
|
return {
|
|
143
|
-
hasError: false,
|
|
144
|
-
isDragging: false,
|
|
145
|
-
dragEnterCounter: 0, // to handle dragenter/dragleave on child elements
|
|
146
102
|
currentFiles: this.files,
|
|
147
103
|
};
|
|
148
104
|
},
|
|
105
|
+
|
|
149
106
|
watch: {
|
|
150
107
|
files(newValue) {
|
|
151
108
|
this.currentFiles = newValue;
|
|
152
109
|
},
|
|
153
110
|
},
|
|
154
|
-
computed: {
|
|
155
|
-
formattedSupportedFormats() {
|
|
156
|
-
const formats = this.supportedFormats.split(',').map((format) => format.toUpperCase());
|
|
157
111
|
|
|
158
|
-
return formats.join(', ');
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
112
|
methods: {
|
|
162
|
-
dragenter() {
|
|
163
|
-
this.dragEnterCounter += 1;
|
|
164
|
-
this.isDragging = true;
|
|
165
|
-
},
|
|
166
|
-
dragover() {
|
|
167
|
-
this.isDragging = true;
|
|
168
|
-
},
|
|
169
|
-
dragleave() {
|
|
170
|
-
this.dragEnterCounter -= 1;
|
|
171
|
-
if (this.dragEnterCounter === 0) {
|
|
172
|
-
this.isDragging = false;
|
|
173
|
-
}
|
|
174
|
-
},
|
|
175
|
-
dragend() {
|
|
176
|
-
this.isDragging = false;
|
|
177
|
-
},
|
|
178
|
-
drop(event) {
|
|
179
|
-
this.isDragging = false;
|
|
180
|
-
|
|
181
|
-
const { files } = event.dataTransfer;
|
|
182
|
-
|
|
183
|
-
if (this.validateFiles(files)) {
|
|
184
|
-
this.addFiles(files);
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
handleFileChange(event) {
|
|
188
|
-
const { files } = event.target;
|
|
189
|
-
|
|
190
|
-
if (this.validateFiles(files)) {
|
|
191
|
-
this.addFiles(files);
|
|
192
|
-
}
|
|
193
|
-
this.$refs.file.value = '';
|
|
194
|
-
},
|
|
195
|
-
validateFiles(files) {
|
|
196
|
-
if (!this.acceptMultiple && files.length > 1) {
|
|
197
|
-
this.setErrorState();
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (!this.validFormat(files)) {
|
|
202
|
-
this.setErrorState();
|
|
203
|
-
return false;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (!this.validSize(files)) {
|
|
207
|
-
this.setErrorState();
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return true;
|
|
212
|
-
},
|
|
213
|
-
validFormat(files) {
|
|
214
|
-
const formats = this.supportedFormats.split(',').map((format) => format.trim());
|
|
215
|
-
|
|
216
|
-
const isValid = Array.from(files).find((file) => {
|
|
217
|
-
const fileName = file.name.toLowerCase();
|
|
218
|
-
const fileType = file.type.toLowerCase();
|
|
219
|
-
const fileExtension = `.${fileName.split('.').pop()}`;
|
|
220
|
-
|
|
221
|
-
const isValidFileExtension = formats.includes(fileExtension);
|
|
222
|
-
const isValidFileType = fileType === mime.lookup(fileName);
|
|
223
|
-
|
|
224
|
-
return isValidFileExtension && isValidFileType;
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
return isValid;
|
|
228
|
-
},
|
|
229
|
-
|
|
230
|
-
validSize(files) {
|
|
231
|
-
if (!this.maxFileSize) {
|
|
232
|
-
return true;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const isValid = Array.from(files).find((file) => {
|
|
236
|
-
const sizeInMB = (file.size / (1024 * 1024)).toFixed(2);
|
|
237
|
-
|
|
238
|
-
return sizeInMB <= this.maxFileSize;
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return isValid;
|
|
242
|
-
},
|
|
243
|
-
|
|
244
|
-
setErrorState() {
|
|
245
|
-
this.hasError = true;
|
|
246
|
-
|
|
247
|
-
setTimeout(() => {
|
|
248
|
-
this.hasError = false;
|
|
249
|
-
}, 5000);
|
|
250
|
-
},
|
|
251
|
-
|
|
252
113
|
emitFileChange() {
|
|
253
114
|
this.$emit('fileChange', this.currentFiles);
|
|
254
115
|
},
|
|
255
116
|
|
|
256
|
-
addFiles(files) {
|
|
257
|
-
let totalLength = files.length;
|
|
258
|
-
|
|
259
|
-
if (!this.shouldReplace) {
|
|
260
|
-
totalLength += this.currentFiles.length;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (totalLength > this.maximumUploads) {
|
|
264
|
-
this.setErrorState();
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const validFiles = Array.from(files).filter((file) => {
|
|
269
|
-
if (this.validFormat([file]) && this.validSize([file])) {
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
return false;
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
if (this.shouldReplace) {
|
|
276
|
-
this.currentFiles = validFiles;
|
|
277
|
-
} else {
|
|
278
|
-
this.currentFiles = this.currentFiles.concat(validFiles);
|
|
279
|
-
}
|
|
280
|
-
this.emitFileChange();
|
|
281
|
-
},
|
|
282
|
-
|
|
283
117
|
modifyFile(index, file) {
|
|
284
118
|
this.currentFiles.splice(index, 1, file);
|
|
285
119
|
this.emitFileChange();
|
|
@@ -289,14 +123,6 @@ export default {
|
|
|
289
123
|
this.currentFiles.splice(index, 1);
|
|
290
124
|
this.emitFileChange();
|
|
291
125
|
},
|
|
292
|
-
|
|
293
|
-
checkDragAndDropSupport() {
|
|
294
|
-
const { dropzone } = this.$refs;
|
|
295
|
-
return (
|
|
296
|
-
'FileReader' in window
|
|
297
|
-
&& ('draggable' in dropzone || ('ondragstart' in dropzone && 'ondrop' in dropzone))
|
|
298
|
-
);
|
|
299
|
-
},
|
|
300
126
|
},
|
|
301
127
|
};
|
|
302
128
|
</script>
|
|
@@ -304,71 +130,7 @@ export default {
|
|
|
304
130
|
<style lang="scss" scoped>
|
|
305
131
|
@import '../../assets/scss/unnnic.scss';
|
|
306
132
|
|
|
307
|
-
@function borderDashed($color) {
|
|
308
|
-
@return url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='16' ry='16' stroke='%23#{str-slice(quote($color), 2)}' stroke-width='4' stroke-dasharray='4%2c 12' stroke-dashoffset='9' stroke-linecap='square'/%3e%3c/svg%3e");
|
|
309
|
-
}
|
|
310
|
-
|
|
311
133
|
.unnnic-upload-area {
|
|
312
|
-
&__dropzone {
|
|
313
|
-
border-radius: $unnnic-border-radius-lg;
|
|
314
|
-
background-color: $unnnic-color-background-carpet;
|
|
315
|
-
padding: $unnnic-spacing-inset-lg;
|
|
316
|
-
|
|
317
|
-
// Dashed border with increased dashes spacing and color neutral clean
|
|
318
|
-
background-image: borderDashed($unnnic-color-neutral-cleanest);
|
|
319
|
-
|
|
320
|
-
&__has-error {
|
|
321
|
-
background-image: borderDashed($unnnic-color-feedback-red);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
&__is-dragover {
|
|
325
|
-
background-color: $unnnic-color-background-sky;
|
|
326
|
-
background-image: borderDashed($unnnic-color-brand-weni);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
&__icon {
|
|
330
|
-
display: block;
|
|
331
|
-
margin: 0 auto;
|
|
332
|
-
|
|
333
|
-
margin-bottom: $unnnic-spacing-stack-sm;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
&__content {
|
|
337
|
-
display: flex;
|
|
338
|
-
flex-direction: column;
|
|
339
|
-
gap: $unnnic-spacing-stack-nano;
|
|
340
|
-
|
|
341
|
-
text-align: center;
|
|
342
|
-
font-family: $unnnic-font-family-secondary;
|
|
343
|
-
|
|
344
|
-
&__title {
|
|
345
|
-
color: $unnnic-color-neutral-darkest;
|
|
346
|
-
font-weight: $unnnic-font-weight-bold;
|
|
347
|
-
font-size: $unnnic-font-size-body-gt;
|
|
348
|
-
line-height: $unnnic-font-size-body-gt + $unnnic-line-height-md;
|
|
349
|
-
|
|
350
|
-
&__search {
|
|
351
|
-
color: $unnnic-color-brand-weni;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
&__error {
|
|
355
|
-
color: $unnnic-color-feedback-red;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
&__subtitle {
|
|
360
|
-
color: $unnnic-color-neutral-cloudy;
|
|
361
|
-
font-weight: $unnnic-font-weight-regular;
|
|
362
|
-
font-size: $unnnic-font-size-body-md;
|
|
363
|
-
line-height: $unnnic-font-size-body-md + $unnnic-line-height-md;
|
|
364
|
-
|
|
365
|
-
&__error {
|
|
366
|
-
color: $unnnic-color-feedback-red;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
134
|
&__cards {
|
|
373
135
|
margin-top: $unnnic-spacing-stack-md;
|
|
374
136
|
display: flex;
|
|
@@ -376,11 +138,4 @@ export default {
|
|
|
376
138
|
gap: $unnnic-spacing-stack-xs;
|
|
377
139
|
}
|
|
378
140
|
}
|
|
379
|
-
|
|
380
|
-
.unnnic-upload-area__dropzone__dragndrop,
|
|
381
|
-
.unnnic-upload-area__dropzone__uploading,
|
|
382
|
-
.unnnic-upload-area__dropzone__success,
|
|
383
|
-
.unnnic-upload-area__dropzone__error {
|
|
384
|
-
display: none;
|
|
385
|
-
}
|
|
386
141
|
</style>
|
package/src/components/index.js
CHANGED
|
@@ -57,6 +57,7 @@ import Switch from './Switch/Switch.vue';
|
|
|
57
57
|
import Slider from './Slider/Slider.vue';
|
|
58
58
|
import DataArea from './DataArea/DataArea.vue';
|
|
59
59
|
import Pagination from './Pagination/Pagination.vue';
|
|
60
|
+
import DropArea from './DropArea/DropArea.vue';
|
|
60
61
|
import UploadArea from './UploadArea/UploadArea.vue';
|
|
61
62
|
import ImportCard from './ImportCard/ImportCard.vue';
|
|
62
63
|
import DateFilter from './DateFilter/DateFilter.vue';
|
|
@@ -142,6 +143,7 @@ const components = {
|
|
|
142
143
|
unnnicSlider: Slider,
|
|
143
144
|
unnnicDataArea: DataArea,
|
|
144
145
|
unnnicPagination: Pagination,
|
|
146
|
+
unnnicDropArea: DropArea,
|
|
145
147
|
unnnicUploadArea: UploadArea,
|
|
146
148
|
unnnicImportCard: ImportCard,
|
|
147
149
|
unnnicDateFilter: DateFilter,
|
|
@@ -234,6 +236,7 @@ export const unnnicSwitch = Switch;
|
|
|
234
236
|
export const unnnicSlider = Slider;
|
|
235
237
|
export const unnnicDataArea = DataArea;
|
|
236
238
|
export const unnnicPagination = Pagination;
|
|
239
|
+
export const unnnicDropArea = DropArea;
|
|
237
240
|
export const unnnicUploadArea = UploadArea;
|
|
238
241
|
export const unnnicImportCard = ImportCard;
|
|
239
242
|
export const unnnicDateFilter = DateFilter;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import UnnnicDropArea from '../components/DropArea/DropArea.vue';
|
|
2
|
+
|
|
3
|
+
const events = {
|
|
4
|
+
'update:currentFiles': { action: 'update:currentFiles' },
|
|
5
|
+
fileChange: { action: 'fileChange' },
|
|
6
|
+
unsupportedFormat: { action: 'unsupportedFormat' },
|
|
7
|
+
exceededTheMaximumFileSizeLimit: { action: 'exceededTheMaximumFileSizeLimit' },
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function getterEvents() {
|
|
11
|
+
return Object.keys(events)
|
|
12
|
+
.reduce(
|
|
13
|
+
(previous, current) => (
|
|
14
|
+
{ ...previous, [current]: this.$props[current] }
|
|
15
|
+
), {},
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
title: 'Example/DropArea',
|
|
21
|
+
component: UnnnicDropArea,
|
|
22
|
+
argTypes: {
|
|
23
|
+
acceptMultiple: { control: 'boolean' },
|
|
24
|
+
supportedFormats: { control: 'text' },
|
|
25
|
+
maxFileSize: { control: 'number' },
|
|
26
|
+
shouldReplace: { control: 'boolean' },
|
|
27
|
+
currentFiles: { control: 'object' },
|
|
28
|
+
maximumUploads: { control: 'number' },
|
|
29
|
+
subtitle: { control: 'text' },
|
|
30
|
+
...events,
|
|
31
|
+
},
|
|
32
|
+
args: {
|
|
33
|
+
acceptMultiple: true,
|
|
34
|
+
supportedFormats: '*',
|
|
35
|
+
maxFileSize: undefined,
|
|
36
|
+
shouldReplace: false,
|
|
37
|
+
currentFiles: [],
|
|
38
|
+
maximumUploads: 1,
|
|
39
|
+
subtitle: '',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const Template = (_args, { argTypes }) => ({
|
|
44
|
+
components: { UnnnicDropArea },
|
|
45
|
+
|
|
46
|
+
props: Object.keys(argTypes),
|
|
47
|
+
|
|
48
|
+
computed: {
|
|
49
|
+
events: getterEvents,
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
template: `
|
|
53
|
+
<UnnnicDropArea v-bind="$props" v-on="events" />
|
|
54
|
+
`,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const TemplateWithTitleAndSubtitleSlots = (_args, { argTypes }) => ({
|
|
58
|
+
components: { UnnnicDropArea },
|
|
59
|
+
|
|
60
|
+
props: Object.keys(argTypes),
|
|
61
|
+
|
|
62
|
+
computed: {
|
|
63
|
+
events: getterEvents,
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
template: `
|
|
67
|
+
<UnnnicDropArea v-bind="$props" v-on="events">
|
|
68
|
+
<template #title>Title Slot</template>
|
|
69
|
+
<template #subtitle>Subtitle Slot</template>
|
|
70
|
+
</UnnnicDropArea>
|
|
71
|
+
`,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const Default = Template.bind({});
|
|
75
|
+
Default.args = {};
|
|
76
|
+
|
|
77
|
+
export const WithTitleAndSubtitleSlots = TemplateWithTitleAndSubtitleSlots.bind(
|
|
78
|
+
{},
|
|
79
|
+
);
|
|
80
|
+
WithTitleAndSubtitleSlots.args = {};
|