vueless 0.0.158 → 0.0.160
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/package.json +1 -1
- package/ui.button-toggle/configs/default.config.js +3 -3
- package/ui.button-toggle-item/configs/default.config.js +8 -2
- package/ui.form-input-file/composables/attrs.composable.js +12 -12
- package/ui.form-input-file/configs/default.config.js +11 -13
- package/ui.form-input-file/index.stories.js +33 -0
- package/ui.form-input-file/index.vue +67 -20
- package/ui.text-alert/configs/default.config.js +1 -5
- package/ui.text-file/composables/attrs.composable.js +12 -11
- package/ui.text-file/configs/default.config.js +10 -5
- package/ui.text-file/constants/index.js +5 -0
- package/ui.text-file/index.vue +17 -5
- package/ui.text-files/composables/attrs.composable.js +13 -4
- package/ui.text-files/configs/default.config.js +9 -2
- package/ui.text-files/index.stories.js +3 -3
- package/ui.text-files/index.vue +50 -29
- package/web-types.json +30 -3
package/package.json
CHANGED
|
@@ -13,13 +13,13 @@ export default /*tw*/ {
|
|
|
13
13
|
separated: {
|
|
14
14
|
false: `
|
|
15
15
|
flex-nowrap -space-x-px gap-0
|
|
16
|
-
[
|
|
17
|
-
[
|
|
16
|
+
[&>:first-child]:rounded-l-lg [&>:last-child]:rounded-r-lg
|
|
17
|
+
[&>:first-child>*>*]:rounded-l-lg [&>:last-child>*>*]:rounded-r-lg
|
|
18
18
|
`,
|
|
19
19
|
},
|
|
20
20
|
},
|
|
21
21
|
compoundVariants: [
|
|
22
|
-
{ separated: false, variant: "thirdary", class: "space-x-
|
|
22
|
+
{ separated: false, variant: "thirdary", class: "space-x-px" },
|
|
23
23
|
{ separated: false, multiple: true, class: "space-x-px" },
|
|
24
24
|
],
|
|
25
25
|
},
|
|
@@ -12,7 +12,13 @@ export default /*tw*/ {
|
|
|
12
12
|
false: "rounded-none",
|
|
13
13
|
},
|
|
14
14
|
variant: {
|
|
15
|
-
thirdary:
|
|
15
|
+
thirdary: `
|
|
16
|
+
!text-gray-900 bg-brand-600
|
|
17
|
+
border-transparent bg-opacity-10
|
|
18
|
+
hover:border-transparent hover:bg-opacity-15
|
|
19
|
+
focus:border-transparent focus:bg-opacity-15
|
|
20
|
+
active:border-transparent active:bg-opacity-20
|
|
21
|
+
`,
|
|
16
22
|
},
|
|
17
23
|
},
|
|
18
24
|
},
|
|
@@ -23,7 +29,7 @@ export default /*tw*/ {
|
|
|
23
29
|
variant: {
|
|
24
30
|
primary: "!text-white bg-brand-600 border-brand-600 disabled:border-brand-600",
|
|
25
31
|
secondary: "text-brand-600 border-brand-600 disabled:border-brand-600 bg-brand-600 bg-opacity-10",
|
|
26
|
-
thirdary: "
|
|
32
|
+
thirdary: " bg-brand-600 bg-opacity-20 hover:bg-opacity-20 focus:bg-opacity-20",
|
|
27
33
|
},
|
|
28
34
|
},
|
|
29
35
|
},
|
|
@@ -6,7 +6,7 @@ import defaultConfig from "../configs/default.config";
|
|
|
6
6
|
|
|
7
7
|
export function useAttrs(props) {
|
|
8
8
|
const { config, getAttrs } = useUI(defaultConfig, () => props.config);
|
|
9
|
-
const { dropzoneWrapper, placeholder,
|
|
9
|
+
const { dropzoneWrapper, placeholder, contentWrapper } = config.value;
|
|
10
10
|
|
|
11
11
|
const cvaDropzoneWrapper = cva({
|
|
12
12
|
base: dropzoneWrapper.base,
|
|
@@ -20,10 +20,10 @@ export function useAttrs(props) {
|
|
|
20
20
|
compoundVariants: placeholder.compoundVariants,
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
const
|
|
24
|
-
base:
|
|
25
|
-
variants:
|
|
26
|
-
compoundVariants:
|
|
23
|
+
const cvaContentWrapper = cva({
|
|
24
|
+
base: contentWrapper.base,
|
|
25
|
+
variants: contentWrapper.variants,
|
|
26
|
+
compoundVariants: contentWrapper.compoundVariants,
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
const dropzoneWrapperClasses = computed(() =>
|
|
@@ -41,9 +41,9 @@ export function useAttrs(props) {
|
|
|
41
41
|
}),
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const contentWrapperClasses = computed(() =>
|
|
45
|
+
cvaContentWrapper({
|
|
46
|
+
multiple: props.multiple,
|
|
47
47
|
}),
|
|
48
48
|
);
|
|
49
49
|
|
|
@@ -51,14 +51,14 @@ export function useAttrs(props) {
|
|
|
51
51
|
const buttonAttrs = getAttrs("button", { isComponent: true });
|
|
52
52
|
const dropzoneWrapperAttrs = getAttrs("dropzoneWrapper", { classes: dropzoneWrapperClasses });
|
|
53
53
|
const descriptionAttrs = getAttrs("description", { isComponent: true });
|
|
54
|
-
const contentWrapperAttrs = getAttrs("contentWrapper");
|
|
55
54
|
const buttonWrapperAttrs = getAttrs("buttonWrapper");
|
|
56
55
|
const placeholderAttrs = getAttrs("placeholder", { classes: placeholderClasses });
|
|
57
56
|
const clearIconAttrs = getAttrs("clearIcon", { isComponent: true });
|
|
57
|
+
const removeItemIconAttrs = getAttrs("removeItemIcon", { isComponent: true });
|
|
58
58
|
const chooseFileIconAttrs = getAttrs("chooseFileIcon", { isComponent: true });
|
|
59
59
|
const inputAttrs = getAttrs("input");
|
|
60
|
-
const fileListAttrs = getAttrs("fileList");
|
|
61
|
-
const
|
|
60
|
+
const fileListAttrs = getAttrs("fileList", { isComponent: true });
|
|
61
|
+
const contentWrapperAttrs = getAttrs("contentWrapper", { classes: contentWrapperClasses });
|
|
62
62
|
|
|
63
63
|
return {
|
|
64
64
|
config,
|
|
@@ -72,7 +72,7 @@ export function useAttrs(props) {
|
|
|
72
72
|
placeholderAttrs,
|
|
73
73
|
fileListAttrs,
|
|
74
74
|
buttonWrapperAttrs,
|
|
75
|
-
selectedItemAttrs,
|
|
76
75
|
chooseFileIconAttrs,
|
|
76
|
+
removeItemIconAttrs,
|
|
77
77
|
};
|
|
78
78
|
}
|
|
@@ -11,7 +11,7 @@ export default /*tw*/ {
|
|
|
11
11
|
},
|
|
12
12
|
dropzoneWrapper: {
|
|
13
13
|
base: `
|
|
14
|
-
size-auto w-full rounded border border-
|
|
14
|
+
size-auto w-full rounded border border-solid border-gray-300 bg-white
|
|
15
15
|
p-4 px-5 py-6 hover:border-gray-400
|
|
16
16
|
`,
|
|
17
17
|
variants: {
|
|
@@ -21,24 +21,20 @@ export default /*tw*/ {
|
|
|
21
21
|
},
|
|
22
22
|
compoundVariants: [
|
|
23
23
|
{ labelAlign: "topInside", label: true, size: "sm", class: "pt-8" },
|
|
24
|
-
{ labelAlign: "topInside", label: true, size: "md", class: "
|
|
24
|
+
{ labelAlign: "topInside", label: true, size: "md", class: "pt-10" },
|
|
25
25
|
{ labelAlign: "topInside", label: true, size: "lg", class: "pt-12" },
|
|
26
26
|
],
|
|
27
27
|
},
|
|
28
28
|
description: "text-gray-700",
|
|
29
|
-
contentWrapper:
|
|
30
|
-
|
|
31
|
-
placeholder: {
|
|
32
|
-
base: "pr-4 text-gray-700 flex-grow",
|
|
29
|
+
contentWrapper: {
|
|
30
|
+
base: "relative mt-3 flex w-full gap-6 justify-between items-start rounded bg-brand-50 p-3",
|
|
33
31
|
variants: {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
md: "text-base",
|
|
37
|
-
lg: "text-lg",
|
|
32
|
+
multiple: {
|
|
33
|
+
false: "items-center",
|
|
38
34
|
},
|
|
39
35
|
},
|
|
40
36
|
},
|
|
41
|
-
|
|
37
|
+
placeholder: {
|
|
42
38
|
base: "pr-4 text-gray-700 flex-grow",
|
|
43
39
|
variants: {
|
|
44
40
|
size: {
|
|
@@ -53,8 +49,10 @@ export default /*tw*/ {
|
|
|
53
49
|
chooseFileIconName: "attach_file",
|
|
54
50
|
clearIcon: "",
|
|
55
51
|
clearIconName: "close",
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
removeItemIcon: "",
|
|
53
|
+
removeItemIconName: "close",
|
|
54
|
+
dropzoneWrapperHover: "border-gray-400 border-dashed",
|
|
55
|
+
dropzoneWrapperError: "hover:border-red-400 border-dashed border-red-300",
|
|
58
56
|
input: "sr-only pointer-events-none size-0 opacity-0",
|
|
59
57
|
buttonWrapper: "flex gap-4 items-center",
|
|
60
58
|
i18n: {
|
|
@@ -10,6 +10,9 @@ export default {
|
|
|
10
10
|
id: "30232",
|
|
11
11
|
title: "Form Inputs & Controls / Input File",
|
|
12
12
|
component: UInputFile,
|
|
13
|
+
args: {
|
|
14
|
+
label: "Vueless file input",
|
|
15
|
+
},
|
|
13
16
|
argTypes: {
|
|
14
17
|
...getArgTypes(UInputFile.name),
|
|
15
18
|
},
|
|
@@ -37,6 +40,27 @@ const DefaultTemplate = (args) => ({
|
|
|
37
40
|
`,
|
|
38
41
|
});
|
|
39
42
|
|
|
43
|
+
const LabelAlignTemplate = (args, { argTypes } = {}) => ({
|
|
44
|
+
components: { UInputFile, URow },
|
|
45
|
+
setup() {
|
|
46
|
+
return {
|
|
47
|
+
args,
|
|
48
|
+
alignOptions: argTypes.labelAlign.options,
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
template: `
|
|
52
|
+
<URow class="!flex-col" gap="xl">
|
|
53
|
+
<div v-for="(align, index) in alignOptions" :key="index">
|
|
54
|
+
<UInputFile
|
|
55
|
+
:label-align="align"
|
|
56
|
+
v-bind="args"
|
|
57
|
+
:label="align"
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
</URow>
|
|
61
|
+
`,
|
|
62
|
+
});
|
|
63
|
+
|
|
40
64
|
const SizesTemplate = (args, { argTypes } = {}) => ({
|
|
41
65
|
components: { UInputFile, URow },
|
|
42
66
|
setup() {
|
|
@@ -60,8 +84,17 @@ const SizesTemplate = (args, { argTypes } = {}) => ({
|
|
|
60
84
|
export const Default = DefaultTemplate.bind({});
|
|
61
85
|
Default.args = {};
|
|
62
86
|
|
|
87
|
+
export const multiple = DefaultTemplate.bind({});
|
|
88
|
+
multiple.args = { multiple: true };
|
|
89
|
+
|
|
90
|
+
export const allowedFileTypes = DefaultTemplate.bind({});
|
|
91
|
+
allowedFileTypes.args = { allowedFileTypes: ["png", "jpeg"], label: "Allow only png and jpeg" };
|
|
92
|
+
|
|
63
93
|
export const error = DefaultTemplate.bind({});
|
|
64
94
|
error.args = { error: "some error" };
|
|
65
95
|
|
|
66
96
|
export const sizes = SizesTemplate.bind({});
|
|
67
97
|
sizes.args = {};
|
|
98
|
+
|
|
99
|
+
export const labelAlign = LabelAlignTemplate.bind({});
|
|
100
|
+
labelAlign.args = {};
|
|
@@ -9,18 +9,21 @@
|
|
|
9
9
|
|
|
10
10
|
<span v-if="!isValue" v-bind="placeholderAttrs" v-text="currentLocale.noFile" />
|
|
11
11
|
|
|
12
|
-
<
|
|
13
|
-
<template
|
|
14
|
-
<
|
|
15
|
-
v-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
<UFiles :size="size" v-bind="fileListAttrs" :file-list="fileList">
|
|
13
|
+
<template #right="{ file }">
|
|
14
|
+
<UIcon
|
|
15
|
+
v-if="props.multiple"
|
|
16
|
+
pill
|
|
17
|
+
internal
|
|
18
|
+
interactive
|
|
19
|
+
size="2xs"
|
|
20
|
+
:name="config.removeItemIconName"
|
|
21
|
+
:data-cy="`${dataCy}-remove-item`"
|
|
22
|
+
v-bind="removeItemIconAttrs"
|
|
23
|
+
@click.stop.prevent="onClickRemoveItem(file.id)"
|
|
19
24
|
/>
|
|
20
25
|
</template>
|
|
21
|
-
|
|
22
|
-
<span v-else v-bind="selectedItemAttrs" v-text="currentFiles.name" />
|
|
23
|
-
</div>
|
|
26
|
+
</UFiles>
|
|
24
27
|
|
|
25
28
|
<div v-bind="buttonWrapperAttrs">
|
|
26
29
|
<template v-if="Array.isArray(currentFiles) || !currentFiles">
|
|
@@ -31,6 +34,7 @@
|
|
|
31
34
|
variant="thirdary"
|
|
32
35
|
:size="nestedComponentSize"
|
|
33
36
|
:label="currentLocale.uploadFile"
|
|
37
|
+
:data-cy="`${dataCy}-upload`"
|
|
34
38
|
v-bind="buttonAttrs"
|
|
35
39
|
>
|
|
36
40
|
<template #right>
|
|
@@ -61,6 +65,7 @@
|
|
|
61
65
|
interactive
|
|
62
66
|
:size="nestedComponentSize"
|
|
63
67
|
:name="config.clearIconName"
|
|
68
|
+
:data-cy="`${dataCy}-clear`"
|
|
64
69
|
v-bind="clearIconAttrs"
|
|
65
70
|
@click="onClickResetFiles"
|
|
66
71
|
/>
|
|
@@ -71,13 +76,14 @@
|
|
|
71
76
|
</template>
|
|
72
77
|
|
|
73
78
|
<script setup>
|
|
74
|
-
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from "vue";
|
|
79
|
+
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
|
75
80
|
import { merge } from "lodash-es";
|
|
76
81
|
|
|
77
82
|
import UText from "../ui.text-block";
|
|
78
83
|
import UIcon from "../ui.image-icon";
|
|
79
84
|
import ULabel from "../ui.form-label";
|
|
80
85
|
import UButton from "../ui.button";
|
|
86
|
+
import UFiles from "../ui.text-files";
|
|
81
87
|
|
|
82
88
|
import UIService, { getRandomId } from "../service.ui";
|
|
83
89
|
import { getFileMbSize } from "./services/fileForm.service";
|
|
@@ -178,6 +184,14 @@ const props = defineProps({
|
|
|
178
184
|
type: Object,
|
|
179
185
|
default: () => ({}),
|
|
180
186
|
},
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Data-cy attribute for automated testing.
|
|
190
|
+
*/
|
|
191
|
+
dataCy: {
|
|
192
|
+
type: String,
|
|
193
|
+
default: "",
|
|
194
|
+
},
|
|
181
195
|
});
|
|
182
196
|
|
|
183
197
|
const emit = defineEmits(["update:modelValue", "update:error"]);
|
|
@@ -200,7 +214,7 @@ const {
|
|
|
200
214
|
inputAttrs,
|
|
201
215
|
fileListAttrs,
|
|
202
216
|
buttonWrapperAttrs,
|
|
203
|
-
|
|
217
|
+
removeItemIconAttrs,
|
|
204
218
|
} = useAttrs(props);
|
|
205
219
|
|
|
206
220
|
const i18nGlobal = tm(UInputFile);
|
|
@@ -234,7 +248,7 @@ const accept = computed(() => {
|
|
|
234
248
|
|
|
235
249
|
const isValue = computed(() => {
|
|
236
250
|
return (
|
|
237
|
-
(Array.isArray(currentFiles.value) && currentFiles.value
|
|
251
|
+
(Array.isArray(currentFiles.value) && currentFiles.value?.length) ||
|
|
238
252
|
(!Array.isArray(currentFiles.value) && currentFiles.value)
|
|
239
253
|
);
|
|
240
254
|
});
|
|
@@ -249,6 +263,14 @@ const nestedComponentSize = computed(() => {
|
|
|
249
263
|
return size;
|
|
250
264
|
});
|
|
251
265
|
|
|
266
|
+
const fileList = computed(() => {
|
|
267
|
+
if (Array.isArray(currentFiles.value)) {
|
|
268
|
+
return currentFiles.value;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return currentFiles.value ? [currentFiles.value] : [];
|
|
272
|
+
});
|
|
273
|
+
|
|
252
274
|
onMounted(() => {
|
|
253
275
|
dropZoneRef.value.addEventListener("dragover", onDragOver);
|
|
254
276
|
dropZoneRef.value.addEventListener("dragleave", onDragLeave);
|
|
@@ -259,6 +281,23 @@ onBeforeUnmount(() => {
|
|
|
259
281
|
dropZoneRef.value.removeEventListener("dragleave", onDragLeave);
|
|
260
282
|
});
|
|
261
283
|
|
|
284
|
+
watch(
|
|
285
|
+
() => props.multiple,
|
|
286
|
+
() => {
|
|
287
|
+
if (!props.multiple && Array.isArray(currentFiles.value)) {
|
|
288
|
+
currentFiles.value = currentFiles.value[0];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (props.multiple && !Array.isArray(currentFiles.value)) {
|
|
292
|
+
currentFiles.value = currentFiles.value ? [currentFiles.value] : [];
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
function removeDuplicates(files) {
|
|
298
|
+
return files.filter((file) => !fileList.value.find((item) => item.name === file.name));
|
|
299
|
+
}
|
|
300
|
+
|
|
262
301
|
function validate(file) {
|
|
263
302
|
const targetFileSize = getFileMbSize(file);
|
|
264
303
|
|
|
@@ -287,7 +326,7 @@ function onChangeFile(event) {
|
|
|
287
326
|
}
|
|
288
327
|
|
|
289
328
|
currentFiles.value = props.multiple
|
|
290
|
-
? [...currentFiles.value, Array.from(event.target.files)
|
|
329
|
+
? [...(currentFiles.value || []), ...removeDuplicates(Array.from(event.target.files))]
|
|
291
330
|
: Array.from(event.target.files).at(0);
|
|
292
331
|
|
|
293
332
|
if (fileInputRef.value) fileInputRef.value.value = "";
|
|
@@ -314,24 +353,32 @@ function onDragLeave(event) {
|
|
|
314
353
|
function onDrop(event) {
|
|
315
354
|
event.preventDefault();
|
|
316
355
|
|
|
317
|
-
let
|
|
356
|
+
let targetFiles = null;
|
|
318
357
|
|
|
319
358
|
if (event.dataTransfer.items) {
|
|
320
|
-
|
|
359
|
+
targetFiles = [...event.dataTransfer.items]
|
|
360
|
+
.filter((item) => item.kind === "file")
|
|
361
|
+
.map((item) => item.getAsFile());
|
|
321
362
|
} else {
|
|
322
|
-
|
|
363
|
+
targetFiles = [...event.dataTransfer.files];
|
|
323
364
|
}
|
|
324
365
|
|
|
325
|
-
if (
|
|
366
|
+
if (targetFiles.length) targetFiles.forEach(validate);
|
|
326
367
|
|
|
327
368
|
nextTick(() => {
|
|
328
|
-
if (currentError.value || !
|
|
369
|
+
if (currentError.value || !targetFiles.length) {
|
|
329
370
|
onClickResetFiles();
|
|
330
371
|
|
|
331
372
|
return;
|
|
332
373
|
}
|
|
333
374
|
|
|
334
|
-
currentFiles.value = props.multiple
|
|
375
|
+
currentFiles.value = props.multiple
|
|
376
|
+
? [...(currentFiles.value || []), ...removeDuplicates(targetFiles)]
|
|
377
|
+
: targetFiles[0];
|
|
335
378
|
});
|
|
336
379
|
}
|
|
380
|
+
|
|
381
|
+
function onClickRemoveItem(id) {
|
|
382
|
+
currentFiles.value = currentFiles.value?.filter((file) => file.name !== id);
|
|
383
|
+
}
|
|
337
384
|
</script>
|
|
@@ -43,9 +43,5 @@ export default /*tw*/ {
|
|
|
43
43
|
bordered: false,
|
|
44
44
|
closeIcon: false,
|
|
45
45
|
},
|
|
46
|
-
safelist: (colors) => [
|
|
47
|
-
{ pattern: `bg-(${colors})-50` },
|
|
48
|
-
{ pattern: `text-(${colors})-700` },
|
|
49
|
-
{ pattern: `border-(${colors})-100` },
|
|
50
|
-
],
|
|
46
|
+
safelist: (colors) => [{ pattern: `bg-(${colors})-50` }, { pattern: `text-(${colors})-700` }, { pattern: `border-(${colors})-100` }],
|
|
51
47
|
};
|
|
@@ -6,32 +6,33 @@ import defaultConfig from "../configs/default.config";
|
|
|
6
6
|
|
|
7
7
|
export function useAttrs(props, { focus }) {
|
|
8
8
|
const { config, getAttrs } = useUI(defaultConfig, () => props.config);
|
|
9
|
-
const {
|
|
9
|
+
const { label } = config.value;
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
base:
|
|
13
|
-
variants:
|
|
14
|
-
compoundVariants:
|
|
11
|
+
const cvaLabel = cva({
|
|
12
|
+
base: label.base,
|
|
13
|
+
variants: label.variants,
|
|
14
|
+
compoundVariants: label.compoundVariants,
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
const labelClasses = computed(() =>
|
|
18
|
+
cvaLabel({
|
|
19
19
|
focus: Boolean(focus.value),
|
|
20
|
+
size: props.size,
|
|
20
21
|
}),
|
|
21
22
|
);
|
|
22
23
|
|
|
23
|
-
const
|
|
24
|
+
const labelAttrs = getAttrs("label", { classes: labelClasses });
|
|
24
25
|
const fileAttrs = getAttrs("file", { isComponent: true });
|
|
25
26
|
const infoAttrs = getAttrs("info");
|
|
26
27
|
const iconAttrs = getAttrs("icon", { isComponent: true });
|
|
27
|
-
const
|
|
28
|
+
const imageAttrs = getAttrs("image");
|
|
28
29
|
|
|
29
30
|
return {
|
|
30
31
|
config,
|
|
31
32
|
fileAttrs,
|
|
32
33
|
infoAttrs,
|
|
33
34
|
iconAttrs,
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
labelAttrs,
|
|
36
|
+
imageAttrs,
|
|
36
37
|
};
|
|
37
38
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
2
|
file: "",
|
|
3
|
-
info: "flex items-
|
|
4
|
-
icon: "
|
|
3
|
+
info: "flex items-center gap-2 ",
|
|
4
|
+
icon: "",
|
|
5
5
|
iconName: "description",
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
base: "whitespace-normal
|
|
6
|
+
image: "rounded-sm max-w-7",
|
|
7
|
+
label: {
|
|
8
|
+
base: "text-gray-700 whitespace-normal hover:underline hover:decoration-dashed hover:underline-offset-4",
|
|
9
9
|
variants: {
|
|
10
10
|
focus: {
|
|
11
11
|
true: "underline decoration-dashed underline-offset-4",
|
|
12
12
|
},
|
|
13
|
+
size: {
|
|
14
|
+
sm: "text-sm",
|
|
15
|
+
md: "text-base",
|
|
16
|
+
lg: "text-lg",
|
|
17
|
+
},
|
|
13
18
|
},
|
|
14
19
|
},
|
|
15
20
|
};
|
package/ui.text-file/index.vue
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<ULink :url="url" no-ring target-blank :data-cy="dataCy" v-bind="fileAttrs">
|
|
3
|
-
<slot name="left" :file="{ id,
|
|
3
|
+
<slot name="left" :file="{ id, label, url, imageUrl }" />
|
|
4
4
|
|
|
5
5
|
<div v-bind="infoAttrs">
|
|
6
|
-
<img v-if="imageUrl" :src="imageUrl" v-bind="
|
|
6
|
+
<img v-if="imageUrl" :src="imageUrl" v-bind="imageAttrs" />
|
|
7
7
|
|
|
8
8
|
<UIcon
|
|
9
9
|
v-else
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
@blur="onBlur"
|
|
17
17
|
/>
|
|
18
18
|
|
|
19
|
-
<span v-bind="
|
|
19
|
+
<span v-bind="labelAttrs" v-text="label" />
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
22
|
<slot name="right" :file="{ id, label, url, imageUrl }" />
|
|
@@ -28,9 +28,12 @@ import { ref } from "vue";
|
|
|
28
28
|
|
|
29
29
|
import ULink from "../ui.button-link";
|
|
30
30
|
import UIcon from "../ui.image-icon";
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
import UIService, { getRandomId } from "../service.ui";
|
|
32
33
|
|
|
33
34
|
import { useAttrs } from "./composables/attrs.composable";
|
|
35
|
+
import { UFile } from "./constants";
|
|
36
|
+
import defaultConfig from "./configs/default.config";
|
|
34
37
|
|
|
35
38
|
/* Should be a string for correct web-types gen */
|
|
36
39
|
defineOptions({ name: "UFile", inheritAttrs: false });
|
|
@@ -69,6 +72,15 @@ const props = defineProps({
|
|
|
69
72
|
default: () => getRandomId(),
|
|
70
73
|
},
|
|
71
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Set size.
|
|
77
|
+
* @values sm, md, lg
|
|
78
|
+
*/
|
|
79
|
+
size: {
|
|
80
|
+
type: String,
|
|
81
|
+
default: UIService.get(defaultConfig, UFile).default.size,
|
|
82
|
+
},
|
|
83
|
+
|
|
72
84
|
/**
|
|
73
85
|
* Sets data-cy attribute for automated testing.
|
|
74
86
|
*/
|
|
@@ -80,7 +92,7 @@ const props = defineProps({
|
|
|
80
92
|
|
|
81
93
|
const focus = ref(false);
|
|
82
94
|
|
|
83
|
-
const { config, fileAttrs, infoAttrs, iconAttrs,
|
|
95
|
+
const { config, fileAttrs, infoAttrs, iconAttrs, labelAttrs, imageAttrs } = useAttrs(props, {
|
|
84
96
|
focus,
|
|
85
97
|
});
|
|
86
98
|
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
1
2
|
import useUI from "../../composable.ui";
|
|
3
|
+
import { cva } from "../../service.ui";
|
|
2
4
|
|
|
3
5
|
import defaultConfig from "../configs/default.config";
|
|
4
6
|
|
|
5
7
|
export function useAttrs(props) {
|
|
6
|
-
const { getAttrs } = useUI(defaultConfig, () => props.config);
|
|
8
|
+
const { getAttrs, config } = useUI(defaultConfig, () => props.config);
|
|
9
|
+
const { body } = config.value;
|
|
10
|
+
|
|
11
|
+
const cvaBody = cva({
|
|
12
|
+
base: body.base,
|
|
13
|
+
variants: body.variants,
|
|
14
|
+
compoundVariants: body.compoundVariants,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const bodyClasses = computed(() => cvaBody({ label: Boolean(props.label) }));
|
|
7
18
|
|
|
8
|
-
const filesAttrs = getAttrs("files");
|
|
9
19
|
const labelAttrs = getAttrs("label");
|
|
10
|
-
const bodyAttrs = getAttrs("body");
|
|
20
|
+
const bodyAttrs = getAttrs("body", { classes: bodyClasses });
|
|
11
21
|
const fileAttrs = getAttrs("file", { isComponent: true });
|
|
12
22
|
|
|
13
23
|
return {
|
|
14
|
-
filesAttrs,
|
|
15
24
|
labelAttrs,
|
|
16
25
|
bodyAttrs,
|
|
17
26
|
fileAttrs,
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
files: "",
|
|
3
2
|
label: "block text-sm font-normal text-gray-500",
|
|
4
|
-
body:
|
|
3
|
+
body: {
|
|
4
|
+
base: "flex gap-4 flex-col",
|
|
5
|
+
variants: {
|
|
6
|
+
label: {
|
|
7
|
+
true: "mt-4",
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
},
|
|
5
11
|
file: "block",
|
|
6
12
|
defaultVariants: {
|
|
7
13
|
placement: "topInside",
|
|
14
|
+
size: "md",
|
|
8
15
|
},
|
|
9
16
|
};
|
|
@@ -11,9 +11,9 @@ export default {
|
|
|
11
11
|
component: UFiles,
|
|
12
12
|
args: {
|
|
13
13
|
label: "Label",
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
fileList: [
|
|
15
|
+
new File(["foo"], "foo.txt", { type: "text/plain" }),
|
|
16
|
+
new File(["bar"], "foo.txt", { type: "text/plain" }),
|
|
17
17
|
],
|
|
18
18
|
},
|
|
19
19
|
argTypes: {
|
package/ui.text-files/index.vue
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
<ULabel :label="label" :description="description" v-bind="labelAttrs">
|
|
3
|
+
<div v-bind="bodyAttrs">
|
|
4
|
+
<slot>
|
|
5
|
+
<UFile
|
|
6
|
+
v-for="file in formattedFileList"
|
|
7
|
+
:id="file.id"
|
|
8
|
+
:key="file.id"
|
|
9
|
+
:label="file.label"
|
|
10
|
+
:url="file.url"
|
|
11
|
+
:image-url="file.imageUrl"
|
|
12
|
+
:size="size"
|
|
13
|
+
v-bind="fileAttrs"
|
|
14
|
+
:data-cy="`${dataCy}-item`"
|
|
15
|
+
>
|
|
16
|
+
<template #left="{ file: currentFile }">
|
|
17
|
+
<!-- @slot Use it to add something left. -->
|
|
18
|
+
<slot name="left" :file="currentFile" />
|
|
19
|
+
</template>
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</div>
|
|
21
|
+
<template #right="{ file: currentFile }">
|
|
22
|
+
<!-- @slot Use it to add something right. -->
|
|
23
|
+
<slot name="right" :file="currentFile" />
|
|
24
|
+
</template>
|
|
25
|
+
</UFile>
|
|
26
|
+
</slot>
|
|
27
|
+
</div>
|
|
28
|
+
</ULabel>
|
|
29
29
|
</template>
|
|
30
30
|
|
|
31
31
|
<script setup>
|
|
@@ -36,6 +36,7 @@ import UIService from "../service.ui";
|
|
|
36
36
|
import { UFiles } from "./constants";
|
|
37
37
|
import defaultConfig from "./configs/default.config";
|
|
38
38
|
import { useAttrs } from "./composables/attrs.composable";
|
|
39
|
+
import { computed } from "vue";
|
|
39
40
|
|
|
40
41
|
/* Should be a string for correct web-types gen */
|
|
41
42
|
defineOptions({ name: "UFiles", inheritAttrs: false });
|
|
@@ -67,13 +68,22 @@ const props = defineProps({
|
|
|
67
68
|
},
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
|
-
*
|
|
71
|
+
* List of file objects.
|
|
71
72
|
*/
|
|
72
|
-
|
|
73
|
+
fileList: {
|
|
73
74
|
type: Array,
|
|
74
75
|
default: () => [],
|
|
75
76
|
},
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Set size.
|
|
80
|
+
* @values sm, md, lg
|
|
81
|
+
*/
|
|
82
|
+
size: {
|
|
83
|
+
type: String,
|
|
84
|
+
default: UIService.get(defaultConfig, UFiles).default.size,
|
|
85
|
+
},
|
|
86
|
+
|
|
77
87
|
/**
|
|
78
88
|
* Sets data-cy attribute for automated testing.
|
|
79
89
|
*/
|
|
@@ -83,5 +93,16 @@ const props = defineProps({
|
|
|
83
93
|
},
|
|
84
94
|
});
|
|
85
95
|
|
|
86
|
-
const {
|
|
96
|
+
const { labelAttrs, bodyAttrs, fileAttrs } = useAttrs(props);
|
|
97
|
+
|
|
98
|
+
const formattedFileList = computed(() =>
|
|
99
|
+
props.fileList.map((file) => {
|
|
100
|
+
return {
|
|
101
|
+
id: file.name,
|
|
102
|
+
label: file.name,
|
|
103
|
+
url: URL.createObjectURL(file),
|
|
104
|
+
imageUrl: file.type.includes("image") ? URL.createObjectURL(file) : undefined,
|
|
105
|
+
};
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
87
108
|
</script>
|
package/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"framework": "vue",
|
|
3
3
|
"name": "vueless",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.160",
|
|
5
5
|
"contributions": {
|
|
6
6
|
"html": {
|
|
7
7
|
"description-markup": "markdown",
|
|
@@ -2840,6 +2840,15 @@
|
|
|
2840
2840
|
},
|
|
2841
2841
|
"default": "() => getRandomId()"
|
|
2842
2842
|
},
|
|
2843
|
+
{
|
|
2844
|
+
"name": "size",
|
|
2845
|
+
"description": "Set size.",
|
|
2846
|
+
"value": {
|
|
2847
|
+
"kind": "expression",
|
|
2848
|
+
"type": "'sm' | 'md' | 'lg'"
|
|
2849
|
+
},
|
|
2850
|
+
"default": "UIService.get(defaultConfig, UFile).default.size"
|
|
2851
|
+
},
|
|
2843
2852
|
{
|
|
2844
2853
|
"name": "dataCy",
|
|
2845
2854
|
"description": "Sets data-cy attribute for automated testing.",
|
|
@@ -2895,14 +2904,23 @@
|
|
|
2895
2904
|
"default": "topInside"
|
|
2896
2905
|
},
|
|
2897
2906
|
{
|
|
2898
|
-
"name": "
|
|
2899
|
-
"description": "
|
|
2907
|
+
"name": "fileList",
|
|
2908
|
+
"description": "List of file objects.",
|
|
2900
2909
|
"value": {
|
|
2901
2910
|
"kind": "expression",
|
|
2902
2911
|
"type": "array"
|
|
2903
2912
|
},
|
|
2904
2913
|
"default": "[]"
|
|
2905
2914
|
},
|
|
2915
|
+
{
|
|
2916
|
+
"name": "size",
|
|
2917
|
+
"description": "Set size.",
|
|
2918
|
+
"value": {
|
|
2919
|
+
"kind": "expression",
|
|
2920
|
+
"type": "'sm' | 'md' | 'lg'"
|
|
2921
|
+
},
|
|
2922
|
+
"default": "md"
|
|
2923
|
+
},
|
|
2906
2924
|
{
|
|
2907
2925
|
"name": "dataCy",
|
|
2908
2926
|
"description": "Sets data-cy attribute for automated testing.",
|
|
@@ -3595,6 +3613,15 @@
|
|
|
3595
3613
|
"type": "object"
|
|
3596
3614
|
},
|
|
3597
3615
|
"default": "{}"
|
|
3616
|
+
},
|
|
3617
|
+
{
|
|
3618
|
+
"name": "dataCy",
|
|
3619
|
+
"description": "Data-cy attribute for automated testing.",
|
|
3620
|
+
"value": {
|
|
3621
|
+
"kind": "expression",
|
|
3622
|
+
"type": "string"
|
|
3623
|
+
},
|
|
3624
|
+
"default": "\"\""
|
|
3598
3625
|
}
|
|
3599
3626
|
],
|
|
3600
3627
|
"events": [
|