@bagelink/vue 1.4.136 → 1.4.141

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 (36) hide show
  1. package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
  2. package/dist/components/form/inputs/RichText/composables/useCommands.d.ts.map +1 -1
  3. package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -1
  4. package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -1
  5. package/dist/components/form/inputs/RichText/config.d.ts.map +1 -1
  6. package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
  7. package/dist/components/form/inputs/RichText/richTextTypes.d.ts +1 -1
  8. package/dist/components/form/inputs/RichText/richTextTypes.d.ts.map +1 -1
  9. package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
  10. package/dist/components/form/inputs/RichText/utils/formatting.d.ts.map +1 -1
  11. package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -1
  12. package/dist/composables/useSchemaField.d.ts.map +1 -1
  13. package/dist/index.cjs +10 -10
  14. package/dist/index.mjs +10 -10
  15. package/dist/style.css +1 -1
  16. package/dist/types/BagelForm.d.ts +13 -5
  17. package/dist/types/BagelForm.d.ts.map +1 -1
  18. package/dist/utils/BagelFormUtils.d.ts +28 -6
  19. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/dataTable/DataTable.vue +1 -1
  22. package/src/components/form/inputs/RadioGroup.vue +4 -4
  23. package/src/components/form/inputs/RichText/components/EditorToolbar.vue +14 -0
  24. package/src/components/form/inputs/RichText/composables/useCommands.ts +42 -0
  25. package/src/components/form/inputs/RichText/composables/useEditor.ts +8 -5
  26. package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +2 -128
  27. package/src/components/form/inputs/RichText/config.ts +18 -4
  28. package/src/components/form/inputs/RichText/index.vue +275 -73
  29. package/src/components/form/inputs/RichText/richTextTypes.ts +5 -0
  30. package/src/components/form/inputs/RichText/utils/commands.ts +614 -82
  31. package/src/components/form/inputs/RichText/utils/formatting.ts +17 -15
  32. package/src/components/form/inputs/RichText/utils/selection.ts +32 -11
  33. package/src/composables/useSchemaField.ts +31 -17
  34. package/src/types/BagelForm.ts +26 -12
  35. package/src/utils/BagelFormUtils.ts +97 -7
  36. package/src/utils/index.ts +1 -1
@@ -19,30 +19,32 @@ export function formatting(state: EditorState) {
19
19
  // Don't apply inline styles directly to block elements
20
20
  if (parentBlock?.tagName.match(/^H[1-6]|P|BLOCKQUOTE|LI$/)) {
21
21
  if (!range.collapsed && range.toString().trim()) {
22
- const span = doc.createElement('span') as HTMLSpanElement
23
- if (command === 'underline') span.style.textDecoration = 'underline'
24
- else if (command === 'bold') span.style.fontWeight = 'bold'
25
- else if (command === 'italic') span.style.fontStyle = 'italic'
26
-
27
- if (isRTL) span.dir = 'rtl'
28
- range.surroundContents(span)
22
+ let element: HTMLElement
23
+ if (command === 'underline') element = doc.createElement('u')
24
+ else if (command === 'bold') element = doc.createElement('b')
25
+ else if (command === 'italic') element = doc.createElement('i')
26
+ else return
27
+
28
+ if (isRTL) element.dir = 'rtl'
29
+ range.surroundContents(element)
29
30
  }
30
31
  } else {
31
32
  if (range.collapsed) return // No selection, nothing to format
32
33
 
33
- const span = doc.createElement('span')
34
- if (command === 'bold') span.style.fontWeight = 'bold'
35
- else if (command === 'italic') span.style.fontStyle = 'italic'
36
- else if (command === 'underline') span.style.textDecoration = 'underline'
34
+ let element: HTMLElement
35
+ if (command === 'bold') element = doc.createElement('b')
36
+ else if (command === 'italic') element = doc.createElement('i')
37
+ else if (command === 'underline') element = doc.createElement('u')
38
+ else return
37
39
 
38
40
  try {
39
- range.surroundContents(span)
40
- } catch (e) {
41
+ range.surroundContents(element)
42
+ } catch {
41
43
  // If surroundContents fails (e.g., for selections across multiple nodes)
42
44
  // Extract the fragment, wrap it, and insert it back
43
45
  const fragment = range.extractContents()
44
- span.appendChild(fragment)
45
- range.insertNode(span)
46
+ element.appendChild(fragment)
47
+ range.insertNode(element)
46
48
  }
47
49
  }
48
50
  }
