@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.
- package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useCommands.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/config.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/richTextTypes.d.ts +1 -1
- package/dist/components/form/inputs/RichText/richTextTypes.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/formatting.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +10 -10
- package/dist/index.mjs +10 -10
- package/dist/style.css +1 -1
- package/dist/types/BagelForm.d.ts +13 -5
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +28 -6
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/dataTable/DataTable.vue +1 -1
- package/src/components/form/inputs/RadioGroup.vue +4 -4
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +14 -0
- package/src/components/form/inputs/RichText/composables/useCommands.ts +42 -0
- package/src/components/form/inputs/RichText/composables/useEditor.ts +8 -5
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +2 -128
- package/src/components/form/inputs/RichText/config.ts +18 -4
- package/src/components/form/inputs/RichText/index.vue +275 -73
- package/src/components/form/inputs/RichText/richTextTypes.ts +5 -0
- package/src/components/form/inputs/RichText/utils/commands.ts +614 -82
- package/src/components/form/inputs/RichText/utils/formatting.ts +17 -15
- package/src/components/form/inputs/RichText/utils/selection.ts +32 -11
- package/src/composables/useSchemaField.ts +31 -17
- package/src/types/BagelForm.ts +26 -12
- package/src/utils/BagelFormUtils.ts +97 -7
- 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
|
-
|
|
23
|
-
if (command === 'underline')
|
|
24
|
-
else if (command === 'bold')
|
|
25
|
-
else if (command === 'italic')
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
34
|
-
if (command === 'bold')
|
|
35
|
-
else if (command === 'italic')
|
|
36
|
-
else if (command === '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(
|
|
40
|
-
} catch
|
|
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
|
-
|
|
45
|
-
range.insertNode(
|
|
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
|
|
28
|
+
// Text formatting - check for elements only, not CSS styles
|
|
29
29
|
bold: (el) => {
|
|
30
30
|
const tagName = el.tagName?.toLowerCase()
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
39
|
-
|
|
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
|
-
|
|
46
|
-
|
|
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
|
|
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'
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 = (
|
|
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 =>
|
|
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 = (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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', {
|
|
359
|
-
|
|
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
|
}
|
package/src/types/BagelForm.ts
CHANGED
|
@@ -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 |
|
|
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:
|
|
312
|
-
): { $el: string, class: string, children:
|
|
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?:
|
|
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
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -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]) => [
|