@bagelink/vue 0.0.1224 → 0.0.1232

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.
@@ -31,7 +31,7 @@ onMounted(() => {
31
31
  }
32
32
  })
33
33
 
34
- const formState = ref<'success' | 'error' | 'idle'>('idle')
34
+ const formState = ref<'success' | 'error' | 'idle' | 'submitting'>('idle')
35
35
 
36
36
  watch(() => props.modelValue, (newValue) => {
37
37
  if (newValue !== undefined) {
@@ -60,9 +60,13 @@ function updateFormData(fieldId: string, value: any) {
60
60
 
61
61
  async function handleSubmit() {
62
62
  try {
63
+ if (formState.value === 'submitting') return
64
+ formState.value = 'submitting'
63
65
  await props.onSubmit?.(formData.value)
64
66
  initialFormData.value = structuredClone(formData.value)
65
67
  formState.value = 'success'
68
+ // Notify parent window of successful submission
69
+ window.parent.postMessage({ type: 'BAGEL_FORM_SUCCESS', data: formData.value }, '*')
66
70
  } catch (error) {
67
71
  formState.value = 'error'
68
72
  }
@@ -98,7 +102,7 @@ defineExpose({ form, isDirty, validateForm })
98
102
  </template>
99
103
  </template>
100
104
  <slot v-else />
101
- <slot name="submit" :submit="handleSubmit" :isDirty="isDirty" :validateForm="validateForm" />
105
+ <slot name="submit" :submit="handleSubmit" :isDirty="isDirty" :validateForm="validateForm" :formState="formState" />
102
106
  <slot v-if="formState === 'success'" name="success" />
103
107
  <slot v-if="formState === 'error'" name="error" />
104
108
  </form>
@@ -100,13 +100,13 @@ defineExpose({ open, close })
100
100
  <Btn flat class="color-white" icon="add" :disabled="zoom === 3" @click="zoom++" />
101
101
  </div>
102
102
  <Btn
103
- v-if="currentItem?.openFile" class="color-white" round thin flat iconEnd="arrow_outward"
103
+ v-if="currentItem?.openFile && currentItem?.src" class="color-white" round thin flat iconEnd="arrow_outward"
104
104
  value="Open File"
105
105
  :href="currentItem?.src"
106
106
  target="_blank"
107
107
  />
108
108
  <Btn
109
- v-if="currentItem?.download" class="color-white" round thin flat icon="download"
109
+ v-if="currentItem?.download && currentItem?.src" class="color-white" round thin flat icon="download"
110
110
  value="Download File"
111
111
  :href="upgradeHeaders(currentItem?.src)"
112
112
  download
@@ -117,11 +117,11 @@ defineExpose({ open, close })
117
117
  <Carousel v-model:index="currentIndex" :items="1" class="bgl-lightbox-item" :class="{ zoomed: zoom > 1 }" :freeDrag="zoom === 1">
118
118
  <template v-for="item in group" :key="item.src">
119
119
  <Zoomer v-if="item.type === 'image'" v-model:zoom="zoom" :disabled="!item?.enableZoom" :mouse-wheel-to-zoom="false">
120
- <Image :draggable="false" :src="item?.src" alt="Preview" class="vw90 lightbox-image" />
120
+ <Image :draggable="false" :src="item?.src" :pathKey="item?.pathKey" alt="Preview" class="vw90 lightbox-image" />
121
121
  </Zoomer>
122
122
 
123
123
  <BglVideo
124
- v-else-if="item?.type === 'video'"
124
+ v-else-if="item?.type === 'video' && item?.src"
125
125
  :src="item?.src"
126
126
  autoplay
127
127
  controls
@@ -129,7 +129,7 @@ defineExpose({ open, close })
129
129
  />
130
130
 
131
131
  <embed
132
- v-else-if="item?.type === 'pdf'"
132
+ v-else-if="item?.type === 'pdf' && item?.src"
133
133
  :src="normalizeURL(item?.src)"
134
134
  type="application/pdf"
135
135
  width="100%"
@@ -1,5 +1,6 @@
1
- export interface LightboxItem {
2
- src: string
1
+ export type XORSrcPath = { src: string, pathKey?: never } | { src?: never, pathKey: string }
2
+
3
+ export type LightboxItem = XORSrcPath & {
3
4
  type: string
4
5
  name: string
5
6
  thumbnail?: string
@@ -1,5 +1,5 @@
1
1
  import type { VNode } from 'vue'
2
- import type { BaseBagelField } from '../types/BagelForm'
2
+ import type { BaseBagelField, BglFormSchemaT } from '../types/BagelForm'
3
3
  import {
4
4
  TextInput,
5
5
  NumberInput,
@@ -17,7 +17,7 @@ import {
17
17
  classify,
18
18
  keyToLabel
19
19
  } from '@bagelink/vue'
20
- import { h } from 'vue'
20
+ import { h, isVNode } from 'vue'
21
21
 
22
22
  const SLOT_VALUE_COMPONENTS = new Set(['div', 'span', 'p'])
23
23
 
@@ -30,6 +30,12 @@ export interface UseSchemaFieldOptions<T> {
30
30
  includeUnset?: boolean
31
31
  }
32
32
 
33
+ // Add type for supported child types
34
+ type SupportedChild<T> = BaseBagelField<T> | string | VNode
35
+ interface SlotProps<T> { row: T, field: BaseBagelField<T> }
36
+ type SlotFunction<T> = (props: SlotProps<T>) => any
37
+ type SupportedSlot<T> = BglFormSchemaT<T> | VNode | SlotFunction<T>
38
+
33
39
  export function useSchemaField<T extends { [key: string]: any }>(options: UseSchemaFieldOptions<T>) {
34
40
  const { mode = 'form', getRowData, onUpdate, includeUnset = false } = options
35
41
 
@@ -57,9 +63,15 @@ export function useSchemaField<T extends { [key: string]: any }>(options: UseSch
57
63
  return typeof field.$el === 'object' ? field.$el : componentMap[field.$el as keyof typeof componentMap] ?? field.$el ?? 'div'
58
64
  }
59
65
 
66
+ function renderChild(child: SupportedChild<T>, slots?: Record<string, SupportedSlot<T>>): any {
67
+ if (typeof child === 'string') return child
68
+ if (isVNode(child)) return child
69
+ return renderField(child, slots)
70
+ }
71
+
60
72
  function renderField(
61
73
  field: BaseBagelField<T>,
62
- slots?: Record<string, (props: { row: T, field: BaseBagelField<T> }) => any>
74
+ slots?: Record<string, SupportedSlot<T>>
63
75
  ): VNode | null {
64
76
  const Component = getComponent(field)
65
77
  if (!Component) return null
@@ -169,10 +181,7 @@ export function useSchemaField<T extends { [key: string]: any }>(options: UseSch
169
181
  // Add default slot if there are children
170
182
  if (children?.length) {
171
183
  componentSlots.default = () => children
172
- .map((child) => {
173
- if (typeof child === 'string') return child
174
- return renderField(child, slots)
175
- })
184
+ .map(child => renderChild(child, slots))
176
185
  .filter(Boolean) // Filter out null results from vIf
177
186
  }
178
187
 
@@ -181,18 +190,29 @@ export function useSchemaField<T extends { [key: string]: any }>(options: UseSch
181
190
  componentSlots.default = () => transformedValue?.toString() || ''
182
191
  }
183
192
 
184
- // Add any custom slots from the field
193
+ // Handle custom slots from the field
185
194
  if (fieldSlots) {
186
195
  Object.entries(fieldSlots).forEach(([name, slot]) => {
187
- componentSlots[name] = typeof slot === 'function'
188
- ? () => slot(currentValue, rowData)
189
- : () => slot
196
+ componentSlots[name] = () => {
197
+ if (Array.isArray(slot)) {
198
+ // Handle BglFormSchemaT array
199
+ return slot.map(schemaField => renderField(schemaField as BaseBagelField<T>, slots))
200
+ } else if (isVNode(slot)) {
201
+ // Handle VNode
202
+ return slot
203
+ } else if (typeof slot === 'function') {
204
+ // Handle function slot
205
+ const slotFn = slot as (props: SlotProps<T>) => any
206
+ return slotFn({ row: rowData, field })
207
+ }
208
+ return slot
209
+ }
190
210
  })
191
211
  }
192
212
 
193
213
  // Handle custom slot content from parent
194
214
  const slotContent = field.id && slots?.[field.id]
195
- ? slots[field.id]({ row: rowData, field })
215
+ ? (slots[field.id] as SlotFunction<T>)({ row: rowData, field })
196
216
  : undefined
197
217
 
198
218
  if (mode === 'preview') {
@@ -1,4 +1,5 @@
1
1
  import type { SelectInput, TextInput } from '@bagelink/vue'
2
+ import type { VNode } from 'vue'
2
3
 
3
4
  export type AttributeValue = string | number | boolean | undefined | undefined | { [key: string]: any }
4
5
 
@@ -29,7 +30,7 @@ export interface BaseBagelField<T = { [key: string]: any }> {
29
30
  'id'?: keyof T extends string ? keyof T : string
30
31
  'label'?: string
31
32
  'placeholder'?: string
32
- 'children'?: (Field<T> | string)[]
33
+ 'children'?: (Field<T> | string | VNode)[]
33
34
  'class'?: AttributeValue | AttributeFn<T>
34
35
  'attrs'?: Attributes<T>
35
36
  'required'?: boolean
@@ -235,7 +235,8 @@ export function findBglFieldById(id: string, _schema: BglFormSchemaT): Field | u
235
235
  for (const field of _schema) {
236
236
  if (field.id === id) return field
237
237
  if (field.children && Number(field.children.length) > 0) {
238
- const child = findBglFieldById(id, field.children.filter(c => typeof c !== 'string'))
238
+ const fieldChildren = field.children.filter((c): c is Field => typeof c === 'object' && '$el' in c)
239
+ const child = findBglFieldById(id, fieldChildren)
239
240
  if (child) return child
240
241
  }
241
242
  }