@@ -25,26 +25,23 @@ export function isStyleActive(style: string, doc: Document) {
25
25
 
26
26
  // Define style checkers for different formatting types
27
27
  const styleCheckers: { [key: string]: (el: Element) => boolean } = {
28
- // Text formatting - check for elements or inline styles
28
+ // Text formatting - check for elements only, not CSS styles
29
29
  bold: (el) => {
30
30
  const tagName = el.tagName?.toLowerCase()
31
- if (tagName === 'strong' || tagName === 'b') return true
32
- const styles = window.getComputedStyle(el)
33
- return styles.fontWeight === 'bold' || styles.fontWeight === '700'
31
+ // Only consider <b> and <strong> tags, not CSS bold styling
32
+ return tagName === 'strong' || tagName === 'b'
34
33
  },
35
34
 
36
35
  italic: (el) => {
37
36
  const tagName = el.tagName?.toLowerCase()
38
- if (tagName === 'em' || tagName === 'i') return true
39
- const styles = window.getComputedStyle(el)
40
- return styles.fontStyle === 'italic'
37
+ // Only consider <i> and <em> tags, not CSS italic styling
38
+ return tagName === 'em' || tagName === 'i'
41
39
  },
42
40
 
43
41
  underline: (el) => {
44
42
  const tagName = el.tagName?.toLowerCase()
45
- if (tagName === 'u') return true
46
- const styles = window.getComputedStyle(el)
47
- return styles.textDecoration.includes('underline')
43
+ // Only consider <u> tag, not CSS underline styling
44
+ return tagName === 'u'
48
45
  },
49
46
 
50
47
  // Block elements
@@ -66,6 +63,30 @@ export function isStyleActive(style: string, doc: Document) {
66
63
  unorderedList: (el) => {
67
64
  // Check if we're inside an unordered list
68
65
  return !!el.closest('ul')
66
+ },
67
+
68
+ // Text alignment
69
+ alignLeft: (el) => {
70
+ const paragraph = el.closest('p, h1, h2, h3, h4, h5, h6')
71
+ return (paragraph as HTMLElement)?.style.textAlign === 'left'
72
+ },
73
+ alignCenter: (el) => {
74
+ const paragraph = el.closest('p, h1, h2, h3, h4, h5, h6')
75
+ return (paragraph as HTMLElement)?.style.textAlign === 'center'
76
+ },
77
+ alignRight: (el) => {
78
+ const paragraph = el.closest('p, h1, h2, h3, h4, h5, h6')
79
+ return (paragraph as HTMLElement)?.style.textAlign === 'right'
80
+ },
81
+ alignJustify: (el) => {
82
+ const paragraph = el.closest('p, h1, h2, h3, h4, h5, h6')
83
+ return (paragraph as HTMLElement)?.style.textAlign === 'justify'
84
+ },
85
+
86
+ // Text direction
87
+ textDirection: (el) => {
88
+ const paragraph = el.closest('p, h1, h2, h3, h4, h5, h6')
89
+ return (paragraph as HTMLElement)?.dir === 'rtl'
69
90
  }
70
91
  }
71
92
 
@@ -141,7 +162,7 @@ export function restoreSelection(
141
162
  try {
142
163
  range.setStart(info.originalStart, info.originalStartOffset)
143
164
  range.setEnd(info.originalEnd, info.originalEndOffset)
144
- } catch (e) {
165
+ } catch {
145
166
  if (fallbackNode) {
146
167
  range.selectNodeContents(fallbackNode)
147
168
  }
@@ -19,7 +19,8 @@ import {
19
19
  TelInput,
20
20
  ColorInput,
21
21
  RangeInput,
22
- EmailInput
22
+ EmailInput,
23
+ getNestedValue
23
24
  } from '@bagelink/vue'
24
25
  import { h, isVNode } from 'vue'
25
26
 
@@ -93,7 +94,9 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
93
94
  field.attrs = { ...field.attrs, multiline: true }
94
95
  }
95
96
 
96
- return typeof field.$el === 'object' ? field.$el : componentMap[field.$el as keyof typeof componentMap] ?? field.$el ?? 'div'
97
+ return typeof field.$el === 'object'
98
+ ? field.$el
99
+ : (componentMap[field.$el as keyof typeof componentMap] ?? field.$el ?? 'div')
97
100
  }
98
101
 
99
102
  function renderChild(child: SchemaChild<T, Path<T>>, slots?: BaseBagelField<T, Path<T>>['slots']) {
@@ -122,7 +125,7 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
122
125
  const vIfCurrentValue = field.id
123
126
  ? ('get' in (rowData || {})
124
127
  ? (rowData as any)?.get(field.id)
125
- : (rowData as any)?.[field.id as keyof T])
128
+ : getNestedValue(rowData, field.id as string))
126
129
  : undefined
127
130
 
128
131
  const vIfResult = field.id
@@ -132,7 +135,7 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
132
135
  return
133
136
  }
134
137
  } else if (typeof condition === 'string') {
135
- if (!(rowData as any)?.[condition]) {
138
+ if (!getNestedValue(rowData, condition)) {
136
139
  return
137
140
  }
138
141
  } else if (!condition) {
@@ -143,8 +146,6 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
143
146
  const {
144
147
  $el: _$el,
145
148
  children,
146
- options: _options,
147
- attrs: _attrs,
148
149
  class: fieldClass,
149
150
  id,
150
151
  transform,
@@ -158,11 +159,11 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
158
159
  ...fieldProps
159
160
  } = field
160
161
 
161
- // Use the get method if available, otherwise fall back to direct access
162
+ // Use the get method if available, otherwise fall back to nested value access
162
163
  const currentValue = field.id
163
164
  ? ('get' in (rowData || {})
164
165
  ? (rowData as any)?.get(field.id)
165
- : (rowData as any)?.[field.id as keyof T])
166
+ : getNestedValue(rowData, field.id as string))
166
167
  : undefined
167
168
 
168
169
  // Apply transform with conditional args: provide (val,row) only when id exists; otherwise provide only (row)
@@ -195,7 +196,7 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
195
196
  // Wire top-level onClick with conditional args
196
197
  if (typeof (field as any).onClick === 'function') {
197
198
  const original = (field as any).onClick as (val?: any, row?: T) => void
198
- props.onClick = (..._args: any[]) => {
199
+ props.onClick = () => {
199
200
  if (id) {
200
201
  original(currentValue, rowData)
201
202
  } else {
@@ -222,7 +223,11 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
222
223
  }
223
224
 
224
225
  // Remove undefined props to avoid vue warnings
225
- Object.keys(props).forEach(key => props[key] === undefined && delete props[key])
226
+ Object.keys(props).forEach((key) => {
227
+ if (props[key] === undefined) {
228
+ delete props[key]
229
+ }
230
+ })
226
231
 
227
232
  // Add options if they exist in the field
228
233
  if (field.options) {
@@ -272,10 +277,13 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
272
277
  if (field.attrs) {
273
278
  const boundAttrs = bindAttrs(field.attrs, currentValue, rowData)
274
279
  Object.entries(boundAttrs).forEach(([key, value]) => {
280
+ // Skip $el as it's not a DOM attribute
281
+ if (key === '$el') return
282
+
275
283
  if (typeof value === 'function') {
276
284
  if (key === 'onClick') {
277
285
  const original = value as (val?: any, row?: T) => void
278
- props.onClick = (..._args: any[]) => {
286
+ props.onClick = () => {
279
287
  if (id) {
280
288
  original(currentValue, rowData)
281
289
  } else {
@@ -301,7 +309,7 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
301
309
  const componentSlots: Parameters<typeof h>[1] = {}
302
310
 
303
311
  // Add default slot if there are children
304
- if (children?.length) {
312
+ if (children && children.length > 0) {
305
313
  componentSlots.default = () => children
306
314
  .map(child => renderChild(child, slots))
307
315
  .filter(Boolean) // Filter out null results from vIf
@@ -309,7 +317,7 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
309
317
 
310
318
  // For slot value components, add the transformed value as default slot content
311
319
  if (isSlotValueComponent && transformedValue !== undefined) {
312
- componentSlots.default = () => transformedValue?.toString() || ''
320
+ componentSlots.default = () => String(transformedValue ?? '')
313
321
  }
314
322
 
315
323
  // Handle custom slots from the field
@@ -332,20 +340,24 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
332
340
  return renderField(schemaField as BaseBagelField<T, Path<T>>, slots)
333
341
  })
334
342
  }
343
+ return []
335
344
  }
336
345
  })
337
346
  }
338
347
 
339
348
  // Handle custom slot content from parent
340
349
 
341
- const slotContent = field.id ? (slots?.[field.id] as VNodeFn<T, Path<T>> | undefined)?.({ row: rowData, field }) : undefined
350
+ const slotContent = field.id
351
+ ? (slots?.[field.id] as VNodeFn<T, Path<T>> | undefined)?.({ row: rowData, field })
352
+ : undefined
342
353
  // field.id && slots?.[field.id] && typeof slots[field.id] === 'function' && !Array.isArray(slots?.[field.id])
343
354
  // ? (slots[field.id])({ row: rowData, field })
344
355
  // : undefined
345
356
 
346
357
  if (mode === 'preview') {
347
358
  // Skip rendering if value is unset and includeUnset is false
348
- if (!includeUnset && (transformedValue === undefined || transformedValue === null || transformedValue.length === 0)) {
359
+ if (!includeUnset && (transformedValue === undefined || transformedValue === null
360
+ || (typeof transformedValue === 'string' && transformedValue.length === 0))) {
349
361
  return
350
362
  }
351
363
 
@@ -355,8 +367,10 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
355
367
  slotContent || (typeof field.$el === 'object'
356
368
  ? h(Component as any, props, componentSlots)
357
369
  : typeof transformedValue === 'object' && transformedValue !== null
358
- ? h('pre', { style: 'margin: 0; white-space: pre-wrap; font-family: inherit; font-size: inherit;' }, renderObject(transformedValue))
359
- : transformedValue?.toString() || '')
370
+ ? h('pre', {
371
+ style: 'margin: 0; white-space: pre-wrap; font-family: inherit; font-size: inherit;'
372
+ }, renderObject(transformedValue))
373
+ : String(transformedValue ?? ''))
360
374
  ])
361
375
  ])
362
376
  }
@@ -67,20 +67,29 @@ export type OpenEndedPath<T> =
67
67
  : never
68
68
  : never
69
69
 
70
+ // Helper type to check if a type has ONLY index signature (no specific keys)
71
+ type HasOnlyIndexSignature<T> = T extends Record<string, any>
72
+ ? string extends keyof T
73
+ ? Record<string, never> extends Pick<T, Exclude<keyof T, string | number>>
74
+ ? true // Only index signature, no specific keys
75
+ : false // Has specific keys
76
+ : false
77
+ : false
78
+
79
+ // Helper type to get paths for index signature properties
80
+ type IndexSignaturePaths<T> = {
81
+ [K in keyof T]: T[K] extends { [key: string]: any }
82
+ ? T[K] extends { [key: string]: infer V }
83
+ ? `${K & string}.${string}`
84
+ : never
85
+ : never
86
+ }[keyof T]
87
+
70
88
  // Enhanced Path type that allows flexibility for nested open-ended objects
71
89
  export type Path<T, PO extends PathsOptions = DefaultPathsOptions> =
72
90
  FieldVal<T, _Path<T, PO>> extends Array<any>
73
91
  ? LiteralStringUnion<_Path<T, PO>>
74
- : _Path<T, PO> | (
75
- // Allow nested paths for properties that have index signatures
76
- keyof T extends infer K ?
77
- K extends keyof T ?
78
- T[K] extends { [key: string]: any } ?
79
- `${K & string}.${string}`
80
- : never
81
- : never
82
- : never
83
- )
92
+ : _Path<T, PO> | IndexSignaturePaths<T> | `${keyof T & string}.more_info.${string}`
84
93
 
85
94
  // Smart field value type that preserves type information when possible
86
95
  export type SmartFieldVal<T, P extends Path<T>> =
@@ -164,18 +173,23 @@ export interface ElementField<
164
173
  children?: ElementField<T, PO>[]
165
174
  }
166
175
 
176
+ // Helper type to extract all possible BaseBagelField types for valid paths
177
+ type ValidBaseBagelField<T, PO extends PathsOptions = DefaultPathsOptions> = {
178
+ [P in Path<T, PO>]: BaseBagelField<T, P, PO>
179
+ }[Path<T, PO>]
180
+
167
181
  export type SchemaChild<
168
182
  T,
169
183
  P extends Path<T, PO>,
170
184
  PO extends PathsOptions = DefaultPathsOptions,
171
- > = Field<T, PO> | ElementField<T, PO> | VNode | VNodeFn<T, P> | string | BaseBagelField<T, Path<T, PO>, PO>
185
+ > = Field<T, PO> | ElementField<T, PO> | VNode | VNodeFn<T, P> | string | ValidBaseBagelField<T, PO>
172
186
 
173
187
  export interface BaseBagelField<
174
188
  T,
175
189
  P extends Path<T, PO>,
176
190
  PO extends PathsOptions = DefaultPathsOptions,
177
191
  > {
178
- '$el'?: any
192
+ '$el'?: string | any
179
193
  'id'?: P
180
194
  'label'?: string
181
195
  'placeholder'?: string
@@ -12,11 +12,15 @@ import type {
12
12
  Attributes,
13
13
  BglFormSchemaT,
14
14
  FieldByP,
15
- SchemaChild,
16
15
  ShallowBglFormSchemaT,
17
16
  UploadInputProps
18
17
  } from '../types/BagelForm'
19
18
 
19
+ // Import ValidBaseBagelField from the types file
20
+ type ValidBaseBagelField<T, PO extends import('type-fest/source/paths').PathsOptions = import('type-fest/source/paths').DefaultPathsOptions> = {
21
+ [P in Path<T, PO>]: BaseBagelField<T, P, PO>
22
+ }[Path<T, PO>]
23
+
20
24
  // Local type definitions for internal use only
21
25
  interface IconType { name: string }
22
26
  interface AutoFillField { name: string }
@@ -70,6 +74,11 @@ export interface RichTextOptions<T, P extends Path<T>> extends InputOptions<T, P
70
74
  height?: number | string
71
75
  }
72
76
 
77
+ export interface TelInputOptions<T, P extends Path<T>> extends InputOptions<T, P> {
78
+ pattern?: string
79
+ autocomplete?: AutoFillField
80
+ }
81
+
73
82
  export function getBaseField<T, P extends Path<T, PO>, PO extends PathsOptions = DefaultPathsOptions>(
74
83
  id?: P,
75
84
  labelOrRest: string | Partial<BaseBagelField<T, P>> = {},
@@ -308,8 +317,8 @@ export function frmRow<
308
317
  T,
309
318
  PO extends PathsOptions = DefaultPathsOptions,
310
319
  >(
311
- ...children: SchemaChild<T, Path<T, PO>, PO>[]
312
- ): { $el: string, class: string, children: SchemaChild<T, Path<T, PO>, PO>[] } {
320
+ ...children: Array<BaseBagelField<T, any, PO>>
321
+ ): { $el: string, class: string, children: Array<BaseBagelField<T, any, PO>> } {
313
322
  return {
314
323
  $el: 'div',
315
324
  class: 'flex gap-1 m_block align-items-end',
@@ -406,16 +415,25 @@ export function telField<
406
415
  >(
407
416
  id?: P,
408
417
  label?: string,
409
- options?: { [key: string]: any }
418
+ options?: TelInputOptions<T, P>
410
419
  ): BaseBagelField<T, P, PO> {
411
420
  return {
412
421
  $el: 'tel',
413
422
  id,
414
423
  label,
415
- vIf: options?.vIf,
416
- attrs: options,
417
424
  class: options?.class,
425
+ required: options?.required,
426
+ placeholder: options?.placeholder,
427
+ helptext: options?.helptext,
428
+ disabled: options?.disabled,
429
+ defaultValue: options?.defaultValue,
430
+ vIf: options?.vIf,
418
431
  transform: options?.transform,
432
+ attrs: {
433
+ ...options?.attrs,
434
+ pattern: options?.pattern,
435
+ autocomplete: options?.autocomplete,
436
+ },
419
437
  }
420
438
  }
421
439
 
@@ -517,6 +535,77 @@ export function arrField<
517
535
  // })
518
536
  // }
519
537
 
538
+ // Schema builder function that provides type context
539
+ export function createSchema<T, PO extends PathsOptions = DefaultPathsOptions>() {
540
+ return {
541
+ txtField: <P extends Path<T, PO>>(
542
+ id?: P,
543
+ label?: string,
544
+ options?: TextInputOptions<T, P>
545
+ ) => txtField<T, P, PO>(id, label, options),
546
+
547
+ selectField: <P extends Path<T, PO>>(
548
+ id?: P,
549
+ label?: string,
550
+ options?: any,
551
+ fieldOptions?: SlctInputOptions<T, P>
552
+ ) => selectField<T, P, PO>(id, label, options, fieldOptions),
553
+
554
+ dateField: <P extends Path<T, PO>>(
555
+ id?: P,
556
+ label?: string,
557
+ options?: DateOptions<T, P>
558
+ ) => dateField<T, P, PO>(id, label, options),
559
+
560
+ telField: <P extends Path<T, PO>>(
561
+ id?: P,
562
+ label?: string,
563
+ options?: TelInputOptions<T, P>
564
+ ) => telField<T, P, PO>(id, label, options),
565
+
566
+ frmRow: (
567
+ ...children: Array<BaseBagelField<T, any, PO>>
568
+ ) => frmRow<T, PO>(...children),
569
+
570
+ // Add other field functions as needed
571
+ numField: <P extends Path<T, PO>>(
572
+ id?: P,
573
+ label?: string,
574
+ options?: NumFieldOptions<T, P>
575
+ ) => numField<T, P, PO>(id, label, options),
576
+
577
+ checkField: <P extends Path<T, PO>>(
578
+ id?: P,
579
+ label?: string,
580
+ options?: CheckInputOptions<T, P>
581
+ ) => checkField<T, P, PO>(id, label, options),
582
+
583
+ emailField: <P extends Path<T, PO>>(
584
+ id?: P,
585
+ label?: string,
586
+ options?: EmailInputOptions<T, P>
587
+ ) => emailField<T, P, PO>(id, label, options),
588
+
589
+ uploadField: <P extends Path<T, PO>>(
590
+ id?: P,
591
+ label?: string,
592
+ options?: UploadOptions<T, P>
593
+ ) => uploadField<T, P, PO>(id, label, options),
594
+
595
+ rangeField: <P extends Path<T, PO>>(
596
+ id?: P,
597
+ label?: string,
598
+ options?: RangeOptions<T, P>
599
+ ) => rangeField<T, P, PO>(id, label, options),
600
+
601
+ colorField: <P extends Path<T, PO>>(
602
+ id?: P,
603
+ label?: string,
604
+ options?: { [key: string]: any }
605
+ ) => colorField<T, P, PO>(id, label, options),
606
+ }
607
+ }
608
+
520
609
  export function useForm() {
521
610
  return {
522
611
  txtField,
@@ -534,6 +623,7 @@ export function useForm() {
534
623
  arrField,
535
624
  richText,
536
625
  findBglFieldById,
537
- getBaseField
626
+ getBaseField,
627
+ createSchema
538
628
  }
539
629
  }
@@ -62,7 +62,7 @@ export function bindAttrs<T, P extends Path<T>>(
62
62
  // TODO: Fix this so that you don't have to return a fn for other on* event handlers
63
63
  if (!attrs) return {}
64
64
 
65
- const exclude = ['class', 'onClick'] as const
65
+ const exclude = ['class', 'onClick', '$el'] as const
66
66
  const arr = Object.entries(attrs)
67
67
  .filter(([key]) => !exclude.includes(key as typeof exclude[number]))
68
68
  .map(([key, value]) => [