@finema/core 1.4.106 → 1.4.108
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/module.d.mts +1 -0
- package/dist/module.d.ts +1 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +4 -2
- package/dist/runtime/components/Button/index.vue +0 -1
- package/dist/runtime/components/Form/Fields.vue +15 -0
- package/dist/runtime/components/Form/InputTags/index.vue +134 -0
- package/dist/runtime/components/Form/InputTags/types.d.ts +11 -0
- package/dist/runtime/components/Form/InputTags/types.mjs +0 -0
- package/dist/runtime/components/Form/InputUploadDropzoneImageAutoMultiple/item.vue +2 -2
- package/dist/runtime/components/Form/InputUploadImageAuto/index.vue +222 -0
- package/dist/runtime/components/Form/InputUploadImageAuto/types.d.ts +19 -0
- package/dist/runtime/components/Form/InputUploadImageAuto/types.mjs +0 -0
- package/dist/runtime/components/Form/types.d.ts +5 -1
- package/dist/runtime/components/Form/types.mjs +2 -0
- package/dist/runtime/components/Loader.vue +1 -1
- package/dist/runtime/components/QRCode.vue +22 -21
- package/dist/runtime/types/config.d.ts +1 -1
- package/dist/runtime/ui.config/index.d.ts +2 -0
- package/dist/runtime/ui.config/index.mjs +2 -0
- package/dist/runtime/ui.config/tags.d.ts +25 -0
- package/dist/runtime/ui.config/tags.mjs +25 -0
- package/dist/runtime/ui.config/uploadDropzoneImage.mjs +2 -2
- package/dist/runtime/ui.config/uploadImage.d.ts +34 -0
- package/dist/runtime/ui.config/uploadImage.mjs +36 -0
- package/package.json +5 -3
package/dist/module.d.mts
CHANGED
package/dist/module.d.ts
CHANGED
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineNuxtModule, createResolver, installModule, addPlugin, addComponentsDir, addImportsDir } from '@nuxt/kit';
|
|
2
2
|
|
|
3
3
|
const name = "@finema/core";
|
|
4
|
-
const version = "1.4.
|
|
4
|
+
const version = "1.4.108";
|
|
5
5
|
|
|
6
6
|
const colors = {
|
|
7
7
|
black: "#20243E",
|
|
@@ -398,7 +398,9 @@ const module = defineNuxtModule({
|
|
|
398
398
|
};
|
|
399
399
|
await installModule("@pinia/nuxt");
|
|
400
400
|
await installModule("@vee-validate/nuxt", veeValidateNuxtOptions);
|
|
401
|
-
|
|
401
|
+
if (!options.securityDisabled) {
|
|
402
|
+
await installModule("nuxt-security", nuxtSecurityOptions);
|
|
403
|
+
}
|
|
402
404
|
addPlugin({
|
|
403
405
|
src: resolve(runtimeDir, "plugin")
|
|
404
406
|
});
|
|
@@ -123,6 +123,14 @@
|
|
|
123
123
|
v-bind="getFieldBinding(option)"
|
|
124
124
|
v-on="option.on ?? {}"
|
|
125
125
|
/>
|
|
126
|
+
<FormInputUploadImageAuto
|
|
127
|
+
v-else-if="option.type === INPUT_TYPES.UPLOAD_IMAGE_AUTO"
|
|
128
|
+
:class="option.class"
|
|
129
|
+
:form="form"
|
|
130
|
+
:request-options="option.props.requestOptions"
|
|
131
|
+
v-bind="getFieldBinding(option)"
|
|
132
|
+
v-on="option.on ?? {}"
|
|
133
|
+
/>
|
|
126
134
|
<FormInputUploadDropzone
|
|
127
135
|
v-else-if="option.type === INPUT_TYPES.UPLOAD_DROPZONE"
|
|
128
136
|
:class="option.class"
|
|
@@ -161,6 +169,13 @@
|
|
|
161
169
|
v-bind="getFieldBinding(option)"
|
|
162
170
|
v-on="option.on ?? {}"
|
|
163
171
|
/>
|
|
172
|
+
<FormInputTags
|
|
173
|
+
v-else-if="option.type === INPUT_TYPES.TAGS"
|
|
174
|
+
:class="option.class"
|
|
175
|
+
:form="form"
|
|
176
|
+
v-bind="getFieldBinding(option)"
|
|
177
|
+
v-on="option.on ?? {}"
|
|
178
|
+
/>
|
|
164
179
|
<component
|
|
165
180
|
:is="option.component"
|
|
166
181
|
v-else-if="option.type === INPUT_TYPES.COMPONENT"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
+
<div
|
|
4
|
+
:class="[
|
|
5
|
+
ui.base,
|
|
6
|
+
ui.border,
|
|
7
|
+
ui.shadow,
|
|
8
|
+
ui.padding,
|
|
9
|
+
{
|
|
10
|
+
[ui.stages.default]: !wrapperProps.errorMessage,
|
|
11
|
+
[ui.stages.error]: wrapperProps.errorMessage,
|
|
12
|
+
},
|
|
13
|
+
]"
|
|
14
|
+
>
|
|
15
|
+
<p
|
|
16
|
+
v-if="wrapperProps.placeholder && !innerValue && (!value || value.length === 0)"
|
|
17
|
+
:class="[ui.placeholder]"
|
|
18
|
+
@click="focusInput"
|
|
19
|
+
>
|
|
20
|
+
{{ wrapperProps.placeholder }}
|
|
21
|
+
</p>
|
|
22
|
+
<div :class="[ui.innerWrapper]">
|
|
23
|
+
<Badge
|
|
24
|
+
v-for="(text, index) in value"
|
|
25
|
+
:key="index"
|
|
26
|
+
:size="ui.tag.size || (ui.default.tag.size as any)"
|
|
27
|
+
:color="ui.tag.color || (ui.default.tag.color as any)"
|
|
28
|
+
:variant="ui.tag.variant || (ui.default.tag.variant as any)"
|
|
29
|
+
:ui="badgeUi"
|
|
30
|
+
>
|
|
31
|
+
{{ tagPrefix + text }}
|
|
32
|
+
</Badge>
|
|
33
|
+
<input
|
|
34
|
+
ref="inputRef"
|
|
35
|
+
v-model="innerValue"
|
|
36
|
+
:class="[ui.input]"
|
|
37
|
+
:disabled="wrapperProps.isDisabled"
|
|
38
|
+
:name="name"
|
|
39
|
+
:readonly="isReadonly"
|
|
40
|
+
:autofocus="!!autoFocus"
|
|
41
|
+
@blur="onBlur"
|
|
42
|
+
@keyup.delete="onDelete"
|
|
43
|
+
@keyup.enter="onEnter"
|
|
44
|
+
@keyup.space="onSpace"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</FieldWrapper>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<script lang="ts" setup>
|
|
52
|
+
import { ref, toRef, useUI, useUiConfig } from '#imports'
|
|
53
|
+
import { type ITagsFieldProps } from '#core/components/Form/InputTags/types'
|
|
54
|
+
import { tags } from '#core/ui.config'
|
|
55
|
+
import { useFieldHOC } from '#core/composables/useForm'
|
|
56
|
+
import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
|
|
57
|
+
|
|
58
|
+
const config = useUiConfig<typeof tags>(tags, 'tags')
|
|
59
|
+
|
|
60
|
+
const props = withDefaults(defineProps<ITagsFieldProps>(), {
|
|
61
|
+
tagPrefix: '#',
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const emits = defineEmits(['change', 'blur'])
|
|
65
|
+
|
|
66
|
+
const { value, wrapperProps } = useFieldHOC<string[]>(props)
|
|
67
|
+
|
|
68
|
+
const { ui } = useUI('tags', toRef(props, 'ui'), config)
|
|
69
|
+
|
|
70
|
+
const inputRef = ref<HTMLInputElement | null>(null)
|
|
71
|
+
const innerValue = ref<string>('')
|
|
72
|
+
const backspaceCount = ref<number>(0)
|
|
73
|
+
|
|
74
|
+
const operateValue = (input: string) => {
|
|
75
|
+
const tagSet = splitBySpace(input)
|
|
76
|
+
|
|
77
|
+
if (value.value && value.value.length > 0) {
|
|
78
|
+
value.value = [...value.value, ...tagSet]
|
|
79
|
+
} else {
|
|
80
|
+
value.value = tagSet
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
innerValue.value = ''
|
|
84
|
+
|
|
85
|
+
emits('change', value.value)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const onBlur = (e: FocusEvent) => {
|
|
89
|
+
const eventValue = e.target as HTMLInputElement
|
|
90
|
+
|
|
91
|
+
if (!eventValue.value || eventValue.value === '') return
|
|
92
|
+
|
|
93
|
+
operateValue(eventValue.value)
|
|
94
|
+
|
|
95
|
+
emits('blur', eventValue.value)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const onDelete = (e: KeyboardEvent) => {
|
|
99
|
+
if (e.key === 'Backspace') {
|
|
100
|
+
if (innerValue.value === '') {
|
|
101
|
+
backspaceCount.value += 1
|
|
102
|
+
} else {
|
|
103
|
+
backspaceCount.value = 0
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (backspaceCount.value >= 2 && value.value.length > 0) {
|
|
107
|
+
value.value.pop()
|
|
108
|
+
backspaceCount.value = 0
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const onEnter = (e: KeyboardEvent) => {
|
|
114
|
+
if (e.key === 'Enter') {
|
|
115
|
+
operateValue(innerValue.value)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const onSpace = (e: KeyboardEvent) => {
|
|
120
|
+
if (e.key === ' ') {
|
|
121
|
+
operateValue(innerValue.value)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const splitBySpace = (input: string): string[] => {
|
|
126
|
+
const spited = input.split(' ')
|
|
127
|
+
|
|
128
|
+
return spited.filter((item) => item !== '')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const focusInput = () => {
|
|
132
|
+
inputRef.value?.focus()
|
|
133
|
+
}
|
|
134
|
+
</script>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type IFieldProps, type IFormFieldBase, type INPUT_TYPES } from '#core/components/Form/types';
|
|
2
|
+
export interface ITagsFieldProps extends IFieldProps {
|
|
3
|
+
leadingIcon?: string;
|
|
4
|
+
trailingIcon?: string;
|
|
5
|
+
tagPrefix?: string;
|
|
6
|
+
badgeUi?: object | any;
|
|
7
|
+
}
|
|
8
|
+
export type ITagsField = IFormFieldBase<INPUT_TYPES.TAGS, ITagsFieldProps, {
|
|
9
|
+
change?: (value: string[]) => void;
|
|
10
|
+
blur?: (value: string) => void;
|
|
11
|
+
}>;
|
|
File without changes
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<div :class="[ui.imageItem.onPreview.wrapper]">
|
|
21
21
|
<img
|
|
22
22
|
:class="[ui.imageItem.onPreview.previewImgClass]"
|
|
23
|
-
:src="upload.data.value[responseKey]"
|
|
23
|
+
:src="upload.data.value[responseKey || 'url']"
|
|
24
24
|
alt="img"
|
|
25
25
|
/>
|
|
26
26
|
<div :class="[ui.imageItem.onPreview.previewActionWrapper]">
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
/>
|
|
47
47
|
</div>
|
|
48
48
|
<img
|
|
49
|
-
:src="upload.data.value[responseKey]"
|
|
49
|
+
:src="upload.data.value[responseKey || 'url']"
|
|
50
50
|
alt="image-preview"
|
|
51
51
|
class="w-full rounded-lg"
|
|
52
52
|
/>
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
+
<div :class="[ui.base]">
|
|
4
|
+
<input
|
|
5
|
+
ref="fileInputRef"
|
|
6
|
+
type="file"
|
|
7
|
+
class="hidden"
|
|
8
|
+
:name="name"
|
|
9
|
+
:accept="acceptFile"
|
|
10
|
+
:disabled="isDisabled"
|
|
11
|
+
@change="handleChange"
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
<div :class="[ui.imageItem.wrapper]">
|
|
15
|
+
<div v-if="!selectedFile" class="w-full">
|
|
16
|
+
<div :class="[ui.action.addingWrapper]" @click="handleOpenFile">
|
|
17
|
+
<Icon :name="ui.action.addingIcon" :class="[ui.action.addingBtnClass]" />
|
|
18
|
+
<p :class="[ui.action.addingTextClass]">{{ uploadAddLabel }}</p>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<!-- Loading State -->
|
|
23
|
+
<div v-if="selectedFile && upload.status.value.isLoading" class="w-full">
|
|
24
|
+
<div :class="[ui.imageItem.onLoading.wrapper]">
|
|
25
|
+
<div :class="[ui.imageItem.onLoading.percentClass]">{{ percent }}%</div>
|
|
26
|
+
<UProgress :value="percent" />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<!-- Success State -->
|
|
31
|
+
<div v-if="selectedFile && upload.status.value.isSuccess" class="w-full">
|
|
32
|
+
<div :class="[ui.imageItem.onPreview.wrapper]">
|
|
33
|
+
<img
|
|
34
|
+
:class="[ui.imageItem.onPreview.previewImgClass]"
|
|
35
|
+
:src="upload.data.value[responseKey || 'url']"
|
|
36
|
+
alt="img"
|
|
37
|
+
/>
|
|
38
|
+
<div :class="[ui.imageItem.onPreview.previewActionWrapper]">
|
|
39
|
+
<Icon
|
|
40
|
+
title="ดูตัวอย่าง"
|
|
41
|
+
:name="ui.action.previewIcon"
|
|
42
|
+
:class="[ui.imageItem.onPreview.actionBtnClass]"
|
|
43
|
+
@click="() => (isPreviewOpen = true)"
|
|
44
|
+
/>
|
|
45
|
+
<Icon
|
|
46
|
+
title="ลบไฟล์"
|
|
47
|
+
:name="ui.action.deleteIcon"
|
|
48
|
+
:class="[ui.imageItem.onPreview.actionBtnClass]"
|
|
49
|
+
@click="handleDeleteFile"
|
|
50
|
+
/>
|
|
51
|
+
<Modal v-model="isPreviewOpen" size="xl">
|
|
52
|
+
<div class="absolute -top-8 left-0 flex w-full justify-between text-gray-600">
|
|
53
|
+
<p>{{ selectedFile?.name }}</p>
|
|
54
|
+
<Icon
|
|
55
|
+
name="i-heroicons-x-mark"
|
|
56
|
+
class="size-6 cursor-pointer hover:text-gray-400"
|
|
57
|
+
@click="() => (isPreviewOpen = false)"
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
<img
|
|
61
|
+
:src="upload.data.value[responseKey || 'url']"
|
|
62
|
+
alt="img-preview"
|
|
63
|
+
class="w-full rounded-lg"
|
|
64
|
+
/>
|
|
65
|
+
</Modal>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div :class="[ui.imageItem.onPreview.previewTextWrapper]">
|
|
70
|
+
<p :class="[ui.imageItem.onPreview.previewText]">{{ selectedFile.name }}</p>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<!-- Failed State -->
|
|
75
|
+
<div v-if="selectedFile && upload.status.value.isError" class="w-full">
|
|
76
|
+
<div :class="[ui.imageItem.onFailed.wrapper]">
|
|
77
|
+
<img
|
|
78
|
+
:class="[ui.imageItem.onFailed.failedImgClass]"
|
|
79
|
+
:src="generateURL(selectedFile)"
|
|
80
|
+
alt="img"
|
|
81
|
+
/>
|
|
82
|
+
<div :class="[ui.imageItem.onFailed.failedActionWrapper]">
|
|
83
|
+
<Icon
|
|
84
|
+
title="ลบไฟล์"
|
|
85
|
+
:name="ui.action.deleteIcon"
|
|
86
|
+
:class="[ui.imageItem.onFailed.actionBtnClass]"
|
|
87
|
+
@click="handleDeleteFile"
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</FieldWrapper>
|
|
95
|
+
</template>
|
|
96
|
+
|
|
97
|
+
<script lang="ts" setup>
|
|
98
|
+
import { type IUploadImageAutoProps } from './types'
|
|
99
|
+
import FieldWrapper from '#core/components/Form/FieldWrapper.vue'
|
|
100
|
+
import { useFieldHOC } from '#core/composables/useForm'
|
|
101
|
+
import {
|
|
102
|
+
computed,
|
|
103
|
+
ref,
|
|
104
|
+
toRef,
|
|
105
|
+
useUI,
|
|
106
|
+
useUiConfig,
|
|
107
|
+
useWatchTrue,
|
|
108
|
+
useUploadLoader,
|
|
109
|
+
_get,
|
|
110
|
+
type IUploadRequest,
|
|
111
|
+
} from '#imports'
|
|
112
|
+
import { uploadImage } from '#core/ui.config'
|
|
113
|
+
import {
|
|
114
|
+
checkMaxSize,
|
|
115
|
+
generateURL,
|
|
116
|
+
useFileAllocate,
|
|
117
|
+
useFileProgress,
|
|
118
|
+
} from '#core/helpers/componentHelper'
|
|
119
|
+
import i18next from 'i18next'
|
|
120
|
+
|
|
121
|
+
const config = useUiConfig<typeof uploadImage>(uploadImage, 'uploadImage')
|
|
122
|
+
|
|
123
|
+
const props = withDefaults(defineProps<IUploadImageAutoProps>(), {
|
|
124
|
+
accept: 'image/*',
|
|
125
|
+
bodyKey: 'file',
|
|
126
|
+
responseKey: 'url',
|
|
127
|
+
uploadAddLabel: 'อัพโหลด',
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const emits = defineEmits(['change', 'success', 'delete', 'error'])
|
|
131
|
+
|
|
132
|
+
const request: IUploadRequest = {
|
|
133
|
+
pathURL: props.uploadPathURL,
|
|
134
|
+
requestOptions: props.requestOptions,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const selectedFile = ref<File>()
|
|
138
|
+
const isPreviewOpen = ref<boolean>(false)
|
|
139
|
+
|
|
140
|
+
const { wrapperProps, value, errorMessage } = useFieldHOC<string | undefined>(props)
|
|
141
|
+
|
|
142
|
+
const upload = useUploadLoader(request)
|
|
143
|
+
const { ui } = useUI('uploadImage', toRef(props, 'ui'), config)
|
|
144
|
+
|
|
145
|
+
const fileInputRef = ref<HTMLInputElement | null>()
|
|
146
|
+
|
|
147
|
+
const fileAllocate = useFileAllocate(toRef(selectedFile), props)
|
|
148
|
+
const { onUploadProgress, onDownloadProgress, percent } = useFileProgress()
|
|
149
|
+
const acceptFile = computed(() =>
|
|
150
|
+
typeof props.accept === 'string' ? props.accept : props.accept?.join(',')
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const handleChange = (e: Event) => {
|
|
154
|
+
if (props.isDisabled) return
|
|
155
|
+
|
|
156
|
+
const file = (e.target as HTMLInputElement).files?.[0]
|
|
157
|
+
const result = handleCheckFileCondition(file)
|
|
158
|
+
|
|
159
|
+
if (result && file) {
|
|
160
|
+
selectedFile.value = file
|
|
161
|
+
emits('change', selectedFile.value)
|
|
162
|
+
const formData = new FormData()
|
|
163
|
+
|
|
164
|
+
formData.append(props.bodyKey, file)
|
|
165
|
+
upload.run(formData, { data: { onUploadProgress, onDownloadProgress } })
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const handleCheckFileCondition = (file: File | undefined): boolean => {
|
|
170
|
+
if (!file) return false
|
|
171
|
+
const maxSize = checkMaxSize(file, fileAllocate.acceptFileSizeKb.value)
|
|
172
|
+
|
|
173
|
+
if (!maxSize) {
|
|
174
|
+
if (fileAllocate.isAcceptFileUseMb.value) {
|
|
175
|
+
errorMessage.value = i18next.t('custom:invalid_file_size_mb', {
|
|
176
|
+
size: fileAllocate.acceptFileSizeMb.value,
|
|
177
|
+
})
|
|
178
|
+
} else {
|
|
179
|
+
errorMessage.value = i18next.t('custom:invalid_file_size_kb', {
|
|
180
|
+
size: fileAllocate.acceptFileSizeKb.value,
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return false
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
errorMessage.value = ''
|
|
188
|
+
|
|
189
|
+
return true
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const handleOpenFile = () => {
|
|
193
|
+
fileInputRef.value?.click()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const handleDeleteFile = () => {
|
|
197
|
+
fileInputRef.value!.value = ''
|
|
198
|
+
selectedFile.value = undefined
|
|
199
|
+
value.value = undefined
|
|
200
|
+
emits('change', undefined)
|
|
201
|
+
|
|
202
|
+
emits('delete')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
useWatchTrue(
|
|
206
|
+
() => upload.status.value.isSuccess,
|
|
207
|
+
() => {
|
|
208
|
+
const response = _get(upload.data.value, props.responseKey, '')
|
|
209
|
+
|
|
210
|
+
value.value = response
|
|
211
|
+
|
|
212
|
+
emits('success', response)
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
useWatchTrue(
|
|
217
|
+
() => upload.status.value.isError,
|
|
218
|
+
() => {
|
|
219
|
+
emits('error', upload.status.value.errorData)
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type AxiosRequestConfig } from 'axios';
|
|
2
|
+
import { type IFieldProps, type IFormFieldBase, type INPUT_TYPES } from '../types';
|
|
3
|
+
export interface IUploadImageAutoProps extends IFieldProps {
|
|
4
|
+
requestOptions: Omit<AxiosRequestConfig, 'baseURL'> & {
|
|
5
|
+
baseURL: string;
|
|
6
|
+
};
|
|
7
|
+
uploadPathURL?: string;
|
|
8
|
+
uploadAddLabel?: string;
|
|
9
|
+
accept?: string[] | string;
|
|
10
|
+
bodyKey?: string;
|
|
11
|
+
responseKey?: string;
|
|
12
|
+
maxSize?: number;
|
|
13
|
+
}
|
|
14
|
+
export type IUploadImageAutoField = IFormFieldBase<INPUT_TYPES.UPLOAD_IMAGE_AUTO, IUploadImageAutoProps, {
|
|
15
|
+
change: (value: File | undefined) => void;
|
|
16
|
+
success: (res: any) => void;
|
|
17
|
+
delete: () => void;
|
|
18
|
+
error: (err: any) => void;
|
|
19
|
+
}>;
|
|
File without changes
|
|
@@ -11,12 +11,14 @@ import { type IDateTimeField } from '#core/components/Form/InputDateTime/date_ti
|
|
|
11
11
|
import { type IDateTimeRangeField } from '#core/components/Form/InputDateTimeRange/date_range_time_field.types';
|
|
12
12
|
import { type IUploadFileClassicField } from '#core/components/Form/InputUploadFileClassic/types';
|
|
13
13
|
import { type IUploadFileField } from '#core/components/Form/InputUploadFileClassicAuto/types';
|
|
14
|
+
import { type IUploadImageAutoField } from '#core/components/Form/InputUploadImageAuto/types';
|
|
14
15
|
import { type IUploadDropzoneField } from '#core/components/Form/InputUploadDropzone/types';
|
|
15
16
|
import { type IUploadDropzoneAutoField } from '#core/components/Form/InputUploadDropzoneAuto/types';
|
|
16
17
|
import type { INumberField } from '#core/components/Form/InputNumber/types';
|
|
17
18
|
import type { IUploadDropzoneAutoMultipleField } from '#core/components/Form/InputUploadDropzoneAutoMultiple/types';
|
|
18
19
|
import type { IUploadDropzoneImageAutoMultipleField } from '#core/components/Form/InputUploadDropzoneImageAutoMultiple/types';
|
|
19
20
|
import type { IWYSIWYGField } from '#core/components/Form/InputWYSIWYG/types';
|
|
21
|
+
import type { ITagsField } from '#core/components/Form/InputTags/types';
|
|
20
22
|
export declare const enum INPUT_TYPES {
|
|
21
23
|
TEXT = "TEXT",
|
|
22
24
|
NUMBER = "NUMBER",
|
|
@@ -34,11 +36,13 @@ export declare const enum INPUT_TYPES {
|
|
|
34
36
|
DATE_TIME_RANGE = "DATE_TIME_RANGE",
|
|
35
37
|
UPLOAD_FILE_CLASSIC = "UPLOAD_FILE_CLASSIC",
|
|
36
38
|
UPLOAD_FILE_CLASSIC_AUTO = "UPLOAD_FILE_CLASSIC_AUTO",
|
|
39
|
+
UPLOAD_IMAGE_AUTO = "UPLOAD_IMAGE_AUTO",
|
|
37
40
|
UPLOAD_DROPZONE = "UPLOAD_DROPZONE",
|
|
38
41
|
UPLOAD_DROPZONE_AUTO = "UPLOAD_DROPZONE_AUTO",
|
|
39
42
|
UPLOAD_DROPZONE_AUTO_MULTIPLE = "UPLOAD_DROPZONE_AUTO_MULTIPLE",
|
|
40
43
|
UPLOAD_DROPZONE_IMAGE_AUTO_MULTIPLE = "UPLOAD_DROPZONE_IMAGE_AUTO_MULTIPLE",
|
|
41
44
|
WYSIWYG = "WYSIWYG",
|
|
45
|
+
TAGS = "TAGS",
|
|
42
46
|
COMPONENT = "COMPONENT"
|
|
43
47
|
}
|
|
44
48
|
export interface IFieldProps {
|
|
@@ -68,4 +72,4 @@ export interface IFormFieldBase<I extends INPUT_TYPES, P extends IFieldProps, O>
|
|
|
68
72
|
props: P;
|
|
69
73
|
on?: O;
|
|
70
74
|
}
|
|
71
|
-
export type IFormField = ITextField | INumberField | IStaticField | ICheckboxField | IRadioField | ISelectField | IToggleField | ITextareaField | IDateTimeField | IDateTimeRangeField | IUploadFileClassicField | IUploadFileField | IUploadDropzoneField | IUploadDropzoneAutoField | IUploadDropzoneAutoMultipleField | IUploadDropzoneImageAutoMultipleField | IWYSIWYGField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
|
|
75
|
+
export type IFormField = ITextField | INumberField | IStaticField | ICheckboxField | IRadioField | ISelectField | IToggleField | ITextareaField | IDateTimeField | IDateTimeRangeField | IUploadFileClassicField | IUploadFileField | IUploadImageAutoField | IUploadDropzoneField | IUploadDropzoneAutoField | IUploadDropzoneAutoMultipleField | IUploadDropzoneImageAutoMultipleField | IWYSIWYGField | ITagsField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
|
|
@@ -15,11 +15,13 @@ export var INPUT_TYPES = /* @__PURE__ */ ((INPUT_TYPES2) => {
|
|
|
15
15
|
INPUT_TYPES2["DATE_TIME_RANGE"] = "DATE_TIME_RANGE";
|
|
16
16
|
INPUT_TYPES2["UPLOAD_FILE_CLASSIC"] = "UPLOAD_FILE_CLASSIC";
|
|
17
17
|
INPUT_TYPES2["UPLOAD_FILE_CLASSIC_AUTO"] = "UPLOAD_FILE_CLASSIC_AUTO";
|
|
18
|
+
INPUT_TYPES2["UPLOAD_IMAGE_AUTO"] = "UPLOAD_IMAGE_AUTO";
|
|
18
19
|
INPUT_TYPES2["UPLOAD_DROPZONE"] = "UPLOAD_DROPZONE";
|
|
19
20
|
INPUT_TYPES2["UPLOAD_DROPZONE_AUTO"] = "UPLOAD_DROPZONE_AUTO";
|
|
20
21
|
INPUT_TYPES2["UPLOAD_DROPZONE_AUTO_MULTIPLE"] = "UPLOAD_DROPZONE_AUTO_MULTIPLE";
|
|
21
22
|
INPUT_TYPES2["UPLOAD_DROPZONE_IMAGE_AUTO_MULTIPLE"] = "UPLOAD_DROPZONE_IMAGE_AUTO_MULTIPLE";
|
|
22
23
|
INPUT_TYPES2["WYSIWYG"] = "WYSIWYG";
|
|
24
|
+
INPUT_TYPES2["TAGS"] = "TAGS";
|
|
23
25
|
INPUT_TYPES2["COMPONENT"] = "COMPONENT";
|
|
24
26
|
return INPUT_TYPES2;
|
|
25
27
|
})(INPUT_TYPES || {});
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<QrcodeVue :value="value" :level="level" :render-as="renderAs" class="size-[350px]" />
|
|
3
|
-
</template>
|
|
4
|
-
<script lang="ts" setup>
|
|
5
|
-
import QrcodeVue from 'qrcode.vue'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<QrcodeVue :value="value" :level="level" :render-as="renderAs" class="size-[350px]" />
|
|
3
|
+
</template>
|
|
4
|
+
<script lang="ts" setup>
|
|
5
|
+
import QrcodeVue, { type RenderAs } from 'qrcode.vue'
|
|
6
|
+
import { type PropType } from 'vue'
|
|
7
|
+
|
|
8
|
+
defineProps({
|
|
9
|
+
value: {
|
|
10
|
+
type: String,
|
|
11
|
+
required: true,
|
|
12
|
+
},
|
|
13
|
+
level: {
|
|
14
|
+
type: String,
|
|
15
|
+
default: 'M',
|
|
16
|
+
},
|
|
17
|
+
renderAs: {
|
|
18
|
+
type: String as PropType<RenderAs>,
|
|
19
|
+
default: 'svg',
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
</script>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type UIComponentList = 'modal' | 'slideover' | 'dropdown' | 'icon' | 'button' | 'buttonGroup' | 'tabs' | 'card' | 'breadcrumb' | 'badge' | 'input' | 'pagination' | 'notification' | 'uploadFileInputClassicAuto' | 'uploadFileDropzone' | 'uploadFileDropzoneImage';
|
|
1
|
+
export type UIComponentList = 'modal' | 'slideover' | 'dropdown' | 'icon' | 'button' | 'buttonGroup' | 'tabs' | 'card' | 'breadcrumb' | 'badge' | 'input' | 'pagination' | 'notification' | 'uploadFileInputClassicAuto' | 'uploadFileDropzone' | 'uploadFileDropzoneImage' | 'uploadImage' | 'tags';
|
|
@@ -12,3 +12,5 @@ export { breadcrumb } from './breadcrumb';
|
|
|
12
12
|
export { uploadFileInputClassicAuto } from './uploadFileInputClassicAuto';
|
|
13
13
|
export { uploadFileDropzone } from './uploadFileDropzone';
|
|
14
14
|
export { uploadFileDropzoneImage } from './uploadDropzoneImage';
|
|
15
|
+
export { uploadImage } from './uploadImage';
|
|
16
|
+
export { tags } from './tags';
|
|
@@ -12,3 +12,5 @@ export { breadcrumb } from "./breadcrumb.mjs";
|
|
|
12
12
|
export { uploadFileInputClassicAuto } from "./uploadFileInputClassicAuto.mjs";
|
|
13
13
|
export { uploadFileDropzone } from "./uploadFileDropzone.mjs";
|
|
14
14
|
export { uploadFileDropzoneImage } from "./uploadDropzoneImage.mjs";
|
|
15
|
+
export { uploadImage } from "./uploadImage.mjs";
|
|
16
|
+
export { tags } from "./tags.mjs";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const tags: {
|
|
2
|
+
base: string;
|
|
3
|
+
border: string;
|
|
4
|
+
shadow: string;
|
|
5
|
+
padding: string;
|
|
6
|
+
stages: {
|
|
7
|
+
default: string;
|
|
8
|
+
error: string;
|
|
9
|
+
};
|
|
10
|
+
placeholder: string;
|
|
11
|
+
innerWrapper: string;
|
|
12
|
+
input: string;
|
|
13
|
+
tag: {
|
|
14
|
+
size: string;
|
|
15
|
+
color: string;
|
|
16
|
+
variant: string;
|
|
17
|
+
};
|
|
18
|
+
default: {
|
|
19
|
+
tag: {
|
|
20
|
+
size: string;
|
|
21
|
+
color: string;
|
|
22
|
+
variant: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const tags = {
|
|
2
|
+
base: "relative flex w-full flex-wrap items-center bg-white ring-1 ring-inset",
|
|
3
|
+
border: "rounded-md border-0",
|
|
4
|
+
shadow: "shadow-sm",
|
|
5
|
+
padding: "px-3.5 py-2.5",
|
|
6
|
+
stages: {
|
|
7
|
+
default: "has-[:focus]:ring-primary-500 ring-gray-300 has-[:focus]:ring-2",
|
|
8
|
+
error: "has-[:focus]:ring-danger-500 ring-danger-500 ring-danger-300 has-[:focus]:ring-2"
|
|
9
|
+
},
|
|
10
|
+
placeholder: "absolute left-3.5 top-2.5 text-sm text-gray-400",
|
|
11
|
+
innerWrapper: "mr-2 flex w-full flex-wrap items-center gap-2",
|
|
12
|
+
input: "m-0 grow p-0 text-sm text-gray-900 outline-none",
|
|
13
|
+
tag: {
|
|
14
|
+
size: "",
|
|
15
|
+
color: "",
|
|
16
|
+
variant: ""
|
|
17
|
+
},
|
|
18
|
+
default: {
|
|
19
|
+
tag: {
|
|
20
|
+
size: "sm",
|
|
21
|
+
color: "primary",
|
|
22
|
+
variant: "solid"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
@@ -9,7 +9,7 @@ export const uploadFileDropzoneImage = {
|
|
|
9
9
|
percentClass: "text-primary"
|
|
10
10
|
},
|
|
11
11
|
onPreview: {
|
|
12
|
-
wrapper: "relative size-24 overflow-hidden rounded-lg
|
|
12
|
+
wrapper: "relative size-24 overflow-hidden rounded-lg border-[1px] border-gray-100",
|
|
13
13
|
previewImgClass: "size-full object-cover",
|
|
14
14
|
previewActionWrapper: "absolute inset-0 z-10 flex items-center justify-center space-x-2 opacity-0 transition hover:bg-black/50 hover:opacity-100",
|
|
15
15
|
actionBtnClass: "size-7 cursor-pointer text-white",
|
|
@@ -17,7 +17,7 @@ export const uploadFileDropzoneImage = {
|
|
|
17
17
|
previewText: "truncate text-center text-sm"
|
|
18
18
|
},
|
|
19
19
|
onFailed: {
|
|
20
|
-
wrapper: "
|
|
20
|
+
wrapper: "border-danger border-dashed relative size-24 overflow-hidden rounded-lg border-[1px]",
|
|
21
21
|
failedImgClass: "size-full object-cover",
|
|
22
22
|
failedActionWrapper: "absolute inset-0 z-10 flex items-center justify-center space-x-2 bg-white/50",
|
|
23
23
|
actionBtnClass: "text-danger size-7 cursor-pointer"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const uploadImage: {
|
|
2
|
+
base: string;
|
|
3
|
+
imageItemWrapper: string;
|
|
4
|
+
imageItem: {
|
|
5
|
+
wrapper: string;
|
|
6
|
+
onLoading: {
|
|
7
|
+
wrapper: string;
|
|
8
|
+
percentClass: string;
|
|
9
|
+
};
|
|
10
|
+
onPreview: {
|
|
11
|
+
wrapper: string;
|
|
12
|
+
previewImgClass: string;
|
|
13
|
+
previewActionWrapper: string;
|
|
14
|
+
actionBtnClass: string;
|
|
15
|
+
previewTextWrapper: string;
|
|
16
|
+
previewText: string;
|
|
17
|
+
};
|
|
18
|
+
onFailed: {
|
|
19
|
+
wrapper: string;
|
|
20
|
+
failedImgClass: string;
|
|
21
|
+
failedActionWrapper: string;
|
|
22
|
+
actionBtnClass: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
action: {
|
|
26
|
+
addingWrapper: string;
|
|
27
|
+
deleteIconClass: string;
|
|
28
|
+
addingBtnClass: string;
|
|
29
|
+
addingTextClass: string;
|
|
30
|
+
previewIcon: string;
|
|
31
|
+
deleteIcon: string;
|
|
32
|
+
addingIcon: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const uploadImage = {
|
|
2
|
+
base: "w-full overflow-hidden",
|
|
3
|
+
imageItemWrapper: "flex w-full flex-wrap gap-4",
|
|
4
|
+
imageItem: {
|
|
5
|
+
wrapper: "max-w-[96px]",
|
|
6
|
+
onLoading: {
|
|
7
|
+
wrapper: "flex size-24 flex-col items-center justify-center overflow-hidden rounded-lg border-[1px] border-dashed p-2",
|
|
8
|
+
percentClass: "text-primary"
|
|
9
|
+
},
|
|
10
|
+
onPreview: {
|
|
11
|
+
wrapper: "relative size-24 overflow-hidden rounded-lg border-[1px] border-gray-100",
|
|
12
|
+
previewImgClass: "size-full object-cover",
|
|
13
|
+
previewActionWrapper: "absolute inset-0 z-10 flex items-center justify-center space-x-2 opacity-0 transition hover:bg-black/50 hover:opacity-100",
|
|
14
|
+
actionBtnClass: "size-7 cursor-pointer text-white",
|
|
15
|
+
previewTextWrapper: "mt-2 truncate",
|
|
16
|
+
previewText: "truncate text-center text-sm"
|
|
17
|
+
},
|
|
18
|
+
onFailed: {
|
|
19
|
+
wrapper: "relative size-24 overflow-hidden rounded-lg border-[1px] border-dashed border-danger",
|
|
20
|
+
failedImgClass: "size-full object-cover",
|
|
21
|
+
failedActionWrapper: "absolute inset-0 z-10 flex items-center justify-center space-x-2 bg-white/50",
|
|
22
|
+
actionBtnClass: "text-danger size-7 cursor-pointer"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
action: {
|
|
26
|
+
// wrapper: 'flex items-center space-x-4',
|
|
27
|
+
addingWrapper: "flex size-24 flex-col items-center justify-center overflow-hidden rounded-lg border-[1px] border-dashed p-2 cursor-pointer transition hover:bg-gray-100",
|
|
28
|
+
// iconClass: 'size-6 text-gray-400 cursor-pointer',
|
|
29
|
+
deleteIconClass: "size-6 text-danger cursor-pointer",
|
|
30
|
+
addingBtnClass: "size-7 text-gray-500",
|
|
31
|
+
addingTextClass: "text-center text-sm text-gray-500",
|
|
32
|
+
previewIcon: "i-ic:outline-remove-red-eye",
|
|
33
|
+
deleteIcon: "ph:trash",
|
|
34
|
+
addingIcon: "i-material-symbols:add"
|
|
35
|
+
}
|
|
36
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finema/core",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.108",
|
|
4
4
|
"repository": "https://gitlab.finema.co/finema/ui-kit",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Finema Dev Core Team",
|
|
@@ -23,8 +23,10 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"prepack": "nuxt-module-build build",
|
|
25
25
|
"dev": "nuxi dev playground",
|
|
26
|
+
"docs": "nuxi dev docs",
|
|
26
27
|
"dev:build": "nuxi build playground",
|
|
27
|
-
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
28
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground && nuxi prepare docs",
|
|
29
|
+
"docs:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare docs",
|
|
28
30
|
"lint": "eslint . --cache",
|
|
29
31
|
"lint:fix": "eslint . --fix --cache",
|
|
30
32
|
"test": "vitest run",
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"@nuxt/kit": "^3.11.1",
|
|
37
|
-
"@nuxt/ui": "^2.15.
|
|
39
|
+
"@nuxt/ui": "^2.15.1",
|
|
38
40
|
"@pinia/nuxt": "^0.5.1",
|
|
39
41
|
"@vee-validate/nuxt": "^4.12.6",
|
|
40
42
|
"@vee-validate/zod": "^4.12.6",
|