@bagelink/vue 1.2.79 → 1.2.83
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/bin/experimentalGenTypedRoutes.ts +13 -2
- package/dist/components/Btn.vue.d.ts +1 -1
- package/dist/components/Btn.vue.d.ts.map +1 -1
- package/dist/components/DataPreview.vue.d.ts +16 -5
- package/dist/components/DataPreview.vue.d.ts.map +1 -1
- package/dist/components/Icon/Icon.vue.d.ts +4 -1
- package/dist/components/Icon/Icon.vue.d.ts.map +1 -1
- package/dist/components/ModalForm.vue.d.ts +2 -1
- package/dist/components/ModalForm.vue.d.ts.map +1 -1
- package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
- package/dist/components/dataTable/useSorting.d.ts +1 -1
- package/dist/components/dataTable/useSorting.d.ts.map +1 -1
- package/dist/components/dataTable/useTableData.d.ts +7 -6
- package/dist/components/dataTable/useTableData.d.ts.map +1 -1
- package/dist/components/dataTable/useTableVirtualization.d.ts.map +1 -1
- package/dist/components/form/BagelForm.vue.d.ts +5 -10
- package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
- package/dist/components/form/BglMultiStepForm.vue.d.ts +10 -6
- package/dist/components/form/BglMultiStepForm.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts +3 -2
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts +14 -6
- package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/composables/index.d.ts +5 -5
- package/dist/composables/index.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts +5 -12
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +298 -357
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +299 -358
- package/dist/plugins/modalTypes.d.ts +3 -2
- package/dist/plugins/modalTypes.d.ts.map +1 -1
- package/dist/style.css +165 -135
- package/dist/types/BagelForm.d.ts +14 -11
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/types/TableSchema.d.ts +9 -9
- package/dist/types/TableSchema.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +4 -3
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/useSearch.d.ts +44 -0
- package/dist/utils/useSearch.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/DataPreview.vue +16 -5
- package/src/components/Icon/Icon.vue +12 -3
- package/src/components/ModalForm.vue +6 -9
- package/src/components/dataTable/DataTable.vue +11 -14
- package/src/components/dataTable/useSorting.ts +1 -1
- package/src/components/dataTable/useTableData.ts +19 -42
- package/src/components/dataTable/useTableVirtualization.ts +4 -8
- package/src/components/form/BagelForm.vue +33 -97
- package/src/components/form/BglMultiStepForm.vue +52 -36
- package/src/components/form/FieldArray.vue +54 -45
- package/src/components/form/inputs/CodeEditor/Index.vue +160 -98
- package/src/components/form/inputs/RichText/index.vue +13 -12
- package/src/composables/index.ts +12 -13
- package/src/composables/useSchemaField.ts +37 -35
- package/src/index.ts +1 -1
- package/src/plugins/modalTypes.ts +3 -2
- package/src/types/BagelForm.ts +22 -14
- package/src/types/TableSchema.ts +9 -9
- package/src/utils/BagelFormUtils.ts +4 -3
- package/src/utils/index.ts +38 -13
- package/src/utils/{search.ts → useSearch.ts} +1 -2
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
<script setup lang="ts" generic="T extends {[key:string]:any}, P">
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
5
|
-
import { onMounted, watch, ref, toRef, computed } from 'vue'
|
|
1
|
+
<script setup lang="ts" generic="T extends {[key:string]:any}, P extends Path<T>">
|
|
2
|
+
import type { Field, BglFormSchemaT, Path, BaseBagelField } from '@bagelink/vue'
|
|
3
|
+
import type { MaybeRefOrGetter } from 'vue'
|
|
4
|
+
import { onMounted, watch, ref, computed, toValue } from 'vue'
|
|
6
5
|
import { useSchemaField } from '../../composables/useSchemaField'
|
|
7
6
|
import { getNestedValue } from '../../utils'
|
|
8
7
|
|
|
9
8
|
const props = withDefaults(defineProps<{
|
|
10
9
|
modelValue?: T
|
|
11
|
-
schema?:
|
|
10
|
+
schema?: MaybeRefOrGetter<BglFormSchemaT<T>>
|
|
12
11
|
tag?: 'form' | 'template'
|
|
13
12
|
class?: string
|
|
14
13
|
onSubmit?: (data: T) => Promise<unknown> | unknown
|
|
@@ -31,10 +30,8 @@ const form = ref<HTMLFormElement>()
|
|
|
31
30
|
const formData = ref<T>(clone(props.modelValue ?? {}) as T)
|
|
32
31
|
const initialFormData = ref<T>(clone(props.modelValue ?? {}) as T)
|
|
33
32
|
const formState = ref<'success' | 'error' | 'idle' | 'submitting'>('idle')
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const schemaRef = toRef(props, 'schema')
|
|
37
|
-
const resolvedSchema = computed(() => resolvedSchemaData.value)
|
|
33
|
+
const resolvedSchema = computed(() => toValue(props.schema))
|
|
34
|
+
|
|
38
35
|
const isDirty = computed(() => {
|
|
39
36
|
try {
|
|
40
37
|
return JSON.stringify(formData.value) !== JSON.stringify(initialFormData.value)
|
|
@@ -46,7 +43,6 @@ const isDirty = computed(() => {
|
|
|
46
43
|
// Initialize on mount
|
|
47
44
|
onMounted(() => {
|
|
48
45
|
if (props.modelValue) initialFormData.value = clone(props.modelValue)
|
|
49
|
-
refreshSchema()
|
|
50
46
|
})
|
|
51
47
|
|
|
52
48
|
// Watch for model changes
|
|
@@ -54,47 +50,9 @@ watch(() => props.modelValue, (val) => {
|
|
|
54
50
|
if (val !== undefined) formData.value = clone(val)
|
|
55
51
|
}, { immediate: true, deep: true })
|
|
56
52
|
|
|
57
|
-
// Schema resolution
|
|
58
|
-
async function resolveSchema(schema?: BglFormSchemaFnT<T>) {
|
|
59
|
-
if (!schema) {
|
|
60
|
-
resolvedSchemaData.value = undefined
|
|
61
|
-
schemaState.value = 'loaded'
|
|
62
|
-
return
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
schemaState.value = 'loading'
|
|
67
|
-
const isPromise = (obj: any) => obj && typeof obj.then === 'function'
|
|
68
|
-
|
|
69
|
-
let result: any
|
|
70
|
-
if (typeof schema === 'function') {
|
|
71
|
-
result = schema()
|
|
72
|
-
result = isPromise(result) ? await result : result
|
|
73
|
-
} else {
|
|
74
|
-
result = isPromise(schema) ? await schema : schema
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
resolvedSchemaData.value = result
|
|
78
|
-
schemaState.value = 'loaded'
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error('Schema error:', error)
|
|
81
|
-
schemaState.value = 'error'
|
|
82
|
-
resolvedSchemaData.value = undefined
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Public refresh method
|
|
87
|
-
async function refreshSchema() {
|
|
88
|
-
await resolveSchema(props.schema)
|
|
89
|
-
return resolvedSchemaData.value
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Watch schema changes
|
|
93
|
-
watch(schemaRef, resolveSchema, { immediate: true, deep: true })
|
|
94
|
-
|
|
95
53
|
// Update form data
|
|
96
|
-
function updateFormData(fieldId: string, value: any) {
|
|
97
|
-
const keys = fieldId
|
|
54
|
+
function updateFormData({ fieldId, value }: { fieldId?: string, value: any }) {
|
|
55
|
+
const keys = fieldId?.split('.') || []
|
|
98
56
|
const newData = clone(formData.value) as { [key: string]: any }
|
|
99
57
|
let current = newData
|
|
100
58
|
|
|
@@ -111,6 +69,7 @@ function updateFormData(fieldId: string, value: any) {
|
|
|
111
69
|
|
|
112
70
|
// Form validation
|
|
113
71
|
const validateForm = () => form.value?.reportValidity() ?? false
|
|
72
|
+
const checkValidity = () => form.value?.checkValidity() ?? false
|
|
114
73
|
const formError = ref<Error>()
|
|
115
74
|
// Form submission
|
|
116
75
|
async function handleSubmit() {
|
|
@@ -130,7 +89,7 @@ async function handleSubmit() {
|
|
|
130
89
|
}
|
|
131
90
|
}
|
|
132
91
|
|
|
133
|
-
// Field
|
|
92
|
+
// Field renderingks
|
|
134
93
|
const { renderField } = useSchemaField<T, P>({
|
|
135
94
|
mode: 'form',
|
|
136
95
|
getFormData: () => ({
|
|
@@ -140,23 +99,23 @@ const { renderField } = useSchemaField<T, P>({
|
|
|
140
99
|
onUpdateModelValue: (field, value) => {
|
|
141
100
|
if (!field.id) return
|
|
142
101
|
|
|
143
|
-
updateFormData(field.id, value)
|
|
102
|
+
updateFormData({ fieldId: field.id, value })
|
|
144
103
|
field.onUpdate?.(value, formData.value)
|
|
145
104
|
}
|
|
146
105
|
})
|
|
147
106
|
|
|
148
|
-
const renderSchemaField = (field: Field<T>)
|
|
107
|
+
const renderSchemaField = (field: Field<T>) => renderField(field as BaseBagelField<T, P>)
|
|
149
108
|
|
|
150
109
|
// Add new method to handle slot input changes
|
|
151
110
|
function handleSlotInputChange(event: Event) {
|
|
152
111
|
const input = event.target as HTMLInputElement
|
|
153
112
|
if (input.name) {
|
|
154
113
|
const value = input.type === 'checkbox' ? input.checked : input.value
|
|
155
|
-
updateFormData(input.name, value)
|
|
114
|
+
updateFormData({ fieldId: input.name, value })
|
|
156
115
|
}
|
|
157
116
|
}
|
|
158
117
|
|
|
159
|
-
defineExpose({ form, isDirty, validateForm,
|
|
118
|
+
defineExpose({ form, isDirty, validateForm, checkValidity })
|
|
160
119
|
</script>
|
|
161
120
|
|
|
162
121
|
<template>
|
|
@@ -167,27 +126,14 @@ defineExpose({ form, isDirty, validateForm, resolveSchema, refreshSchema })
|
|
|
167
126
|
@submit.prevent="handleSubmit"
|
|
168
127
|
@input="handleSlotInputChange"
|
|
169
128
|
>
|
|
170
|
-
<!-- Loading state -->
|
|
171
|
-
<slot v-if="schemaState === 'loading'" name="loading">
|
|
172
|
-
<div class="flex-center h-300px">
|
|
173
|
-
<Loading />
|
|
174
|
-
</div>
|
|
175
|
-
</slot>
|
|
176
|
-
|
|
177
|
-
<!-- Error state -->
|
|
178
|
-
<slot v-else-if="schemaState === 'error'" name="schema-error">
|
|
179
|
-
<div class="flex-center h-300px txt-red">
|
|
180
|
-
Error loading form
|
|
181
|
-
</div>
|
|
182
|
-
</slot>
|
|
183
|
-
|
|
184
129
|
<!-- Render fields -->
|
|
185
|
-
<
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
130
|
+
<template v-if="resolvedSchema">
|
|
131
|
+
<Component
|
|
132
|
+
:is="renderSchemaField(field)"
|
|
133
|
+
v-for="field in resolvedSchema"
|
|
134
|
+
:key="field.id"
|
|
135
|
+
/>
|
|
136
|
+
</template>
|
|
191
137
|
|
|
192
138
|
<!-- Default slot -->
|
|
193
139
|
<slot v-else />
|
|
@@ -195,32 +141,22 @@ defineExpose({ form, isDirty, validateForm, resolveSchema, refreshSchema })
|
|
|
195
141
|
<slot
|
|
196
142
|
name="submit"
|
|
197
143
|
:submit="handleSubmit"
|
|
198
|
-
:isDirty
|
|
199
|
-
:validateForm
|
|
200
|
-
:formState
|
|
201
|
-
:schemaState="schemaState"
|
|
144
|
+
:isDirty
|
|
145
|
+
:validateForm
|
|
146
|
+
:formState
|
|
202
147
|
/>
|
|
203
148
|
</form>
|
|
204
149
|
|
|
205
150
|
<!-- Template mode -->
|
|
206
151
|
<template v-else>
|
|
207
|
-
<
|
|
208
|
-
<
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
</slot>
|
|
216
|
-
|
|
217
|
-
<component
|
|
218
|
-
:is="renderSchemaField(field)"
|
|
219
|
-
v-for="field in resolvedSchema"
|
|
220
|
-
v-else-if="resolvedSchema"
|
|
221
|
-
:key="field.id"
|
|
222
|
-
:class="props.class"
|
|
223
|
-
/>
|
|
152
|
+
<template v-if="resolvedSchema">
|
|
153
|
+
<component
|
|
154
|
+
:is="renderSchemaField(field)"
|
|
155
|
+
v-for="field in resolvedSchema"
|
|
156
|
+
:key="field.id"
|
|
157
|
+
:class="props.class"
|
|
158
|
+
/>
|
|
159
|
+
</template>
|
|
224
160
|
</template>
|
|
225
161
|
</template>
|
|
226
162
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
<script setup lang="ts" generic="T extends {[key:string]:any}, P">
|
|
2
|
-
import type {
|
|
1
|
+
<script setup lang="ts" generic="T extends {[key:string]:any}, P extends Path<T>">
|
|
2
|
+
import type { BglFormSchemaT, Path } from '@bagelink/vue'
|
|
3
3
|
|
|
4
|
+
import type { MaybeRefOrGetter } from 'vue'
|
|
4
5
|
import type { ComponentExposed, ComponentProps } from 'vue-component-type-helpers'
|
|
5
|
-
import { BagelForm, Btn, useBglSchema } from '@bagelink/vue'
|
|
6
|
-
import { ref, watch, computed } from 'vue'
|
|
6
|
+
import { BagelForm, Btn, useBglSchema, sleep } from '@bagelink/vue'
|
|
7
|
+
import { ref, watch, computed, nextTick, toValue } from 'vue'
|
|
7
8
|
|
|
8
9
|
const props = withDefaults(
|
|
9
10
|
defineProps<{
|
|
@@ -13,7 +14,7 @@ const props = withDefaults(
|
|
|
13
14
|
'schema' | `${string}modelValue` | `ref${string}` | `onVnode${string}` | 'onSubmit'
|
|
14
15
|
)
|
|
15
16
|
>
|
|
16
|
-
schema
|
|
17
|
+
schema?: MaybeRefOrGetter<BglFormSchemaT<T>>
|
|
17
18
|
showProgress?: boolean
|
|
18
19
|
rtl?: boolean
|
|
19
20
|
stepLabels?: string[]
|
|
@@ -59,13 +60,13 @@ function reportValidity() {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
const computedSchema = computed(
|
|
62
|
-
() => useBglSchema({ schema: props.schema })
|
|
63
|
+
() => useBglSchema({ schema: toValue(props.schema) })
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
// Filter out steps with vIf conditions that evaluate to false
|
|
66
67
|
const filteredSchema = computed(() => {
|
|
67
68
|
const schema = computedSchema.value
|
|
68
|
-
return schema.filter((step,
|
|
69
|
+
return schema.filter((step, _index) => {
|
|
69
70
|
// Skip steps that have vIf or v-if returning false
|
|
70
71
|
if (step.vIf !== undefined || step['v-if'] !== undefined) {
|
|
71
72
|
const condition = step.vIf ?? step['v-if']
|
|
@@ -119,9 +120,6 @@ const currentStepSchema = computed(() => {
|
|
|
119
120
|
return [computedSchema.value[actualIndex]]
|
|
120
121
|
})
|
|
121
122
|
|
|
122
|
-
const isStepping = ref(false)
|
|
123
|
-
let isSteppingTO: NodeJS.Timeout
|
|
124
|
-
|
|
125
123
|
// Tracks which way we're sliding (left or right)
|
|
126
124
|
const slideDirection = ref(props.rtl ? 'right' : 'left')
|
|
127
125
|
|
|
@@ -138,9 +136,7 @@ watch(
|
|
|
138
136
|
}
|
|
139
137
|
|
|
140
138
|
previousStep.value = oldStep
|
|
141
|
-
|
|
142
|
-
isStepping.value = true
|
|
143
|
-
isSteppingTO = setTimeout(() => (isStepping.value = false), 200)
|
|
139
|
+
// We don't need isStepping flag anymore
|
|
144
140
|
emits('stepChange', {
|
|
145
141
|
newStep,
|
|
146
142
|
oldStep,
|
|
@@ -150,19 +146,32 @@ watch(
|
|
|
150
146
|
}
|
|
151
147
|
)
|
|
152
148
|
|
|
153
|
-
const
|
|
149
|
+
const isLastStep = computed(() => currentStep.value === numberOfSteps.value - 1)
|
|
154
150
|
|
|
155
151
|
const isStepValidated = computed(() => (stepIndex: number) => validatedSteps.value.includes(stepIndex))
|
|
156
152
|
|
|
153
|
+
// Add a computed property to check if current step is valid
|
|
154
|
+
const isStepValid = ref(false)
|
|
155
|
+
|
|
156
|
+
async function checkCurrentStepValidity() {
|
|
157
|
+
await nextTick()
|
|
158
|
+
if (!props.validateOnSteps) isStepValid.value = true
|
|
159
|
+
else isStepValid.value = formRef.value?.checkValidity() ?? false
|
|
160
|
+
}
|
|
161
|
+
|
|
157
162
|
function prevStep() {
|
|
158
163
|
if (currentStep.value > 0) currentStep.value--
|
|
159
164
|
}
|
|
160
165
|
|
|
161
166
|
const formContainer = ref<HTMLElement>()
|
|
162
167
|
|
|
163
|
-
function nextStep() {
|
|
168
|
+
async function nextStep() {
|
|
169
|
+
// Always use reportValidity when attempting to move to next step
|
|
170
|
+
// This will show validation errors to the user
|
|
164
171
|
if (props.validateOnSteps && reportValidity() === false) return
|
|
165
|
-
if (
|
|
172
|
+
if (!isLastStep.value) currentStep.value++
|
|
173
|
+
await sleep(400)
|
|
174
|
+
checkCurrentStepValidity()
|
|
166
175
|
}
|
|
167
176
|
|
|
168
177
|
function goToStep(stepIndex: number) {
|
|
@@ -173,6 +182,7 @@ function goToStep(stepIndex: number) {
|
|
|
173
182
|
}
|
|
174
183
|
|
|
175
184
|
// For forward navigation to non-validated steps, validate current step first if needed
|
|
185
|
+
// This will show validation errors to the user
|
|
176
186
|
if (props.validateOnSteps && reportValidity() === false) {
|
|
177
187
|
return false
|
|
178
188
|
}
|
|
@@ -187,6 +197,7 @@ function goToStep(stepIndex: number) {
|
|
|
187
197
|
}
|
|
188
198
|
|
|
189
199
|
function handleSubmit() {
|
|
200
|
+
// Show validation errors to the user when submitting
|
|
190
201
|
if (reportValidity() === false) return
|
|
191
202
|
emits('submit', formData.value)
|
|
192
203
|
}
|
|
@@ -194,15 +205,11 @@ function handleSubmit() {
|
|
|
194
205
|
function reset() {
|
|
195
206
|
validatedSteps.value = []
|
|
196
207
|
currentStep.value = 0
|
|
197
|
-
// Clear form if BagelForm supports it
|
|
198
|
-
// if (formRef.value && typeof formRef.value.clearForm === 'function') {
|
|
199
|
-
// formRef.value.clearForm()
|
|
200
|
-
// }
|
|
201
208
|
}
|
|
202
209
|
|
|
203
210
|
// Re-evaluate filtered steps when formData changes
|
|
204
211
|
watch(() => formData.value, () => {
|
|
205
|
-
|
|
212
|
+
checkCurrentStepValidity()
|
|
206
213
|
if (currentStep.value >= numberOfSteps.value && numberOfSteps.value > 0) {
|
|
207
214
|
currentStep.value = 0
|
|
208
215
|
}
|
|
@@ -211,11 +218,13 @@ watch(() => formData.value, () => {
|
|
|
211
218
|
defineExpose({
|
|
212
219
|
submit: handleSubmit,
|
|
213
220
|
validateForm: reportValidity,
|
|
221
|
+
checkValidity: formRef.value?.checkValidity,
|
|
214
222
|
isDirty: computed(() => formRef.value?.isDirty),
|
|
215
223
|
reset,
|
|
216
224
|
goToStep,
|
|
217
225
|
currentStep: computed(() => currentStep.value),
|
|
218
226
|
totalSteps: computed(() => numberOfSteps.value),
|
|
227
|
+
isStepValid,
|
|
219
228
|
nextStep,
|
|
220
229
|
prevStep,
|
|
221
230
|
})
|
|
@@ -260,7 +269,7 @@ defineExpose({
|
|
|
260
269
|
:name="slideDirection === 'right' ? 'slide-right' : 'slide-left'"
|
|
261
270
|
mode="out-in"
|
|
262
271
|
>
|
|
263
|
-
<div
|
|
272
|
+
<div :key="currentStep" ref="formContainer" class="bgl-form-container">
|
|
264
273
|
<BagelForm
|
|
265
274
|
ref="formRef"
|
|
266
275
|
v-model="formData"
|
|
@@ -286,11 +295,17 @@ defineExpose({
|
|
|
286
295
|
submit: handleSubmit,
|
|
287
296
|
currentStep,
|
|
288
297
|
totalSteps: numberOfSteps,
|
|
289
|
-
|
|
298
|
+
isLastStep,
|
|
299
|
+
isStepValid,
|
|
290
300
|
}"
|
|
291
301
|
>
|
|
292
|
-
<Btn v-if="currentStep !== 0" color="gray" icon="arrow_back" click="prevStep" />
|
|
293
|
-
<Btn
|
|
302
|
+
<Btn v-if="currentStep !== 0" color="gray" icon="arrow_back" @click="prevStep" />
|
|
303
|
+
<Btn
|
|
304
|
+
v-if="!isLastStep"
|
|
305
|
+
icon="arrow_forward"
|
|
306
|
+
:disabled="props.validateOnSteps && !isStepValid"
|
|
307
|
+
@click="nextStep"
|
|
308
|
+
/>
|
|
294
309
|
<Btn v-else value="Submit" @click="handleSubmit" />
|
|
295
310
|
</slot>
|
|
296
311
|
</div>
|
|
@@ -305,12 +320,10 @@ defineExpose({
|
|
|
305
320
|
gap: 1rem;
|
|
306
321
|
width: 100%;
|
|
307
322
|
/* Default transition duration */
|
|
308
|
-
--transition-duration:
|
|
323
|
+
--transition-duration: 300ms;
|
|
309
324
|
--move-distance: 35%;
|
|
310
|
-
--ease-in:
|
|
311
|
-
--ease-out:
|
|
312
|
-
/* --ease-in: cubic-bezier(0.42, 0, 0.58, 1); */
|
|
313
|
-
/* --ease-out: cubic-bezier(0.5, 0, 0.75, 0); */
|
|
325
|
+
--ease-in: cubic-bezier(0.42, 0, 0.58, 1);
|
|
326
|
+
--ease-out: cubic-bezier(0.42, 0, 0.58, 1);
|
|
314
327
|
}
|
|
315
328
|
|
|
316
329
|
.bgl-steps-indicator {
|
|
@@ -398,16 +411,18 @@ defineExpose({
|
|
|
398
411
|
justify-content: center;
|
|
399
412
|
gap: 1rem;
|
|
400
413
|
grid-area: unset !important;
|
|
401
|
-
|
|
414
|
+
margin-top: 2rem;
|
|
402
415
|
}
|
|
403
416
|
|
|
404
417
|
/* Slide Left Animation (going forward) */
|
|
405
418
|
.slide-left-enter-active {
|
|
406
|
-
transition: opacity
|
|
419
|
+
transition: opacity var(--transition-duration) var(--ease-in),
|
|
420
|
+
transform var(--transition-duration) var(--ease-in);
|
|
407
421
|
}
|
|
408
422
|
|
|
409
423
|
.slide-left-leave-active {
|
|
410
|
-
transition: opacity
|
|
424
|
+
transition: opacity var(--transition-duration) var(--ease-out),
|
|
425
|
+
transform var(--transition-duration) var(--ease-out);
|
|
411
426
|
}
|
|
412
427
|
|
|
413
428
|
.slide-left-enter-from {
|
|
@@ -422,12 +437,13 @@ defineExpose({
|
|
|
422
437
|
|
|
423
438
|
/* Slide Right Animation (going back) */
|
|
424
439
|
.slide-right-enter-active {
|
|
425
|
-
transition:
|
|
440
|
+
transition: opacity var(--transition-duration) var(--ease-in),
|
|
441
|
+
transform var(--transition-duration) var(--ease-in);
|
|
426
442
|
}
|
|
427
443
|
|
|
428
444
|
.slide-right-leave-active {
|
|
429
|
-
transition:
|
|
430
|
-
|
|
445
|
+
transition: opacity var(--transition-duration) var(--ease-out),
|
|
446
|
+
transform var(--transition-duration) var(--ease-out);
|
|
431
447
|
}
|
|
432
448
|
|
|
433
449
|
.slide-right-enter-from {
|
|
@@ -5,12 +5,13 @@ import type {
|
|
|
5
5
|
Attributes,
|
|
6
6
|
BagelFieldOptions,
|
|
7
7
|
BaseBagelField,
|
|
8
|
-
|
|
8
|
+
BglFormSchemaT,
|
|
9
9
|
Field,
|
|
10
10
|
Path
|
|
11
11
|
} from '@bagelink/vue'
|
|
12
|
+
import type { MaybeRefOrGetter } from 'vue'
|
|
12
13
|
import { BagelForm, Btn, Loading, Icon } from '@bagelink/vue'
|
|
13
|
-
import { ref,
|
|
14
|
+
import { ref, computed, watch, toValue } from 'vue'
|
|
14
15
|
|
|
15
16
|
export interface FieldArrayProps<T, P extends Path<T>> {
|
|
16
17
|
el?: any
|
|
@@ -28,7 +29,7 @@ export interface FieldArrayProps<T, P extends Path<T>> {
|
|
|
28
29
|
add?: boolean
|
|
29
30
|
delete?: boolean
|
|
30
31
|
transform?: (value: T) => T
|
|
31
|
-
schema?:
|
|
32
|
+
schema?: MaybeRefOrGetter<BglFormSchemaT<T>>
|
|
32
33
|
modelValue: T[]
|
|
33
34
|
type?: 'object' | 'number' | 'text'
|
|
34
35
|
}
|
|
@@ -53,12 +54,6 @@ const emit = defineEmits(['update:modelValue'])
|
|
|
53
54
|
const minimizedItems = ref<boolean[]>([])
|
|
54
55
|
const internalData = ref<any[]>(props.modelValue || [])
|
|
55
56
|
const schemaState = ref<'loading' | 'loaded' | 'error'>('loaded')
|
|
56
|
-
const resolvedSchemaData = ref<any[]>([])
|
|
57
|
-
|
|
58
|
-
// Watch for external changes to modelValue
|
|
59
|
-
watch(() => props.modelValue, (newValue) => {
|
|
60
|
-
internalData.value = newValue || []
|
|
61
|
-
}, { deep: true })
|
|
62
57
|
|
|
63
58
|
// Generate schema for primitive types
|
|
64
59
|
const primitiveSchema = computed<PrimitiveArrFieldT[]>(() => {
|
|
@@ -70,46 +65,57 @@ const primitiveSchema = computed<PrimitiveArrFieldT[]>(() => {
|
|
|
70
65
|
return []
|
|
71
66
|
})
|
|
72
67
|
|
|
68
|
+
const resolvedSchemaData = $computed(() => {
|
|
69
|
+
if (props.type !== 'object') return primitiveSchema.value as BglFormSchemaT<T>
|
|
70
|
+
|
|
71
|
+
return toValue(props.schema)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Watch for external changes to modelValue
|
|
75
|
+
watch(() => props.modelValue, (newValue) => {
|
|
76
|
+
internalData.value = newValue || []
|
|
77
|
+
}, { deep: true })
|
|
78
|
+
|
|
73
79
|
// Resolve schema
|
|
74
|
-
async function resolveSchema() {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
// async function resolveSchema() {
|
|
81
|
+
// // For primitive types, use the predefined schemaks
|
|
82
|
+
// if (props.type !== 'object') {
|
|
83
|
+
// resolvedSchemaData.value = primitiveSchema.value
|
|
84
|
+
// schemaState.value = 'loaded'
|
|
85
|
+
// return
|
|
86
|
+
// }
|
|
81
87
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
// // For object type without schema
|
|
89
|
+
// if (!props.schema) {
|
|
90
|
+
// resolvedSchemaData.value = []
|
|
91
|
+
// schemaState.value = 'loaded'
|
|
92
|
+
// return
|
|
93
|
+
// }
|
|
88
94
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
// // For object type with schema
|
|
96
|
+
// try {
|
|
97
|
+
// // schemaState.value = 'loading'
|
|
98
|
+
// const isPromise = (obj: any) => obj && typeof obj.then === 'function'
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
// let result: any
|
|
101
|
+
// if (typeof props.schema === 'function') {
|
|
102
|
+
// result = props.schema()
|
|
103
|
+
// result = isPromise(result) ? await result : result
|
|
104
|
+
// } else {
|
|
105
|
+
// result = isPromise(props.schema) ? await props.schema : props.schema
|
|
106
|
+
// }
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
108
|
+
// resolvedSchemaData.value = result
|
|
109
|
+
// schemaState.value = 'loaded'
|
|
110
|
+
// } catch (error) {
|
|
111
|
+
// console.error('Schema error:', error)
|
|
112
|
+
// schemaState.value = 'error'
|
|
113
|
+
// resolvedSchemaData.value = []
|
|
114
|
+
// }
|
|
115
|
+
// }
|
|
110
116
|
|
|
111
|
-
// Initialize schema on mount
|
|
112
|
-
onMounted(resolveSchema)
|
|
117
|
+
// // Initialize schema on mount
|
|
118
|
+
// onMounted(resolveSchema)
|
|
113
119
|
|
|
114
120
|
// Event handlers
|
|
115
121
|
function emitValue() {
|
|
@@ -148,10 +154,13 @@ function updateItem(index: number, value: any) {
|
|
|
148
154
|
|
|
149
155
|
// Computed properties for rendering
|
|
150
156
|
const isPrimitiveType = computed(() => props.type === 'text' || props.type === 'number')
|
|
151
|
-
const canRenderItems = computed(
|
|
157
|
+
const canRenderItems = computed(
|
|
158
|
+
() => isPrimitiveType.value || (
|
|
159
|
+
props.type === 'object' && Number(resolvedSchemaData?.length) > 0
|
|
160
|
+
)
|
|
152
161
|
)
|
|
153
162
|
const showMinimizeButton = computed(() => {
|
|
154
|
-
return resolvedSchemaData
|
|
163
|
+
return Number(resolvedSchemaData?.length) > 2 || resolvedSchemaData?.some(schema => schema.$el === 'richtext')
|
|
155
164
|
})
|
|
156
165
|
</script>
|
|
157
166
|
|