@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.
Files changed (66) hide show
  1. package/bin/experimentalGenTypedRoutes.ts +13 -2
  2. package/dist/components/Btn.vue.d.ts +1 -1
  3. package/dist/components/Btn.vue.d.ts.map +1 -1
  4. package/dist/components/DataPreview.vue.d.ts +16 -5
  5. package/dist/components/DataPreview.vue.d.ts.map +1 -1
  6. package/dist/components/Icon/Icon.vue.d.ts +4 -1
  7. package/dist/components/Icon/Icon.vue.d.ts.map +1 -1
  8. package/dist/components/ModalForm.vue.d.ts +2 -1
  9. package/dist/components/ModalForm.vue.d.ts.map +1 -1
  10. package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
  11. package/dist/components/dataTable/useSorting.d.ts +1 -1
  12. package/dist/components/dataTable/useSorting.d.ts.map +1 -1
  13. package/dist/components/dataTable/useTableData.d.ts +7 -6
  14. package/dist/components/dataTable/useTableData.d.ts.map +1 -1
  15. package/dist/components/dataTable/useTableVirtualization.d.ts.map +1 -1
  16. package/dist/components/form/BagelForm.vue.d.ts +5 -10
  17. package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
  18. package/dist/components/form/BglMultiStepForm.vue.d.ts +10 -6
  19. package/dist/components/form/BglMultiStepForm.vue.d.ts.map +1 -1
  20. package/dist/components/form/FieldArray.vue.d.ts +3 -2
  21. package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
  22. package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts +14 -6
  23. package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts.map +1 -1
  24. package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
  25. package/dist/composables/index.d.ts +5 -5
  26. package/dist/composables/index.d.ts.map +1 -1
  27. package/dist/composables/useSchemaField.d.ts +5 -12
  28. package/dist/composables/useSchemaField.d.ts.map +1 -1
  29. package/dist/index.cjs +298 -357
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.mjs +299 -358
  33. package/dist/plugins/modalTypes.d.ts +3 -2
  34. package/dist/plugins/modalTypes.d.ts.map +1 -1
  35. package/dist/style.css +165 -135
  36. package/dist/types/BagelForm.d.ts +14 -11
  37. package/dist/types/BagelForm.d.ts.map +1 -1
  38. package/dist/types/TableSchema.d.ts +9 -9
  39. package/dist/types/TableSchema.d.ts.map +1 -1
  40. package/dist/utils/BagelFormUtils.d.ts +4 -3
  41. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  42. package/dist/utils/index.d.ts.map +1 -1
  43. package/dist/utils/useSearch.d.ts +44 -0
  44. package/dist/utils/useSearch.d.ts.map +1 -0
  45. package/package.json +1 -1
  46. package/src/components/DataPreview.vue +16 -5
  47. package/src/components/Icon/Icon.vue +12 -3
  48. package/src/components/ModalForm.vue +6 -9
  49. package/src/components/dataTable/DataTable.vue +11 -14
  50. package/src/components/dataTable/useSorting.ts +1 -1
  51. package/src/components/dataTable/useTableData.ts +19 -42
  52. package/src/components/dataTable/useTableVirtualization.ts +4 -8
  53. package/src/components/form/BagelForm.vue +33 -97
  54. package/src/components/form/BglMultiStepForm.vue +52 -36
  55. package/src/components/form/FieldArray.vue +54 -45
  56. package/src/components/form/inputs/CodeEditor/Index.vue +160 -98
  57. package/src/components/form/inputs/RichText/index.vue +13 -12
  58. package/src/composables/index.ts +12 -13
  59. package/src/composables/useSchemaField.ts +37 -35
  60. package/src/index.ts +1 -1
  61. package/src/plugins/modalTypes.ts +3 -2
  62. package/src/types/BagelForm.ts +22 -14
  63. package/src/types/TableSchema.ts +9 -9
  64. package/src/utils/BagelFormUtils.ts +4 -3
  65. package/src/utils/index.ts +38 -13
  66. package/src/utils/{search.ts → useSearch.ts} +1 -2
@@ -7,10 +7,9 @@ declare global {
7
7
  }
8
8
  }
9
9
  import { appendStyle, appendScript } from '@bagelink/vue'
