@bagelink/vue 0.0.1117 → 0.0.1119
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/components/ModalForm.vue.d.ts +0 -125
- package/dist/components/ModalForm.vue.d.ts.map +1 -1
- package/dist/components/form/BagelForm.vue.d.ts +44 -0
- package/dist/components/form/BagelForm.vue.d.ts.map +1 -0
- package/dist/components/form/index.d.ts +1 -1
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/inputs/NumberInput.vue.d.ts +1 -1
- package/dist/components/form/inputs/NumberInput.vue.d.ts.map +1 -1
- package/dist/index.cjs +171 -160
- package/dist/index.mjs +171 -160
- package/dist/style.css +8 -8
- package/package.json +1 -1
- package/src/components/ModalForm.vue +6 -11
- package/src/components/form/BagelForm.vue +150 -0
- package/src/components/form/index.ts +1 -1
- package/src/components/form/inputs/NumberInput.vue +3 -3
package/package.json
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
type BglFormSchemaFnT,
|
|
5
|
-
Btn,
|
|
6
|
-
type BtnOptions,
|
|
7
|
-
Modal,
|
|
8
|
-
useBagel,
|
|
9
|
-
} from '@bagelink/vue'
|
|
2
|
+
import type { BglFormSchemaFnT, BtnOptions, BagelForm } from '@bagelink/vue'
|
|
3
|
+
import { Btn, Modal, useBagel, BagelForm2 } from '@bagelink/vue'
|
|
10
4
|
|
|
11
5
|
const props = defineProps<{
|
|
12
6
|
side?: boolean
|
|
@@ -80,15 +74,16 @@ defineExpose({ setFormValues })
|
|
|
80
74
|
:visible="visible"
|
|
81
75
|
:dismissable
|
|
82
76
|
:title
|
|
83
|
-
@update:visible="($event) => emit('update:visible', $event)"
|
|
77
|
+
@update:visible="($event: boolean) => emit('update:visible', $event)"
|
|
84
78
|
>
|
|
85
|
-
<
|
|
79
|
+
<BagelForm2 v-model="formData" :schema="computedFormSchema" @submit="runSubmit" />
|
|
80
|
+
<!-- <BagelForm
|
|
86
81
|
v-if="visible"
|
|
87
82
|
ref="form"
|
|
88
83
|
v-model="formData"
|
|
89
84
|
:schema="computedFormSchema"
|
|
90
85
|
@submit="runSubmit"
|
|
91
|
-
/>
|
|
86
|
+
/> -->
|
|
92
87
|
<template v-if="onDelete || onSubmit" #footer>
|
|
93
88
|
<div>
|
|
94
89
|
<Btn thin flat value="Cancel" @click="closeModal" />
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BglFormSchemaT, BglFormSchemaFnT, Field } from '@bagelink/vue'
|
|
3
|
+
import type { VNode } from 'vue'
|
|
4
|
+
import { BglForm, CheckInput, DateInput, FieldArray, FileUpload, NumberInput, RichText, SelectInput, TabsNav, TextInput, ToggleInput, UploadInput } from '@bagelink/vue'
|
|
5
|
+
import { h, watch } from 'vue'
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
modelValue: Record<string, any>
|
|
9
|
+
schema?: BglFormSchemaFnT
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
13
|
+
modelValue: () => ({}),
|
|
14
|
+
schema: undefined
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const emit = defineEmits<{
|
|
18
|
+
(e: 'update:modelValue', value: Record<string, any>): void
|
|
19
|
+
(e: 'submit', value: Record<string, any>): void
|
|
20
|
+
}>()
|
|
21
|
+
|
|
22
|
+
const form = $ref<HTMLFormElement>()
|
|
23
|
+
let formData = $ref({ ...props.modelValue })
|
|
24
|
+
let initialFormData = $ref({ ...props.modelValue })
|
|
25
|
+
|
|
26
|
+
// Keep formData in sync with modelValue prop
|
|
27
|
+
watch(() => props.modelValue, (newValue) => {
|
|
28
|
+
formData = { ...newValue }
|
|
29
|
+
}, { immediate: true, deep: true })
|
|
30
|
+
|
|
31
|
+
const resolvedSchema = $computed<BglFormSchemaT | undefined>(() => {
|
|
32
|
+
if (!props.schema) return undefined
|
|
33
|
+
return typeof props.schema === 'function' ? props.schema() : props.schema
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const isDirty = $computed(() => {
|
|
37
|
+
const current = JSON.stringify(formData)
|
|
38
|
+
const initial = JSON.stringify(initialFormData)
|
|
39
|
+
return current !== initial
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
function getComponent(field: Field) {
|
|
43
|
+
const componentMap = {
|
|
44
|
+
text: TextInput,
|
|
45
|
+
textarea: TextInput,
|
|
46
|
+
number: NumberInput,
|
|
47
|
+
array: FieldArray,
|
|
48
|
+
select: SelectInput,
|
|
49
|
+
toggle: ToggleInput,
|
|
50
|
+
check: CheckInput,
|
|
51
|
+
richtext: RichText,
|
|
52
|
+
upload: UploadInput,
|
|
53
|
+
file: FileUpload,
|
|
54
|
+
date: DateInput,
|
|
55
|
+
tabs: TabsNav,
|
|
56
|
+
bglform: BglForm
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (field.$el === 'textarea' && !field.attrs?.multiline) {
|
|
60
|
+
field.attrs = { ...field.attrs, multiline: true }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return componentMap[field.$el as keyof typeof componentMap] ?? field.$el ?? 'div'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function processFieldValue(fieldType: any, value: any): any {
|
|
67
|
+
if (value == null) return value
|
|
68
|
+
if (fieldType === 'select' && typeof value === 'object') return value.value
|
|
69
|
+
if (typeof value === 'object' && 'value' in value) return value.value
|
|
70
|
+
return value
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function updateFormData(fieldId: string, value: any, fieldType?: any) {
|
|
74
|
+
formData = {
|
|
75
|
+
...formData,
|
|
76
|
+
[fieldId]: processFieldValue(fieldType, value)
|
|
77
|
+
}
|
|
78
|
+
emit('update:modelValue', formData)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function handleSubmit() {
|
|
82
|
+
emit('submit', formData)
|
|
83
|
+
initialFormData = { ...formData }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function renderSchemaField(field: Field): VNode | null {
|
|
87
|
+
const Component = getComponent(field)
|
|
88
|
+
if (!Component) return null
|
|
89
|
+
|
|
90
|
+
const { $el, vIf, 'v-if': vIf2, children, ...fieldProps } = field
|
|
91
|
+
const currentValue = field.id ? formData[field.id] : undefined
|
|
92
|
+
|
|
93
|
+
const props: Record<string, any> = {
|
|
94
|
+
...fieldProps,
|
|
95
|
+
'modelValue': processFieldValue(field.$el, currentValue),
|
|
96
|
+
'onUpdate:modelValue': (value: any) => {
|
|
97
|
+
if (!field.id) return
|
|
98
|
+
updateFormData(field.id, value, field.$el)
|
|
99
|
+
field.onUpdate?.(value, formData)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Handle dynamic props
|
|
104
|
+
if (field.attrs) {
|
|
105
|
+
Object.entries(field.attrs).forEach(([key, value]) => {
|
|
106
|
+
props[key] = typeof value === 'function' ? value(field, formData) : value
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (field.class) {
|
|
111
|
+
props.class = typeof field.class === 'function'
|
|
112
|
+
? field.class(field, formData)
|
|
113
|
+
: field.class
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const slots = field.children?.length
|
|
117
|
+
? {
|
|
118
|
+
default: () => field.children!.map(child => typeof child === 'string' ? child : renderSchemaField(child)
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
: undefined
|
|
122
|
+
|
|
123
|
+
return h(Component as any, props, slots)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function shouldRenderField(field: Field): boolean {
|
|
127
|
+
const condition = field.vIf ?? field['v-if']
|
|
128
|
+
if (condition === undefined) return true
|
|
129
|
+
return typeof condition === 'function'
|
|
130
|
+
? condition(formData[field.id as string], formData)
|
|
131
|
+
: !!condition
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
defineExpose({ form, isDirty })
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<template>
|
|
138
|
+
<form ref="form" @submit.prevent="handleSubmit">
|
|
139
|
+
<template v-if="resolvedSchema">
|
|
140
|
+
<template v-for="(field, index) in resolvedSchema" :key="field.id || index">
|
|
141
|
+
<component
|
|
142
|
+
:is="renderSchemaField(field)"
|
|
143
|
+
v-if="shouldRenderField(field)"
|
|
144
|
+
/>
|
|
145
|
+
</template>
|
|
146
|
+
</template>
|
|
147
|
+
<slot v-else />
|
|
148
|
+
<slot name="submit" :submit="handleSubmit" :isDirty="isDirty" />
|
|
149
|
+
</form>
|
|
150
|
+
</template>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
export { default as BagelForm2 } from './BagelForm.vue'
|
|
1
2
|
export { default as BglField } from './BglField.vue'
|
|
2
3
|
export { default as BglForm } from './BglForm.vue'
|
|
3
4
|
export { default as BagelForm } from './BglForm.vue'
|
|
4
|
-
export { default as BglMultiStepForm } from './BglMultiStepForm.vue'
|
|
5
5
|
export { default as FieldArray } from './FieldArray.vue'
|
|
6
6
|
export * from './inputs'
|
|
@@ -5,7 +5,7 @@ import { watch } from 'vue'
|
|
|
5
5
|
type NumberLayout = 'default' | 'vertical' | 'horizontal'
|
|
6
6
|
|
|
7
7
|
interface NumberInputProps {
|
|
8
|
-
modelValue?: number
|
|
8
|
+
modelValue?: number | string
|
|
9
9
|
min?: number
|
|
10
10
|
max?: number
|
|
11
11
|
step?: number
|
|
@@ -43,7 +43,7 @@ const {
|
|
|
43
43
|
|
|
44
44
|
const emit = defineEmits(['update:modelValue'])
|
|
45
45
|
|
|
46
|
-
let numberValue = $ref(modelValue || 0)
|
|
46
|
+
let numberValue = $ref(Number.parseFloat(`${modelValue}`) || 0)
|
|
47
47
|
|
|
48
48
|
const btnLayouts: NumberLayout[] = ['horizontal', 'vertical']
|
|
49
49
|
|
|
@@ -88,7 +88,7 @@ watch(() => numberValue, () => {
|
|
|
88
88
|
|
|
89
89
|
watch(() => modelValue, (newVal) => {
|
|
90
90
|
if (newVal !== numberValue) {
|
|
91
|
-
numberValue = newVal || 0
|
|
91
|
+
numberValue = Number.parseFloat(`${newVal}`) || 0
|
|
92
92
|
}
|
|
93
93
|
}, { immediate: true })
|
|
94
94
|
</script>
|