@datametria/vue-components 2.2.0 → 2.3.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/README.md +25 -7
- package/dist/index.es.js +3378 -2148
- package/dist/index.umd.js +9 -9
- package/dist/src/components/DatametriaAutocomplete.vue.d.ts +14 -17
- package/dist/src/components/DatametriaBreadcrumb.vue.d.ts +39 -7
- package/dist/src/components/DatametriaCheckbox.vue.d.ts +35 -6
- package/dist/src/components/DatametriaCheckboxGroup.vue.d.ts +30 -0
- package/dist/src/components/DatametriaDataTable.vue.d.ts +64 -0
- package/dist/src/components/DatametriaDatePicker.vue.d.ts +15 -37
- package/dist/src/components/DatametriaDialog.vue.d.ts +71 -0
- package/dist/src/components/DatametriaEmpty.vue.d.ts +30 -0
- package/dist/src/components/DatametriaFloatingBar.vue.d.ts +2 -2
- package/dist/src/components/DatametriaForm.vue.d.ts +40 -0
- package/dist/src/components/DatametriaFormItem.vue.d.ts +28 -0
- package/dist/src/components/DatametriaGrid.vue.d.ts +1 -1
- package/dist/src/components/DatametriaInput.vue.d.ts +69 -10
- package/dist/src/components/DatametriaMenu.vue.d.ts +3 -3
- package/dist/src/components/DatametriaNavbar.vue.d.ts +2 -2
- package/dist/src/components/DatametriaPagination.vue.d.ts +29 -0
- package/dist/src/components/DatametriaPopconfirm.vue.d.ts +43 -0
- package/dist/src/components/DatametriaProgress.vue.d.ts +33 -8
- package/dist/src/components/DatametriaRadio.vue.d.ts +25 -6
- package/dist/src/components/DatametriaRadioGroup.vue.d.ts +29 -0
- package/dist/src/components/DatametriaResult.vue.d.ts +30 -0
- package/dist/src/components/DatametriaSelect.vue.d.ts +16 -11
- package/dist/src/components/DatametriaSidebar.vue.d.ts +3 -3
- package/dist/src/components/DatametriaSlider.vue.d.ts +3 -3
- package/dist/src/components/DatametriaSortableTable.vue.d.ts +1 -1
- package/dist/src/components/DatametriaSteps.vue.d.ts +45 -0
- package/dist/src/components/DatametriaSwitch.vue.d.ts +9 -4
- package/dist/src/components/DatametriaTabPane.vue.d.ts +28 -0
- package/dist/src/components/DatametriaTextarea.vue.d.ts +27 -8
- package/dist/src/components/DatametriaTimePicker.vue.d.ts +17 -25
- package/dist/src/components/DatametriaToast.vue.d.ts +1 -1
- package/dist/src/components/DatametriaTooltip.vue.d.ts +1 -1
- package/dist/src/components/DatametriaTree.vue.d.ts +31 -0
- package/dist/src/components/DatametriaTreeNode.vue.d.ts +17 -0
- package/dist/src/components/DatametriaUpload.vue.d.ts +64 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/vue-components.css +1 -1
- package/package.json +4 -3
- package/src/components/DatametriaAutocomplete.vue +155 -260
- package/src/components/DatametriaBreadcrumb.vue +66 -80
- package/src/components/DatametriaCheckbox.vue +150 -37
- package/src/components/DatametriaCheckboxGroup.vue +43 -0
- package/src/components/DatametriaDataTable.vue +304 -0
- package/src/components/DatametriaDatePicker.vue +238 -614
- package/src/components/DatametriaDialog.vue +295 -0
- package/src/components/DatametriaDropdown.vue +352 -0
- package/src/components/DatametriaEmpty.vue +153 -0
- package/src/components/DatametriaForm.vue +160 -0
- package/src/components/DatametriaFormItem.vue +181 -0
- package/src/components/DatametriaInput.vue +226 -63
- package/src/components/DatametriaPagination.vue +373 -0
- package/src/components/DatametriaPopconfirm.vue +236 -0
- package/src/components/DatametriaProgress.vue +176 -63
- package/src/components/DatametriaRadio.vue +83 -72
- package/src/components/DatametriaRadioGroup.vue +42 -0
- package/src/components/DatametriaResult.vue +133 -0
- package/src/components/DatametriaSelect.vue +172 -67
- package/src/components/DatametriaSortableTable.vue +35 -4
- package/src/components/DatametriaSteps.vue +314 -0
- package/src/components/DatametriaSwitch.vue +86 -80
- package/src/components/DatametriaTabPane.vue +82 -0
- package/src/components/DatametriaTextarea.vue +140 -100
- package/src/components/DatametriaTimePicker.vue +231 -214
- package/src/components/DatametriaTree.vue +124 -0
- package/src/components/DatametriaTreeNode.vue +174 -0
- package/src/components/DatametriaUpload.vue +365 -0
- package/src/index.ts +25 -11
- package/src/components/__tests__/DatametriaAutocomplete.test.ts +0 -180
- package/src/components/__tests__/DatametriaBreadcrumb.test.ts +0 -75
- package/src/components/__tests__/DatametriaCheckbox.test.ts +0 -47
- package/src/components/__tests__/DatametriaDatePicker.test.ts +0 -234
- package/src/components/__tests__/DatametriaProgress.test.ts +0 -90
- package/src/components/__tests__/DatametriaRadio.test.ts +0 -77
- package/src/components/__tests__/DatametriaSwitch.test.ts +0 -64
- package/src/components/__tests__/DatametriaTextarea.test.ts +0 -66
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="datametria-empty" role="status" aria-live="polite">
|
|
3
|
+
<div class="datametria-empty__image">
|
|
4
|
+
<slot name="image">
|
|
5
|
+
<svg
|
|
6
|
+
v-if="imageType === 'no-data'"
|
|
7
|
+
class="datametria-empty__svg"
|
|
8
|
+
viewBox="0 0 200 200"
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
+
>
|
|
11
|
+
<circle cx="100" cy="100" r="80" fill="#f0f0f0" />
|
|
12
|
+
<path d="M70 90 Q100 70 130 90" stroke="#999" stroke-width="3" fill="none" />
|
|
13
|
+
<circle cx="80" cy="85" r="8" fill="#999" />
|
|
14
|
+
<circle cx="120" cy="85" r="8" fill="#999" />
|
|
15
|
+
<path d="M70 130 Q100 150 130 130" stroke="#999" stroke-width="3" fill="none" />
|
|
16
|
+
</svg>
|
|
17
|
+
<svg
|
|
18
|
+
v-else-if="imageType === 'no-results'"
|
|
19
|
+
class="datametria-empty__svg"
|
|
20
|
+
viewBox="0 0 200 200"
|
|
21
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
+
>
|
|
23
|
+
<circle cx="80" cy="80" r="50" fill="none" stroke="#999" stroke-width="4" />
|
|
24
|
+
<line x1="120" y1="120" x2="160" y2="160" stroke="#999" stroke-width="4" stroke-linecap="round" />
|
|
25
|
+
<line x1="60" y1="60" x2="100" y2="100" stroke="#e74c3c" stroke-width="3" />
|
|
26
|
+
<line x1="100" y1="60" x2="60" y2="100" stroke="#e74c3c" stroke-width="3" />
|
|
27
|
+
</svg>
|
|
28
|
+
<svg
|
|
29
|
+
v-else-if="imageType === 'error'"
|
|
30
|
+
class="datametria-empty__svg"
|
|
31
|
+
viewBox="0 0 200 200"
|
|
32
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
33
|
+
>
|
|
34
|
+
<circle cx="100" cy="100" r="80" fill="#fee" stroke="#e74c3c" stroke-width="3" />
|
|
35
|
+
<line x1="70" y1="70" x2="130" y2="130" stroke="#e74c3c" stroke-width="4" stroke-linecap="round" />
|
|
36
|
+
<line x1="130" y1="70" x2="70" y2="130" stroke="#e74c3c" stroke-width="4" stroke-linecap="round" />
|
|
37
|
+
</svg>
|
|
38
|
+
<img
|
|
39
|
+
v-else-if="image"
|
|
40
|
+
:src="image"
|
|
41
|
+
:alt="imageAlt"
|
|
42
|
+
class="datametria-empty__custom-image"
|
|
43
|
+
/>
|
|
44
|
+
</slot>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="datametria-empty__description">
|
|
48
|
+
<slot name="description">
|
|
49
|
+
<p v-if="description" class="datametria-empty__text">{{ description }}</p>
|
|
50
|
+
</slot>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div v-if="$slots.default" class="datametria-empty__actions">
|
|
54
|
+
<slot></slot>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<script setup lang="ts">
|
|
60
|
+
import { computed } from 'vue'
|
|
61
|
+
|
|
62
|
+
interface Props {
|
|
63
|
+
description?: string
|
|
64
|
+
image?: string
|
|
65
|
+
imageAlt?: string
|
|
66
|
+
imageType?: 'no-data' | 'no-results' | 'error'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
70
|
+
description: '',
|
|
71
|
+
image: '',
|
|
72
|
+
imageAlt: 'Empty state',
|
|
73
|
+
imageType: 'no-data'
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const imageType = computed(() => {
|
|
77
|
+
if (props.image) return null
|
|
78
|
+
return props.imageType
|
|
79
|
+
})
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<style scoped>
|
|
83
|
+
.datametria-empty {
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
padding: var(--dm-spacing-xl, 48px) var(--dm-spacing-lg, 24px);
|
|
89
|
+
text-align: center;
|
|
90
|
+
min-height: 300px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.datametria-empty__image {
|
|
94
|
+
margin-bottom: var(--dm-spacing-lg, 24px);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.datametria-empty__svg {
|
|
98
|
+
width: 200px;
|
|
99
|
+
height: 200px;
|
|
100
|
+
opacity: 0.8;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.datametria-empty__custom-image {
|
|
104
|
+
max-width: 200px;
|
|
105
|
+
max-height: 200px;
|
|
106
|
+
object-fit: contain;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.datametria-empty__description {
|
|
110
|
+
margin-bottom: var(--dm-spacing-md, 16px);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.datametria-empty__text {
|
|
114
|
+
color: var(--dm-color-text-secondary, #666);
|
|
115
|
+
font-size: var(--dm-font-size-base, 14px);
|
|
116
|
+
line-height: 1.6;
|
|
117
|
+
margin: 0;
|
|
118
|
+
max-width: 400px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.datametria-empty__actions {
|
|
122
|
+
margin-top: var(--dm-spacing-md, 16px);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@media (prefers-color-scheme: dark) {
|
|
126
|
+
.datametria-empty__text {
|
|
127
|
+
color: var(--dm-color-text-secondary-dark, #999);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.datametria-empty__svg circle[fill="#f0f0f0"] {
|
|
131
|
+
fill: #2a2a2a;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.datametria-empty__svg circle[fill="#fee"] {
|
|
135
|
+
fill: #3a2020;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@media (max-width: 768px) {
|
|
140
|
+
.datametria-empty {
|
|
141
|
+
padding: var(--dm-spacing-lg, 24px) var(--dm-spacing-md, 16px);
|
|
142
|
+
min-height: 250px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.datametria-empty__svg,
|
|
146
|
+
.datametria-empty__custom-image {
|
|
147
|
+
width: 150px;
|
|
148
|
+
height: 150px;
|
|
149
|
+
max-width: 150px;
|
|
150
|
+
max-height: 150px;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
</style>
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<form
|
|
3
|
+
class="datametria-form"
|
|
4
|
+
:class="{
|
|
5
|
+
[`datametria-form--label-${labelPosition}`]: labelPosition,
|
|
6
|
+
'datametria-form--inline': inline
|
|
7
|
+
}"
|
|
8
|
+
@submit.prevent="handleSubmit"
|
|
9
|
+
>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</form>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { provide, reactive, ref } from 'vue'
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
model?: Record<string, any>
|
|
19
|
+
rules?: Record<string, any>
|
|
20
|
+
labelWidth?: string
|
|
21
|
+
labelPosition?: 'left' | 'right' | 'top'
|
|
22
|
+
inline?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
+
model: () => ({}),
|
|
27
|
+
rules: () => ({}),
|
|
28
|
+
labelPosition: 'right',
|
|
29
|
+
inline: false
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits<{
|
|
33
|
+
validate: [valid: boolean, errors: Record<string, string[]>]
|
|
34
|
+
submit: [model: Record<string, any>]
|
|
35
|
+
}>()
|
|
36
|
+
|
|
37
|
+
const fields = reactive<Map<string, any>>(new Map())
|
|
38
|
+
const errors = ref<Record<string, string[]>>({})
|
|
39
|
+
|
|
40
|
+
const registerField = (field: any) => {
|
|
41
|
+
fields.set(field.prop, field)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const unregisterField = (prop: string) => {
|
|
45
|
+
fields.delete(prop)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const validate = async (): Promise<boolean> => {
|
|
49
|
+
const validationPromises: Promise<boolean>[] = []
|
|
50
|
+
const newErrors: Record<string, string[]> = {}
|
|
51
|
+
|
|
52
|
+
fields.forEach((field) => {
|
|
53
|
+
validationPromises.push(
|
|
54
|
+
field.validate().then((valid: boolean) => {
|
|
55
|
+
if (!valid && field.errorMessage) {
|
|
56
|
+
newErrors[field.prop] = [field.errorMessage]
|
|
57
|
+
}
|
|
58
|
+
return valid
|
|
59
|
+
})
|
|
60
|
+
)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const results = await Promise.all(validationPromises)
|
|
64
|
+
const isValid = results.every((result) => result)
|
|
65
|
+
|
|
66
|
+
errors.value = newErrors
|
|
67
|
+
emit('validate', isValid, newErrors)
|
|
68
|
+
|
|
69
|
+
return isValid
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const validateField = async (prop: string): Promise<boolean> => {
|
|
73
|
+
const field = fields.get(prop)
|
|
74
|
+
if (!field) return true
|
|
75
|
+
|
|
76
|
+
const valid = await field.validate()
|
|
77
|
+
if (!valid && field.errorMessage) {
|
|
78
|
+
errors.value[prop] = [field.errorMessage]
|
|
79
|
+
} else {
|
|
80
|
+
delete errors.value[prop]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return valid
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const resetFields = () => {
|
|
87
|
+
fields.forEach((field) => {
|
|
88
|
+
field.reset()
|
|
89
|
+
})
|
|
90
|
+
errors.value = {}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const clearValidate = (props?: string | string[]) => {
|
|
94
|
+
if (!props) {
|
|
95
|
+
errors.value = {}
|
|
96
|
+
fields.forEach((field) => field.clearValidate())
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const propsArray = Array.isArray(props) ? props : [props]
|
|
101
|
+
propsArray.forEach((prop) => {
|
|
102
|
+
delete errors.value[prop]
|
|
103
|
+
const field = fields.get(prop)
|
|
104
|
+
if (field) field.clearValidate()
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const handleSubmit = async () => {
|
|
109
|
+
const valid = await validate()
|
|
110
|
+
if (valid) {
|
|
111
|
+
emit('submit', props.model)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
provide('datametriaForm', {
|
|
116
|
+
model: props.model,
|
|
117
|
+
rules: props.rules,
|
|
118
|
+
labelWidth: props.labelWidth,
|
|
119
|
+
labelPosition: props.labelPosition,
|
|
120
|
+
registerField,
|
|
121
|
+
unregisterField,
|
|
122
|
+
validateField
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
defineExpose({
|
|
126
|
+
validate,
|
|
127
|
+
validateField,
|
|
128
|
+
resetFields,
|
|
129
|
+
clearValidate
|
|
130
|
+
})
|
|
131
|
+
</script>
|
|
132
|
+
|
|
133
|
+
<style scoped>
|
|
134
|
+
.datametria-form {
|
|
135
|
+
font-size: var(--dm-font-size-base, 14px);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.datametria-form--inline {
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-wrap: wrap;
|
|
141
|
+
gap: 16px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.datametria-form--label-left :deep(.datametria-form-item__label) {
|
|
145
|
+
text-align: left;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.datametria-form--label-right :deep(.datametria-form-item__label) {
|
|
149
|
+
text-align: right;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.datametria-form--label-top :deep(.datametria-form-item) {
|
|
153
|
+
flex-direction: column;
|
|
154
|
+
align-items: flex-start;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.datametria-form--label-top :deep(.datametria-form-item__label) {
|
|
158
|
+
margin-bottom: 8px;
|
|
159
|
+
}
|
|
160
|
+
</style>
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="datametria-form-item"
|
|
4
|
+
:class="{
|
|
5
|
+
'is-error': errorMessage,
|
|
6
|
+
'is-required': isRequired
|
|
7
|
+
}"
|
|
8
|
+
>
|
|
9
|
+
<label
|
|
10
|
+
v-if="label"
|
|
11
|
+
class="datametria-form-item__label"
|
|
12
|
+
:style="labelStyle"
|
|
13
|
+
>
|
|
14
|
+
{{ label }}
|
|
15
|
+
</label>
|
|
16
|
+
<div class="datametria-form-item__content">
|
|
17
|
+
<slot></slot>
|
|
18
|
+
<transition name="fade">
|
|
19
|
+
<div v-if="errorMessage" class="datametria-form-item__error">
|
|
20
|
+
{{ errorMessage }}
|
|
21
|
+
</div>
|
|
22
|
+
</transition>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import { ref, computed, inject, onMounted, onBeforeUnmount, watch } from 'vue'
|
|
29
|
+
import { useValidation } from '../composables/useValidation'
|
|
30
|
+
|
|
31
|
+
interface Props {
|
|
32
|
+
prop?: string
|
|
33
|
+
label?: string
|
|
34
|
+
rules?: any[]
|
|
35
|
+
required?: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const props = defineProps<Props>()
|
|
39
|
+
|
|
40
|
+
const form = inject<any>('datametriaForm', null)
|
|
41
|
+
const errorMessage = ref('')
|
|
42
|
+
|
|
43
|
+
const isRequired = computed(() => {
|
|
44
|
+
if (props.required) return true
|
|
45
|
+
if (!props.rules) return false
|
|
46
|
+
return props.rules.some((rule: any) => rule.required)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const labelStyle = computed(() => {
|
|
50
|
+
if (!form?.labelWidth) return {}
|
|
51
|
+
return { width: form.labelWidth }
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const modelValue = computed(() => {
|
|
55
|
+
if (!form?.model || !props.prop) return undefined
|
|
56
|
+
return form.model[props.prop]
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const validate = async (): Promise<boolean> => {
|
|
60
|
+
if (!props.prop || !props.rules) return true
|
|
61
|
+
|
|
62
|
+
const validation = useValidation()
|
|
63
|
+
const errors: string[] = []
|
|
64
|
+
|
|
65
|
+
for (const rule of props.rules) {
|
|
66
|
+
if (rule.required && !validation.required(modelValue.value)) {
|
|
67
|
+
errors.push(rule.message || 'Campo obrigatório')
|
|
68
|
+
break
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (errors.length > 0) {
|
|
73
|
+
errorMessage.value = errors[0]
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
errorMessage.value = ''
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const reset = () => {
|
|
82
|
+
errorMessage.value = ''
|
|
83
|
+
if (form?.model && props.prop) {
|
|
84
|
+
form.model[props.prop] = undefined
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const clearValidate = () => {
|
|
89
|
+
errorMessage.value = ''
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
watch(modelValue, () => {
|
|
93
|
+
if (errorMessage.value) {
|
|
94
|
+
validate()
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
onMounted(() => {
|
|
99
|
+
if (form && props.prop) {
|
|
100
|
+
form.registerField({
|
|
101
|
+
prop: props.prop,
|
|
102
|
+
validate,
|
|
103
|
+
reset,
|
|
104
|
+
clearValidate,
|
|
105
|
+
get errorMessage() {
|
|
106
|
+
return errorMessage.value
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
onBeforeUnmount(() => {
|
|
113
|
+
if (form && props.prop) {
|
|
114
|
+
form.unregisterField(props.prop)
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
defineExpose({
|
|
119
|
+
validate,
|
|
120
|
+
reset,
|
|
121
|
+
clearValidate,
|
|
122
|
+
errorMessage
|
|
123
|
+
})
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<style scoped>
|
|
127
|
+
.datametria-form-item {
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: flex-start;
|
|
130
|
+
margin-bottom: 18px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.datametria-form-item__label {
|
|
134
|
+
flex-shrink: 0;
|
|
135
|
+
padding-right: 12px;
|
|
136
|
+
line-height: 32px;
|
|
137
|
+
color: var(--dm-text-primary, #333);
|
|
138
|
+
font-size: var(--dm-font-size-base, 14px);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.datametria-form-item.is-required .datametria-form-item__label::before {
|
|
142
|
+
content: '*';
|
|
143
|
+
color: var(--dm-color-danger, #f56c6c);
|
|
144
|
+
margin-right: 4px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.datametria-form-item__content {
|
|
148
|
+
flex: 1;
|
|
149
|
+
position: relative;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.datametria-form-item__error {
|
|
153
|
+
color: var(--dm-color-danger, #f56c6c);
|
|
154
|
+
font-size: 12px;
|
|
155
|
+
line-height: 1;
|
|
156
|
+
padding-top: 4px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.datametria-form-item.is-error :deep(input),
|
|
160
|
+
.datametria-form-item.is-error :deep(textarea),
|
|
161
|
+
.datametria-form-item.is-error :deep(select) {
|
|
162
|
+
border-color: var(--dm-color-danger, #f56c6c);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.fade-enter-active,
|
|
166
|
+
.fade-leave-active {
|
|
167
|
+
transition: opacity 0.2s;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.fade-enter-from,
|
|
171
|
+
.fade-leave-to {
|
|
172
|
+
opacity: 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Dark mode */
|
|
176
|
+
@media (prefers-color-scheme: dark) {
|
|
177
|
+
.datametria-form-item__label {
|
|
178
|
+
color: var(--dm-text-primary-dark, #e0e0e0);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
</style>
|