@bagelink/vue 0.0.1117 → 0.0.1121
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/Image.vue.d.ts +8 -8
- package/dist/components/Image.vue.d.ts.map +1 -1
- 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/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
- package/dist/index.cjs +245 -205
- package/dist/index.mjs +245 -205
- package/dist/style.css +13 -10
- package/package.json +1 -1
- package/src/components/Image.vue +103 -53
- 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/src/components/form/inputs/RichText/components/EditorToolbar.vue +1 -0
package/dist/style.css
CHANGED
|
@@ -1244,14 +1244,14 @@ pre code.hljs{
|
|
|
1244
1244
|
direction: ltr;
|
|
1245
1245
|
}
|
|
1246
1246
|
|
|
1247
|
-
.txtInputIconStart .iconStart[data-v-
|
|
1247
|
+
.txtInputIconStart .iconStart[data-v-4a70ce50] {
|
|
1248
1248
|
color: var(--input-color);
|
|
1249
1249
|
position: absolute;
|
|
1250
1250
|
inset-inline-start:calc(var(--input-height) / 3 - 0.25rem);
|
|
1251
1251
|
margin-top: calc(var(--input-height) / 2 );
|
|
1252
1252
|
line-height: 0;
|
|
1253
1253
|
}
|
|
1254
|
-
.textInputSpinnerWrap .spinner[data-v-
|
|
1254
|
+
.textInputSpinnerWrap .spinner[data-v-4a70ce50] {
|
|
1255
1255
|
color: var(--input-color);
|
|
1256
1256
|
position: absolute;
|
|
1257
1257
|
inset-inline-end: 0;
|
|
@@ -1261,18 +1261,18 @@ pre code.hljs{
|
|
|
1261
1261
|
flex-direction: column;
|
|
1262
1262
|
gap: 0;
|
|
1263
1263
|
}
|
|
1264
|
-
.top-bgl-ctrl-num-btn[data-v-
|
|
1264
|
+
.top-bgl-ctrl-num-btn[data-v-4a70ce50]{
|
|
1265
1265
|
margin-top: calc(var(--input-height) / 10) !important;
|
|
1266
1266
|
}
|
|
1267
|
-
.bgl-ctrl-num-btn[data-v-
|
|
1267
|
+
.bgl-ctrl-num-btn[data-v-4a70ce50]{
|
|
1268
1268
|
height: calc(var(--input-height) / 2.5) !important;
|
|
1269
1269
|
isolation: isolate;
|
|
1270
1270
|
}
|
|
1271
|
-
.bgl-big-ctrl-num-btn[data-v-
|
|
1271
|
+
.bgl-big-ctrl-num-btn[data-v-4a70ce50]{
|
|
1272
1272
|
width: 100% !important;
|
|
1273
1273
|
isolation: isolate;
|
|
1274
1274
|
}
|
|
1275
|
-
.bgl-number-input[data-v-
|
|
1275
|
+
.bgl-number-input[data-v-4a70ce50]{
|
|
1276
1276
|
padding-inline-end: 1.75rem !important;
|
|
1277
1277
|
}
|
|
1278
1278
|
|
|
@@ -1435,7 +1435,7 @@ input[type="range"][data-v-25d991e5]:active::-webkit-slider-thumb {
|
|
|
1435
1435
|
background: var(--bgl-primary-light);
|
|
1436
1436
|
}
|
|
1437
1437
|
|
|
1438
|
-
.toolbar[data-v-
|
|
1438
|
+
.toolbar[data-v-bcd681b9] .active {
|
|
1439
1439
|
background: var(--bgl-primary);
|
|
1440
1440
|
color: white;
|
|
1441
1441
|
}
|
|
@@ -2123,12 +2123,15 @@ line-height: 1.65;
|
|
|
2123
2123
|
color: var(--bgl-green);
|
|
2124
2124
|
}
|
|
2125
2125
|
|
|
2126
|
-
.img-web-kit[data-v-
|
|
2126
|
+
.img-web-kit[data-v-6f277b5b] {
|
|
2127
2127
|
max-width: 100%;
|
|
2128
2128
|
vertical-align: middle;
|
|
2129
2129
|
border: 0;
|
|
2130
2130
|
width: 100%;
|
|
2131
2131
|
}
|
|
2132
|
+
.error-image[data-v-6f277b5b] {
|
|
2133
|
+
background-color: var(--skeleton-bg);
|
|
2134
|
+
}
|
|
2132
2135
|
|
|
2133
2136
|
.bgl_bottombar .bgl_btn-flex{
|
|
2134
2137
|
flex-direction: column;
|
|
@@ -3336,11 +3339,11 @@ body:has(.bg-dark.is-active) {
|
|
|
3336
3339
|
border-radius: var(--card-border-radius);
|
|
3337
3340
|
}
|
|
3338
3341
|
|
|
3339
|
-
.modal-title[data-v-
|
|
3342
|
+
.modal-title[data-v-f796c518] {
|
|
3340
3343
|
margin-top: 0.5rem;
|
|
3341
3344
|
}
|
|
3342
3345
|
@media screen and (max-width: 910px) {
|
|
3343
|
-
.modal-title[data-v-
|
|
3346
|
+
.modal-title[data-v-f796c518] {
|
|
3344
3347
|
margin-top: 1rem;
|
|
3345
3348
|
}
|
|
3346
3349
|
}
|
package/package.json
CHANGED
package/src/components/Image.vue
CHANGED
|
@@ -1,83 +1,112 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { Skeleton, normalizeDimension, appendScript, normalizeURL } from '@bagelink/vue'
|
|
3
|
-
import { watch } from 'vue'
|
|
2
|
+
import { Skeleton, normalizeDimension, appendScript, normalizeURL, Icon } from '@bagelink/vue'
|
|
3
|
+
import { watch, computed } from 'vue'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
interface Window {
|
|
7
|
-
heic2any: any
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const { height, width, alt = '', src, pathKey } = defineProps<{
|
|
5
|
+
interface ImageProps {
|
|
12
6
|
src?: string
|
|
13
7
|
pathKey?: string
|
|
14
8
|
alt?: string
|
|
15
9
|
width?: string | number
|
|
16
10
|
height?: string | number
|
|
17
11
|
caption?: string
|
|
18
|
-
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare global {
|
|
15
|
+
interface Window {
|
|
16
|
+
heic2any: any
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const props = defineProps<ImageProps>()
|
|
19
21
|
|
|
20
22
|
let imageSrc = $ref<string | null>(null)
|
|
23
|
+
let loadingError = $ref(false)
|
|
21
24
|
|
|
22
|
-
const fileBaseUrl =
|
|
23
|
-
function pathToUrl() {
|
|
24
|
-
if (pathKey?.startsWith('static/')) return `${import.meta.env.VITE_BAGEL_BASE_URL}/${pathKey}`
|
|
25
|
+
const fileBaseUrl = computed(() => 'https://files.bagel.design')
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
function getImageUrl(): string | null {
|
|
28
|
+
if (!props.src && !props.pathKey) return null
|
|
29
|
+
if (props.src) return props.src
|
|
30
|
+
if (props.pathKey?.startsWith('static/')) {
|
|
31
|
+
return `${import.meta.env.VITE_BAGEL_BASE_URL}/${props.pathKey}`
|
|
32
|
+
}
|
|
33
|
+
return `${fileBaseUrl.value}/${props.pathKey}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function getCachedImage(url: string): Promise<string | null> {
|
|
37
|
+
if (!('caches' in window)) return null
|
|
38
|
+
try {
|
|
39
|
+
const imgCache = await window.caches.open('img-cache')
|
|
40
|
+
const cachedResponse = await imgCache.match(url)
|
|
41
|
+
if (cachedResponse) {
|
|
42
|
+
return URL.createObjectURL(await cachedResponse.blob())
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.warn('Cache access error:', error)
|
|
46
|
+
}
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function cacheImage(url: string, blob: Blob) {
|
|
51
|
+
if (!('caches' in window)) return
|
|
52
|
+
try {
|
|
53
|
+
const imgCache = await window.caches.open('img-cache')
|
|
54
|
+
await imgCache.put(url, new Response(blob))
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.warn('Cache write error:', error)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function convertHeicImage(url: string): Promise<string> {
|
|
61
|
+
await appendScript('https://cdnjs.cloudflare.com/ajax/libs/heic2any/0.0.1/index.min.js')
|
|
62
|
+
const response = await fetch(normalizeURL(url))
|
|
63
|
+
const blob = await response.blob()
|
|
64
|
+
const convertedBlob = await window.heic2any({ blob }) as Blob
|
|
65
|
+
await cacheImage(url, convertedBlob)
|
|
66
|
+
return URL.createObjectURL(convertedBlob)
|
|
27
67
|
}
|
|
28
68
|
|
|
29
69
|
async function loadImage() {
|
|
30
|
-
|
|
31
|
-
|
|
70
|
+
loadingError = false
|
|
71
|
+
const url = getImageUrl()
|
|
32
72
|
if (!url) {
|
|
33
73
|
imageSrc = null
|
|
34
74
|
return
|
|
35
75
|
}
|
|
36
|
-
const ext = url.split('.').pop()?.toLowerCase().split('?').shift()
|
|
37
76
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
imageSrc = URL.createObjectURL(await cachedResponse.blob())
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.warn('Error accessing cache:', error)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
await appendScript('https://cdnjs.cloudflare.com/ajax/libs/heic2any/0.0.1/index.min.js')
|
|
55
|
-
const response = await fetch(normalizeURL(url))
|
|
56
|
-
const blob = await response.blob()
|
|
57
|
-
const convertedBlob = await window.heic2any({ blob }) as Blob
|
|
58
|
-
imageSrc = URL.createObjectURL(convertedBlob)
|
|
59
|
-
// Only attempt to cache if the cache API is available
|
|
60
|
-
if ('caches' in window) {
|
|
61
|
-
try {
|
|
62
|
-
const imgCache = await window.caches.open('img-cache')
|
|
63
|
-
imgCache.put(url, new Response(convertedBlob))
|
|
64
|
-
} catch (cacheError) {
|
|
65
|
-
console.warn('Failed to cache the image:', cacheError)
|
|
66
|
-
}
|
|
77
|
+
try {
|
|
78
|
+
const ext = url.split('.').pop()?.toLowerCase().split('?')[0]
|
|
79
|
+
|
|
80
|
+
if (ext === 'heic') {
|
|
81
|
+
const cachedSrc = await getCachedImage(url)
|
|
82
|
+
if (cachedSrc) {
|
|
83
|
+
imageSrc = cachedSrc
|
|
84
|
+
return
|
|
67
85
|
}
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
imageSrc = await convertHeicImage(url)
|
|
87
|
+
} else {
|
|
88
|
+
imageSrc = url
|
|
70
89
|
}
|
|
71
|
-
}
|
|
72
|
-
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Image loading error:', error)
|
|
92
|
+
loadingError = true
|
|
93
|
+
imageSrc = null
|
|
73
94
|
}
|
|
74
95
|
}
|
|
75
|
-
|
|
96
|
+
|
|
97
|
+
watch(() => [props.src, props.pathKey], loadImage, { immediate: true })
|
|
76
98
|
</script>
|
|
77
99
|
|
|
78
100
|
<template>
|
|
79
101
|
<figcaption v-if="caption">
|
|
80
|
-
<img
|
|
102
|
+
<img
|
|
103
|
+
v-if="imageSrc"
|
|
104
|
+
:src="imageSrc"
|
|
105
|
+
v-bind="$attrs"
|
|
106
|
+
:alt="alt"
|
|
107
|
+
:width="normalizeDimension(width)"
|
|
108
|
+
:height="normalizeDimension(height)"
|
|
109
|
+
>
|
|
81
110
|
<Skeleton
|
|
82
111
|
v-else
|
|
83
112
|
class="img-web-kit"
|
|
@@ -85,7 +114,25 @@ watch(() => [src, pathKey], loadImage, { immediate: true })
|
|
|
85
114
|
:height="normalizeDimension(height)"
|
|
86
115
|
/>
|
|
87
116
|
</figcaption>
|
|
88
|
-
|
|
117
|
+
|
|
118
|
+
<img
|
|
119
|
+
v-else-if="imageSrc"
|
|
120
|
+
:src="imageSrc"
|
|
121
|
+
v-bind="$attrs"
|
|
122
|
+
:alt="alt"
|
|
123
|
+
:width="normalizeDimension(width)"
|
|
124
|
+
:height="normalizeDimension(height)"
|
|
125
|
+
>
|
|
126
|
+
<div
|
|
127
|
+
v-else-if="loadingError"
|
|
128
|
+
class="flex-center error-image"
|
|
129
|
+
:style="{
|
|
130
|
+
width: normalizeDimension(width),
|
|
131
|
+
height: normalizeDimension(height),
|
|
132
|
+
}"
|
|
133
|
+
>
|
|
134
|
+
<Icon name="broken_image" />
|
|
135
|
+
</div>
|
|
89
136
|
<Skeleton
|
|
90
137
|
v-else
|
|
91
138
|
class="img-web-kit"
|
|
@@ -101,4 +148,7 @@ watch(() => [src, pathKey], loadImage, { immediate: true })
|
|
|
101
148
|
border: 0;
|
|
102
149
|
width: 100%;
|
|
103
150
|
}
|
|
151
|
+
.error-image {
|
|
152
|
+
background-color: var(--skeleton-bg);
|
|
153
|
+
}
|
|
104
154
|
</style>
|
|
@@ -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>
|
|
@@ -35,6 +35,7 @@ function runAction(name: ToolbarConfigOption, value?: string) {
|
|
|
35
35
|
v-else-if="action.name !== 'separator'" v-tooltip="action.label" :icon="action.icon" thin flat
|
|
36
36
|
:aria-label="action.name" :class="[action.class, { active: selectedStyles.has(action.name) }]"
|
|
37
37
|
class=""
|
|
38
|
+
tabindex="-1"
|
|
38
39
|
@click="runAction(action.name)"
|
|
39
40
|
/>
|
|
40
41
|
<span v-else-if="action.name === 'separator'" :key="`separator-${index}`" class="opacity-2 mb-025">|</span>
|