10
- import { nextTick, onMounted, watch } from 'vue'
10
+ import { onMounted, ref, computed, watch } from 'vue'
11
11
 
12
- // Props
13
- const { language, readonly = false, modelValue = '', autodetect, ignoreIllegals = true, label, height = '300px' } = defineProps<{
12
+ interface CodeEditorProps {
14
13
  language?: Language
15
14
  readonly?: boolean
16
15
  modelValue?: string
@@ -18,39 +17,50 @@ const { language, readonly = false, modelValue = '', autodetect, ignoreIllegals
18
17
  ignoreIllegals?: boolean
19
18
  label?: string
20
19
  height?: string
21
- }>()
20
+ }
21
+ // Props with default values
22
+ const props = withDefaults(defineProps<CodeEditorProps>(), {
23
+ language: 'html',
24
+ readonly: false,
25
+ modelValue: '',
26
+ autodetect: true,
27
+ ignoreIllegals: true,
28
+ label: '',
29
+ height: '240px'
30
+ })
22
31
 
23
32
  const emit = defineEmits(['update:modelValue'])
33
+ // State
34
+ const code = ref(props.modelValue || '')
35
+ const editorRef = ref<HTMLDivElement>()
36
+ const loaded = ref(false)
37
+ const hljs = ref<HilightJS | null>(null)
38
+ // Computed
39
+ const maxHeight = computed(() => {
40
+ const h = props.height ?? '240px'
41
+ return h.match(/^\d+$/) ? `${h}px` : h
42
+ })
24
43
 
25
- let hljs = $ref<HilightJS | null>(null)
44
+ const formattedCode = computed(() => {
45
+ if (!hljs.value) return escapeHtml(code.value)
26
46
 
27
- let elHeight = $ref(height)
28
- // State and refs
29
- let code = $ref('')
30
- const textarea = $ref<HTMLTextAreaElement>()
31
- let loaded = $ref(false)
47
+ try {
48
+ const lang = props.language || ''
32
49
 
33
- // Computed properties
34
- const cannotDetectLanguage = $computed(() => {
35
- const lang = language || ''
36
- return !(autodetect ?? !lang) && !hljs?.getLanguage(lang)
37
- })
50
+ if (lang && !props.autodetect && !hljs.value.getLanguage(lang)) {
51
+ console.warn(`The language "${lang}" is not available.`)
52
+ return escapeHtml(code.value)
53
+ }
38
54
 
39
- const className = $computed(() => {
40
- if (cannotDetectLanguage) return ''
41
- return `hljs ${language || ''}`
42
- })
55
+ const result = props.autodetect
56
+ ? hljs.value.highlightAuto(code.value)
57
+ : hljs.value.highlight(code.value, { language: lang, ignoreIllegals: props.ignoreIllegals })
43
58
 
44
- const highlightedCode = $computed(() => {
45
- if (cannotDetectLanguage) {
46
- console.warn(`The language "${language}" you specified could not be found.`)
47
- return escapeHtml(code)
59
+ return result.value || escapeHtml(code.value)
60
+ } catch (error) {
61
+ console.error('Highlighting error:', error)
62
+ return escapeHtml(code.value)
48
63
  }
49
- const lang = language || ''
50
- const result = autodetect
51
- ? hljs?.highlightAuto(code)
52
- : hljs?.highlight(code, { language: lang, ignoreIllegals })
53
- return result?.value || ''
54
64
  })
55
65
 
56
66
  // Methods
@@ -67,113 +77,165 @@ function escapeHtml(unsafe: string) {
67
77
  })
68
78
  }
69
79
 
80
+ function handleInput(e: Event) {
81
+ const target = e.target as HTMLTextAreaElement
82
+ code.value = target.value
83
+ emit('update:modelValue', code.value)
84
+ }
85
+
70
86
  function handleTab(event: KeyboardEvent) {
87
+ if (event.key !== 'Tab') return
88
+
89
+ event.preventDefault()
71
90
  const target = event.target as HTMLTextAreaElement
72
91
  const start = target.selectionStart
73
- const tab = ' '
74
- code = code.slice(0, start) + tab + code.slice(start)
75
- nextTick(() => {
76
- target.selectionStart = target.selectionEnd = start + tab.length
77
- })
78
- }
92
+ const end = target.selectionEnd
79
93
 
80
- function adjustHeight() {
81
- if (textarea?.scrollHeight && textarea.scrollHeight > Number.parseInt(elHeight)) {
82
- elHeight = `${textarea.scrollHeight}px`
83
- }
94
+ // Add tab or indent selected text
95
+ const newValue = `${code.value.substring(0, start)} ${code.value.substring(end)}`
96
+ code.value = newValue
97
+ emit('update:modelValue', code.value)
98
+
99
+ // Move cursor position after the inserted tab
100
+ setTimeout(() => {
101
+ target.selectionStart = target.selectionEnd = start + 2
102
+ }, 0)
84
103
  }
85
104
 
86
105
  // Lifecycle
87
106
  onMounted(async () => {
88
- // Append scripts and styles for Highlight.js
89
- await appendScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/highlight.min.js', { id: 'hljs-cdn' })
90
- await appendStyle('https://cdn.jsdelivr.net/npm/highlight.js/styles/atom-one-dark.min.css')
91
-
92
- // Initialize hljs
93
- if (window.hljs) {
94
- hljs = window.hljs as HilightJS
95
- loaded = true
96
- } else {
97
- console.error('Highlight.js failed to load.')
107
+ try {
108
+ // Load highlight.js
109
+ await appendScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/highlight.min.js', { id: 'hljs-cdn' })
110
+ await appendStyle('https://cdn.jsdelivr.net/npm/highlight.js/styles/atom-one-dark.min.css')
111
+
112
+ if (window.hljs) {
113
+ hljs.value = window.hljs
114
+ loaded.value = true
115
+ } else {
116
+ console.error('Failed to load highlight.js')
117
+ }
118
+ } catch (error) {
119
+ console.error('Error loading highlight.js:', error)
98
120
  }
99
121
  })
100
122
 
101
- watch(() => modelValue, (newVal) => {
102
- adjustHeight()
103
- if (newVal !== code) {
104
- code = newVal
123
+ // Watch for external modelValue changes
124
+ watch(() => props.modelValue, (newVal) => {
125
+ if (newVal !== undefined && newVal !== code.value) {
126
+ code.value = newVal
105
127
  }
106
128
  }, { immediate: true })
107
129
  </script>
108
130
 
109
131
  <template>
110
- <div class="mb-05">
111
- <label v-if="label" class="label txt-start">{{ label }}</label>
112
- <div v-if="loaded" class="code-editor-wrap grid rounded p-1 overflow hm-300px ltr txt-start relative h-100p">
113
- <div class="relative block h-100" :style="{ height: `calc(${elHeight} - 2rem)` }">
114
- <pre class=" overflow-hidden absolute inset-0 p-0 m-0 h-100 codeText">
115
- <code class="absolute inset-0" :class="className" v-html="highlightedCode" />
116
- </pre>
132
+ <div class="code-editor-container ltr" :style="{ maxHeight }">
133
+ <label v-if="label" class="label">{{ label }}</label>
134
+ <div
135
+ v-if="loaded"
136
+ ref="editorRef"
137
+ class="code-editor-grandpa"
138
+ >
139
+ <div class="editor-content-papa relative">
140
+ <pre class="code-display" wrap><code v-html="formattedCode" /></pre>
117
141
  <textarea
118
142
  v-if="!readonly"
119
- ref="textarea"
120
- v-model="code"
121
- class="code-editor absolute inset-0 bg-transparent overflow-hidden h-100 p-0 m-0 codeText border-none txt-start"
143
+ :value="code"
144
+ class="code-input"
122
145
  spellcheck="false"
123
- placeholder="Write your code here"
124
- aria-label="Code Editor"
125
- data-gramm="false"
126
- @keydown.tab.prevent="handleTab"
127
- @input="emit('update:modelValue', code)"
146
+ autocomplete="off"
147
+ autocorrect="off"
148
+ autocapitalize="off"
149
+ @input="handleInput"
150
+ @keydown="handleTab"
128
151
  />
129
152
  </div>
130
153
  </div>
131
154
  </div>
132
155
  </template>
133
156
 
134
- <style>
135
- pre code.hljs{
136
- padding: 0 !important;
137
- inset: 0 !important;
138
- position: absolute;
157
+ <style scoped>
158
+ .code-editor-container {
159
+ margin-bottom: 0.5rem;
160
+ height: 100%;
139
161
  }
140
- </style>
141
162
 
142
- <style scoped>
143
- .codeText{
144
- font-family: monospace;
145
- white-space: pre-wrap;
146
- word-wrap: break-word;
147
- caret-color: var(--bgl-white);
148
- color: var(--bgl-white);
163
+ .label {
164
+ display: block;
165
+ text-align: left;
166
+ margin-bottom: 0.25rem;
149
167
  }
150
- .code-editor-wrap {
151
- background: #282c34;
152
- height: max-content;
168
+
169
+ .code-editor-grandpa {
170
+ background: #22252A;
171
+ border-radius: 0.25rem;
172
+ width: 100%;
173
+ height: 100%;
174
+ overflow: auto;
175
+ padding: 1ch;
176
+ padding-inline-start: 2ch;
153
177
  }
154
- .code-editor-wrap:focus-within, .code-editor-wrap:focus-visible, .code-editor-wrap:focus {
155
- box-shadow: inset 0 0 10px #00000021;
156
- outline: solid 1px var(--border-color);
157
- /* outline: -webkit-focus-ring-color auto 1px; */
158
178
 
179
+ .code-editor-grandpa:focus-within {
180
+ outline: solid 1px var(--border-color, #4f575f);
181
+ box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.13);
159
182
  }
160
183
 
161
- .code-editor-wrap:focus-within:has(textarea:focus) + .label,
162
- .label:has(+ .code-editor-wrap:focus-within) {
163
- color: var(--bgl-primary) !important;
184
+ .editor-content-papa {
185
+ position: relative;
186
+ width: 100%;
187
+ padding-bottom: calc(100% - 5lh);
188
+ }
189
+ .code-display,
190
+ .code-input {
191
+ inset: 0;
192
+ margin: 0;
193
+ padding: 0;
194
+ width: 100%;
195
+ height: 100%;
196
+ overflow: auto;
197
+ font-family: monospace;
198
+ font-size: 1em;
199
+ line-height: 1.5;
200
+ tab-size: 2;
201
+ word-break: keep-all;
202
+ text-align: left;
164
203
  }
165
204
 
166
- .code-editor {
167
- color: transparent;
168
- resize: none;
205
+ .code-display {
206
+ position: relative;
207
+ color: #fff;
208
+ pointer-events: none;
209
+ z-index: 1;
169
210
  }
170
211
 
171
- .code-editor::selection {
172
- background: #2466bc30;
173
- color: inherit;
212
+ .code-display code {
213
+ display: block;
214
+ background: transparent !important;
215
+ padding: 0 !important;
174
216
  }
175
217
 
176
- .code-editor:focus {
177
- outline: none;
218
+ .code-input {
219
+ position: absolute;
220
+ background: transparent;
221
+ color: transparent;
222
+ caret-color: #fff;
223
+ border: none;
224
+ resize: none;
225
+ outline: none;
226
+ z-index: 2;
227
+ }
228
+
229
+ .code-input::selection {
230
+ background-color: rgba(36, 102, 188, 0.3);
231
+ color: transparent;
232
+ }
233
+ </style>
234
+
235
+ <style>
236
+ /* Global styles */
237
+ pre code.hljs {
238
+ padding: 0 !important;
239
+ background: transparent !important;
178
240
  }
179
241
  </style>
@@ -15,6 +15,9 @@ const editor = useEditor()
15
15
  const isInitializing = ref(false)
16
16
  const hasInitialized = ref(false)
17
17
 
18
+ // Initialize content from modelValue
19
+ editor.state.content = props.modelValue
20
+
18
21
  // Initialize debugger if debug mode is enabled
19
22
  if (props.debug) {
20
23
  editor.initDebugger()
@@ -83,6 +86,9 @@ async function initEditor() {
83
86
  // Set default direction based on content
84
87
  doc.body.dir = hasRTL ? 'rtl' : 'ltr'
85
88
 
89
+ // Ensure editor.state.content is set to the current HTML content
90
+ editor.state.content = doc.body.innerHTML
91
+
86
92
  editor.init(doc)
87
93
  useEditorKeyboard(doc, commands)
88
94
 
@@ -92,6 +98,8 @@ async function initEditor() {
92
98
  p.dir = doc.body.dir
93
99
  p.innerHTML = '<br>'
94
100
  doc.body.appendChild(p)
101
+ // Update state.content after changes
102
+ editor.state.content = doc.body.innerHTML
95
103
  } else {
96
104
  // Convert any direct text nodes to paragraphs
97
105
  const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT)
@@ -112,6 +120,8 @@ async function initEditor() {
112
120
  doc.body.removeChild(textNode)
113
121
  }
114
122
  })
123
+ // Update state.content after cleanup
124
+ editor.state.content = doc.body.innerHTML
115
125
  }
116
126
 
117
127
  doc.body.focus()
@@ -137,7 +147,7 @@ watch(() => props.modelValue, (newValue, oldValue) => {
137
147
  })
138
148
 
139
149
  watch(() => editor.state.content, (newValue) => {
140
- if (editor.state.doc?.body.innerHTML) {
150
+ if (editor.state.doc?.body) {
141
151
  editor.state.doc.body.dir = hasRTL ? 'rtl' : 'ltr'
142
152
  }
143
153
  emit('update:modelValue', newValue)
@@ -168,7 +178,7 @@ watch(() => editor.state.content, (newValue) => {
168
178
  v-if="editor.state.isSplitView"
169
179
  v-model="editor.state.content"
170
180
  language="html"
171
- class="code-editor"
181
+ :height="editor.state.isFullscreen ? 'calc(100vh - 4rem)' : '250px'"
172
182
  @update:modelValue="editor.updateState.content('html')"
173
183
  />
174
184
  </div>
@@ -196,12 +206,6 @@ watch(() => editor.state.content, (newValue) => {
196
206
  .content-area li{
197
207
  line-height: 1.65;
198
208
  }
199
-
200
- .code-editor {
201
- flex: 1;
202
- min-height: 240px !important;
203
- height: 100%;
204
- }
205
209
  </style>
206
210
 
207
211
  <style scoped>
@@ -213,7 +217,7 @@ watch(() => editor.state.content, (newValue) => {
213
217
 
214
218
  .editor-container {
215
219
  display: flex;
216
- gap: 1rem;
220
+ gap: 0.5rem;
217
221
  }
218
222
 
219
223
  .content-area,
@@ -274,9 +278,6 @@ watch(() => editor.state.content, (newValue) => {
274
278
  height: 100%;
275
279
  overflow-y: auto;
276
280
  }
277
- .fullscreen-mode .code-editor{
278
- height: 100% !important;
279
- }
280
281
 
281
282
  .debug-controls {
282
283
  display: flex;
@@ -1,33 +1,32 @@
1
- import type { BglFormSchemaFnT, BglFormSchemaT, IfAny } from '@bagelink/vue'
1
+ import type { BglFormSchemaT, IfAny } from '@bagelink/vue'
2
2
 
3
- import type { Ref, UnwrapRef } from 'vue'
3
+ import type { MaybeRefOrGetter, Ref, UnwrapRef } from 'vue'
4
4
  import { getFallbackSchema } from '@bagelink/vue'
5
- import { ref, watch } from 'vue'
5
+ import { ref, toValue, watch } from 'vue'
6
6
 
7
7
  export { useDevice } from './useDevice'
8
8
  export { usePolling } from './usePolling'
9
9
  export { useValidateFieldValue } from './useValidateFieldValue'
10
10
  interface UseBglSchemaParamsT<T> {
11
- schema?: BglFormSchemaFnT<T>
12
- columns?: string[]
13
- data?: any[]
11
+ schema?: MaybeRefOrGetter<BglFormSchemaT<T>>
12
+ columns?: MaybeRefOrGetter<string[]>
13
+ data?: T[]
14
14
  }
15
15
 
16
16
  export function useBglSchema<T = { [key: string]: unknown }>(
17
17
  { schema, columns, data }: UseBglSchemaParamsT<T> = {}
18
18
  ): BglFormSchemaT<T> {
19
- let _schema = schema
20
- if (typeof _schema === 'function') {
21
- _schema = _schema()
22
- }
19
+ const _schema = $computed(() => toValue(schema))
20
+ const _columns = $computed(() => toValue(columns))
21
+
23
22
  if (_schema) {
24
23
  return (
25
- columns && columns.length > 0
26
- ? _schema.filter(f => columns.includes(f.id as string))
24
+ _columns && _columns.length > 0
25
+ ? _schema.filter(f => _columns.includes(f.id as string))
27
26
  : _schema
28
27
  ) as BglFormSchemaT<T>
29
28
  }
30
- return getFallbackSchema(data, columns)
29
+ return getFallbackSchema(data, _columns)
31
30
  }
32
31
 
33
32
  export function localRef<T>(
@@ -1,5 +1,6 @@
1
1
  import type { VNode } from 'vue'
2
- import type { Field, BglFormSchemaT, SchemaChildrenT, Attributes, Path } from '../types/BagelForm'
2
+
3
+ import type { Field, Attributes, Path, SchemaChild, BaseBagelField, VNodeFn } from '../types/BagelForm'
3
4
  import {
4
5
  TextInput,
5
6
  NumberInput,
@@ -20,26 +21,20 @@ import {
20
21
  RangeInput,
21
22
  EmailInput
22
23
  } from '@bagelink/vue'
23
-
24
24
  import { h, isVNode } from 'vue'
25
25
 
26
26
  const SLOT_VALUE_COMPONENTS = new Set(['div', 'span', 'p'])
27
27
 
28
28
  const SRC_VALUE_COMPONENTS = new Set(['img', 'iframe'])
29
29
 
30
- export interface UseSchemaFieldOptions<T> {
30
+ export interface UseSchemaFieldOptions<T, SFP extends Path<T>> {
31
31
  mode?: 'form' | 'preview' | 'table'
32
32
  getFormData?: () => T
33
- onUpdateModelValue?: (field: Field<T>, value: any) => void
33
+ onUpdateModelValue?: (field: BaseBagelField<T, SFP>, value: any) => void
34
34
  includeUnset?: boolean
35
35
  }
36
36
 
37
- // Add type for supported child types
38
- interface SlotProps<T> { row?: T, field: Field<T> }
39
- type SlotFunction<T> = (props: SlotProps<T>) => any
40
- type SupportedSlot<T> = BglFormSchemaT<T> | VNode | SlotFunction<T>
41
-
42
- export function useSchemaField<T extends { [key: string]: any }, _P>(optns: UseSchemaFieldOptions<T>) {
37
+ export function useSchemaField<T extends { [key: string]: any }, SP extends Path<T>>(optns: UseSchemaFieldOptions<T, SP>) {
43
38
  const { mode = 'form', getFormData, onUpdateModelValue, includeUnset = false } = optns
44
39
 
45
40
  // Helper function to render objects recursively
@@ -101,21 +96,21 @@ export function useSchemaField<T extends { [key: string]: any }, _P>(optns: UseS
101
96
  return typeof field.$el === 'object' ? field.$el : componentMap[field.$el as keyof typeof componentMap] ?? field.$el ?? 'div'
102
97
  }
103
98
 
104
- function renderChild(child: SchemaChildrenT<T>[number], slots?: Record<string, SupportedSlot<T>>): any {
105
- if (typeof child === 'string') return child
99
+ function renderChild(child: SchemaChild<T, SP>, slots?: BaseBagelField<T, SP>['slots']) {
100
+ if (typeof child === 'string') return h(child)
106
101
  if (isVNode(child)) return child
107
102
  return renderField(
108
- child,
103
+ child as BaseBagelField<T, SP>,
109
104
  slots
110
105
  )
111
106
  }
112
107
 
113
108
  function renderField(
114
- field: Field<T>,
115
- slots?: Record<string, SupportedSlot<T>>
116
- ): VNode | null {
117
- const Component = getComponent(field)
118
- if (!Component) return null
109
+ field: BaseBagelField<T, SP>,
110
+ slots?: BaseBagelField<T, SP>['slots']
111
+ ): VNode | undefined {
112
+ const Component = getComponent(field as Field<T>)
113
+ if (!Component) return
119
114
 
120
115
  const rowData = (getFormData?.() || {}) as T | undefined
121
116
 
@@ -129,14 +124,14 @@ export function useSchemaField<T extends { [key: string]: any }, _P>(optns: UseS
129
124
  rowData
130
125
  )
131
126
  ) {
132
- return null
127
+ return
133
128
  }
134
129
  } else if (typeof condition === 'string') {
135
130
  if (!rowData?.[condition]) {
136
- return null
131
+ return
137
132
  }
138
133
  } else if (!condition) {
139
- return null
134
+ return
140
135
  }
141
136
  }
142
137
 
@@ -234,7 +229,8 @@ export function useSchemaField<T extends { [key: string]: any }, _P>(optns: UseS
234
229
  props.class = classify(currentValue, rowData, fieldClass, props.class)
235
230
 
236
231
  // Handle component slots with vIf aware child rendering
237
- const componentSlots: { [key: string]: any } = {}
232
+ // const componentSlots: { [name: string]: Slot } = {}
233
+ const componentSlots: Parameters<typeof h>[1] = {}
238
234
 
239
235
  // Add default slot if there are children
240
236
  if (children?.length) {
@@ -254,29 +250,35 @@ export function useSchemaField<T extends { [key: string]: any }, _P>(optns: UseS
254
250
  componentSlots[name] = () => {
255
251
  if (Array.isArray(slot)) {
256
252
  // Handle BglFormSchemaT array
257
- return slot.map(schemaField => renderField(schemaField, slots))
258
- } if (isVNode(slot)) {
259
- // Handle VNode
260
- return slot
261
- } if (typeof slot === 'function') {
262
- // Handle function slot
263
- const slotFn = slot as (props: SlotProps<T>) => any
264
- return slotFn({ row: rowData, field })
253
+ return slot.map((schemaField) => {
254
+ if (typeof schemaField === 'function') {
255
+ // Handle function slot
256
+ const slotFn = schemaField
257
+ return slotFn({ row: rowData, field })
258
+ }
259
+ if (isVNode(schemaField)) {
260
+ // Handle VNode
261
+ return schemaField
262
+ }
263
+
264
+ return renderField(schemaField as BaseBagelField<T, SP>, slots)
265
+ })
265
266
  }
266
- return slot
267
267
  }
268
268
  })
269
269
  }
270
270
 
271
271
  // Handle custom slot content from parent
272
- const slotContent = field.id && slots?.[field.id]
273
- ? (slots[field.id] as SlotFunction<T>)({ row: rowData, field })
274
- : undefined
272
+
273
+ const slotContent = field.id ? (slots?.[field.id] as VNodeFn<T, SP> | undefined)?.({ row: rowData, field }) : undefined
274
+ // field.id && slots?.[field.id] && typeof slots[field.id] === 'function' && !Array.isArray(slots?.[field.id])
275
+ // ? (slots[field.id])({ row: rowData, field })
276
+ // : undefined
275
277
 
276
278
  if (mode === 'preview') {
277
279
  // Skip rendering if value is unset and includeUnset is false
278
280
  if (!includeUnset && (transformedValue === undefined || transformedValue === null || transformedValue.length === 0)) {
279
- return null
281
+ return
280
282
  }
281
283
 
282
284
  return h('div', { class: 'preview-field' }, [
package/src/index.ts CHANGED
@@ -17,4 +17,4 @@ export * from './utils/calendar/dateUtils'
17
17
  import './styles/bagel.css'
18
18
 
19
19
  export * from './utils/constants'
20
- export * from './utils/search'
20
+ export * from './utils/useSearch'
@@ -1,4 +1,5 @@
1
- import type { BglFormSchemaFnT, BtnOptions, ThemeType } from '@bagelink/vue'
1
+ import type { BglFormSchemaT, BtnOptions, ThemeType } from '@bagelink/vue'
2
+ import type { MaybeRefOrGetter } from 'vue'
2
3
 
3
4
  export interface ModalOptions {
4
5
  title?: string
@@ -37,7 +38,7 @@ export interface ModalFormComponentProps<T extends { [key: string]: any }> exten
37
38
  }
38
39
 
39
40
  export interface ModalFormOptions<T extends { [key: string]: any }> {
40
- 'schema': BglFormSchemaFnT<T>
41
+ 'schema': MaybeRefOrGetter<BglFormSchemaT<T>>
41
42
  'modelValue'?: T
42
43
  'onUpdate:modelValue'?: (val: T) => void
43
44
  'onSubmit'?: (formData: T) => any