@bagelink/vue 1.4.111 → 1.4.115
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/bin/generateFormSchema.ts +12 -12
- package/dist/components/Card.vue.d.ts.map +1 -1
- package/dist/components/ImportData.vue.d.ts.map +1 -1
- package/dist/components/analytics/PieChart.vue.d.ts.map +1 -1
- package/dist/components/calendar/Index.vue.d.ts.map +1 -1
- package/dist/components/calendar/index.d.ts +2 -0
- package/dist/components/calendar/index.d.ts.map +1 -0
- package/dist/components/calendar/views/MonthView.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/WeekView.vue.d.ts.map +1 -1
- package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
- package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts +1 -0
- package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/media.d.ts.map +1 -1
- package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts +2 -2
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.mjs +5 -5
- package/dist/style.css +1 -1
- package/dist/types/BagelForm.d.ts +24 -12
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +11 -7
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/elementUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Card.vue +1 -2
- package/src/components/DataPreview.vue +1 -1
- package/src/components/ImportData.vue +94 -88
- package/src/components/analytics/PieChart.vue +21 -34
- package/src/components/calendar/Index.vue +15 -35
- package/src/components/calendar/views/MonthView.vue +84 -88
- package/src/components/calendar/views/WeekView.vue +143 -89
- package/src/components/dataTable/DataTable.vue +2 -3
- package/src/components/form/BagelForm.vue +3 -6
- package/src/components/form/inputs/DateInput.vue +2 -2
- package/src/components/form/inputs/DatePicker.vue +40 -47
- package/src/components/form/inputs/RichText/utils/media.ts +1 -2
- package/src/components/layout/AppContent.vue +21 -1
- package/src/composables/useSchemaField.ts +7 -7
- package/src/types/BagelForm.ts +67 -13
- package/src/utils/BagelFormUtils.ts +49 -50
- package/src/utils/elementUtils.ts +1 -4
- /package/src/components/{dialog → calendar}/index.ts +0 -0
|
@@ -114,12 +114,9 @@ async function handleSubmit() {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
// Field renderingks
|
|
117
|
-
const { renderField } = useSchemaField<T
|
|
117
|
+
const { renderField } = useSchemaField<T>({
|
|
118
118
|
mode: 'form',
|
|
119
|
-
getFormData: () =>
|
|
120
|
-
...formData.value,
|
|
121
|
-
get: (path: string) => getNestedValue(formData.value, path, '')
|
|
122
|
-
}),
|
|
119
|
+
getFormData: () => formData.value,
|
|
123
120
|
onUpdateModelValue: (field, value) => {
|
|
124
121
|
if (!field.id) return
|
|
125
122
|
|
|
@@ -128,7 +125,7 @@ const { renderField } = useSchemaField<T, P>({
|
|
|
128
125
|
}
|
|
129
126
|
})
|
|
130
127
|
|
|
131
|
-
const renderSchemaField = (field: any) => renderField(field as BaseBagelField<T,
|
|
128
|
+
const renderSchemaField = (field: any) => renderField(field as BaseBagelField<T, Path<T>>)
|
|
132
129
|
|
|
133
130
|
// Add new method to handle slot input changes
|
|
134
131
|
function handleSlotInputChange(event: Event) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { ModeType } from '../../../utils/calendar/typings'
|
|
3
|
-
import { TextInput, Dropdown,
|
|
3
|
+
import { TextInput, Dropdown, formatDate } from '@bagelink/vue'
|
|
4
4
|
import { onClickOutside } from '@vueuse/core'
|
|
5
5
|
import { ref, onMounted } from 'vue'
|
|
6
6
|
import { WEEK_START_DAY } from '../../../utils/calendar/time'
|
|
@@ -47,7 +47,7 @@ const isOpen = ref(false)
|
|
|
47
47
|
function useFormatting() {
|
|
48
48
|
const formatDisplayDate = (date: Date | string | undefined): string => {
|
|
49
49
|
if (!date) return ''
|
|
50
|
-
return
|
|
50
|
+
return formatDate(date, { fmt: props.enableTime ? 'DD.MM.YY HH:mm' : 'DD.MM.YY' })
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const parseUserInput = (input: string): Date | null => {
|
|
@@ -15,6 +15,7 @@ const props = withDefaults(
|
|
|
15
15
|
locale?: string
|
|
16
16
|
enableTime?: boolean
|
|
17
17
|
highlightedDates?: MaybeRefOrGetter<(string | Date)[]>
|
|
18
|
+
disabledDates?: MaybeRefOrGetter<(string | Date)[]>
|
|
18
19
|
autoSize?: boolean
|
|
19
20
|
}>(),
|
|
20
21
|
{
|
|
@@ -28,6 +29,7 @@ const props = withDefaults(
|
|
|
28
29
|
const emit = defineEmits(['update:modelValue'])
|
|
29
30
|
|
|
30
31
|
const computedHighlightedDates = $computed(() => toValue(props.highlightedDates))
|
|
32
|
+
const computedDisabledDates = $computed(() => toValue(props.disabledDates))
|
|
31
33
|
|
|
32
34
|
// State
|
|
33
35
|
const currentMonth = ref(new Date())
|
|
@@ -50,8 +52,24 @@ function useDateValidation() {
|
|
|
50
52
|
const minDate = parseDate(props.min)
|
|
51
53
|
const maxDate = parseDate(props.max)
|
|
52
54
|
|
|
55
|
+
// Check if date is in min/max range
|
|
53
56
|
if (minDate && date < minDate) return true
|
|
54
57
|
if (maxDate && date > maxDate) return true
|
|
58
|
+
|
|
59
|
+
// Check if date is in the disabled dates array
|
|
60
|
+
if (Array.isArray(computedDisabledDates) && computedDisabledDates.length > 0) {
|
|
61
|
+
const isInDisabledDates = computedDisabledDates.some((disabledDate) => {
|
|
62
|
+
const parsedDisabledDate = parseDate(disabledDate)
|
|
63
|
+
if (!parsedDisabledDate) return false
|
|
64
|
+
|
|
65
|
+
// Compare year, month, and day
|
|
66
|
+
return date.getFullYear() === parsedDisabledDate.getFullYear()
|
|
67
|
+
&& date.getMonth() === parsedDisabledDate.getMonth()
|
|
68
|
+
&& date.getDate() === parsedDisabledDate.getDate()
|
|
69
|
+
})
|
|
70
|
+
if (isInDisabledDates) return true
|
|
71
|
+
}
|
|
72
|
+
|
|
55
73
|
return false
|
|
56
74
|
}
|
|
57
75
|
|
|
@@ -310,7 +328,7 @@ function selectDate(date: Date | null) {
|
|
|
310
328
|
</script>
|
|
311
329
|
|
|
312
330
|
<template>
|
|
313
|
-
<div class="ltr gap-075 m_flex-wrap calendar-container justify-content-center h-100p" :class="{
|
|
331
|
+
<div class="ltr gap-075 m_flex-wrap calendar-container justify-content-center h-100p" :class="{ flex: !autoSize }">
|
|
314
332
|
<div class="calendar-section m_border-none px-05 m_p-0">
|
|
315
333
|
<div class="flex space-between pb-1">
|
|
316
334
|
<template v-if="currentView === 'days'">
|
|
@@ -333,18 +351,12 @@ function selectDate(date: Date | null) {
|
|
|
333
351
|
</div>
|
|
334
352
|
|
|
335
353
|
<div v-if="currentView === 'days'" class="calendar-grid grid gap-025">
|
|
336
|
-
<div
|
|
337
|
-
v-for="day in weekDays"
|
|
338
|
-
:key="day"
|
|
339
|
-
class="txt-center txt-12 opacity-6"
|
|
340
|
-
>
|
|
354
|
+
<div v-for="day in weekDays" :key="day" class="txt-center txt-12 opacity-6">
|
|
341
355
|
{{ day }}
|
|
342
356
|
</div>
|
|
343
357
|
|
|
344
358
|
<button
|
|
345
|
-
v-for="date in currentMonthDays"
|
|
346
|
-
:key="date?.toISOString()"
|
|
347
|
-
type="button"
|
|
359
|
+
v-for="date in currentMonthDays" :key="date?.toISOString()" type="button"
|
|
348
360
|
class="day aspect-ratio-1 flex align-items-center justify-content-center pointer round txt14 p-0"
|
|
349
361
|
:class="{
|
|
350
362
|
'selected': isSelected(date),
|
|
@@ -352,9 +364,7 @@ function selectDate(date: Date | null) {
|
|
|
352
364
|
'disabled': isDateDisabled(date),
|
|
353
365
|
'not-in-month': isNotInMonth(date),
|
|
354
366
|
'highlighted': isHighlighted(date),
|
|
355
|
-
}"
|
|
356
|
-
:disabled="isDateDisabled(date)"
|
|
357
|
-
@click="selectDate(date)"
|
|
367
|
+
}" :disabled="isDateDisabled(date)" @click="selectDate(date)"
|
|
358
368
|
>
|
|
359
369
|
{{ date?.getDate() }}
|
|
360
370
|
</button>
|
|
@@ -362,52 +372,34 @@ function selectDate(date: Date | null) {
|
|
|
362
372
|
|
|
363
373
|
<div v-else-if="currentView === 'months'" class="month-grid grid gap-05 p-05">
|
|
364
374
|
<Btn
|
|
365
|
-
v-for="month in months"
|
|
366
|
-
:
|
|
367
|
-
thin
|
|
368
|
-
:flat="month.value !== currentMonthValue.month"
|
|
369
|
-
:disabled="month.disabled"
|
|
370
|
-
:value="month.name"
|
|
371
|
-
@click="selectMonth(month.value)"
|
|
375
|
+
v-for="month in months" :key="month.value" thin :flat="month.value !== currentMonthValue.month"
|
|
376
|
+
:disabled="month.disabled" :value="month.name" @click="selectMonth(month.value)"
|
|
372
377
|
/>
|
|
373
378
|
</div>
|
|
374
379
|
|
|
375
380
|
<div v-else class="year-grid grid gap-05 p-0">
|
|
376
381
|
<Btn
|
|
377
|
-
v-for="year in years"
|
|
378
|
-
:
|
|
379
|
-
:flat="year.value !== currentMonthValue.year"
|
|
380
|
-
:disabled="year.disabled"
|
|
381
|
-
:value="year.value.toString()"
|
|
382
|
-
@click="selectYear(year.value)"
|
|
382
|
+
v-for="year in years" :key="year.value" thin :flat="year.value !== currentMonthValue.year"
|
|
383
|
+
:disabled="year.disabled" :value="year.value.toString()" @click="selectYear(year.value)"
|
|
383
384
|
/>
|
|
384
385
|
</div>
|
|
385
386
|
</div>
|
|
386
387
|
|
|
387
|
-
<div
|
|
388
|
+
<div
|
|
389
|
+
v-if="enableTime && currentView === 'days'"
|
|
390
|
+
class="time-picker border-start flex column gap-1 w-120px px-025"
|
|
391
|
+
>
|
|
388
392
|
<div class="flex gap-025">
|
|
389
393
|
<NumberInput
|
|
390
|
-
center
|
|
391
|
-
:modelValue="
|
|
392
|
-
:disabled="!selectedDate"
|
|
393
|
-
:min="0"
|
|
394
|
-
:max="23"
|
|
395
|
-
layout="vertical"
|
|
396
|
-
:padZero="2"
|
|
397
|
-
@update:modelValue="handleHourInput"
|
|
394
|
+
center :modelValue="hours" :disabled="!selectedDate" :min="0" :max="23" layout="vertical"
|
|
395
|
+
:padZero="2" @update:modelValue="handleHourInput"
|
|
398
396
|
/>
|
|
399
397
|
<p class="pb-075">
|
|
400
398
|
:
|
|
401
399
|
</p>
|
|
402
400
|
<NumberInput
|
|
403
|
-
center
|
|
404
|
-
:modelValue="
|
|
405
|
-
:disabled="!selectedDate"
|
|
406
|
-
:min="0"
|
|
407
|
-
:max="59"
|
|
408
|
-
:padZero="2"
|
|
409
|
-
layout="vertical"
|
|
410
|
-
@update:modelValue="handleMinuteInput"
|
|
401
|
+
center :modelValue="minutes" :disabled="!selectedDate" :min="0" :max="59" :padZero="2"
|
|
402
|
+
layout="vertical" @update:modelValue="handleMinuteInput"
|
|
411
403
|
/>
|
|
412
404
|
</div>
|
|
413
405
|
</div>
|
|
@@ -478,6 +470,7 @@ function selectDate(date: Date | null) {
|
|
|
478
470
|
color: var(--bgl-text-color);
|
|
479
471
|
outline: 1px solid var(--border-color);
|
|
480
472
|
}
|
|
473
|
+
|
|
481
474
|
.day:hover:not(.disabled).selected {
|
|
482
475
|
filter: var(--bgl-hover-filter);
|
|
483
476
|
background-color: var(--bgl-primary);
|
|
@@ -504,16 +497,16 @@ function selectDate(date: Date | null) {
|
|
|
504
497
|
}
|
|
505
498
|
|
|
506
499
|
.day.highlighted:not(.selected) {
|
|
507
|
-
|
|
508
|
-
|
|
500
|
+
background-color: var(--bgl-secondary-light, rgba(var(--bgl-primary-rgb, 0, 123, 255), 0.15));
|
|
501
|
+
font-weight: 500;
|
|
509
502
|
}
|
|
510
503
|
|
|
511
504
|
.day.highlighted.selected {
|
|
512
|
-
|
|
513
|
-
|
|
505
|
+
/* Add a subtle ring effect for dates that are both selected and highlighted */
|
|
506
|
+
box-shadow: 0 0 0 2px var(--bgl-secondary, rgba(var(--bgl-primary-rgb, 0, 123, 255), 0.5));
|
|
514
507
|
}
|
|
515
508
|
|
|
516
509
|
.day.highlighted:not(.selected):hover {
|
|
517
|
-
|
|
510
|
+
background-color: var(--bgl-secondary-light-hover, rgba(var(--bgl-primary-rgb, 0, 123, 255), 0.25));
|
|
518
511
|
}
|
|
519
512
|
</style>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { BaseBagelField } from '@bagelink/vue'
|
|
2
1
|
import type { ModalApi } from '../../../../../plugins/useModal'
|
|
3
2
|
|
|
4
3
|
import type { EditorState } from '../richTextTypes'
|
|
@@ -90,7 +89,7 @@ export function insertEmbed(modal: ModalApi, state: EditorState) {
|
|
|
90
89
|
bglFrmUtil.numField('width', 'Width', { min: 200, placeholder: '560' }),
|
|
91
90
|
bglFrmUtil.numField('height', 'Height', { min: 200, placeholder: '315' })
|
|
92
91
|
),
|
|
93
|
-
{ id: 'allowFullscreen', $el: 'check', label: 'Allow Fullscreen', value: true }
|
|
92
|
+
{ id: 'allowFullscreen', $el: 'check', label: 'Allow Fullscreen', attrs: { value: true } },
|
|
94
93
|
],
|
|
95
94
|
onSubmit: (data: { url: string, width?: number, height?: number, allowFullscreen?: boolean }) => {
|
|
96
95
|
if (!data.url) return
|
|
@@ -66,7 +66,7 @@ const sidebarCardStyle = inject('sidebarCardStyle', { value: true })
|
|
|
66
66
|
</header>
|
|
67
67
|
|
|
68
68
|
<!-- Page Content -->
|
|
69
|
-
<main class="flex-grow overflow py-1 w-100p m_p-05 m_scrollbar-gutter-stable-both m_vw100" :class="{
|
|
69
|
+
<main class="pageContent flex-grow overflow py-1 w-100p m_p-05 m_scrollbar-gutter-stable-both m_vw100" :class="{
|
|
70
70
|
'px-1': !sidebarCardStyle?.value,
|
|
71
71
|
}">
|
|
72
72
|
<slot name="content">
|
|
@@ -77,6 +77,26 @@ const sidebarCardStyle = inject('sidebarCardStyle', { value: true })
|
|
|
77
77
|
</div>
|
|
78
78
|
</template>
|
|
79
79
|
|
|
80
|
+
<style>
|
|
81
|
+
.slide-fade-enter-from:has(.app-header),
|
|
82
|
+
.slide-fade-leave-to:has(.app-header) {
|
|
83
|
+
transform: translateX(0) !important;
|
|
84
|
+
opacity: 1 !important;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.slide-fade-enter-from:has(.app-header) .pageContent,
|
|
88
|
+
.slide-fade-leave-to:has(.app-header) .pageContent {
|
|
89
|
+
transform: translateX(-20px) !important;
|
|
90
|
+
opacity: 0 !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.slide-fade-enter-active:has(.app-header) .pageContent,
|
|
94
|
+
.slide-fade-leave-active:has(.app-header) .pageContent {
|
|
95
|
+
transition: all 0.15s ease-in;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
}
|
|
98
|
+
</style>
|
|
99
|
+
|
|
80
100
|
<style scoped>
|
|
81
101
|
.paddingAppContent {
|
|
82
102
|
padding-inline-start: 0.5rem;
|
|
@@ -34,7 +34,7 @@ export interface UseSchemaFieldOptions<T, SFP extends Path<T>> {
|
|
|
34
34
|
includeUnset?: boolean
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export function useSchemaField<T extends { [key: string]: any }
|
|
37
|
+
export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchemaFieldOptions<T, Path<T>>) {
|
|
38
38
|
const { mode = 'form', getFormData, onUpdateModelValue, includeUnset = false } = optns
|
|
39
39
|
|
|
40
40
|
// Helper function to render objects recursively
|
|
@@ -96,18 +96,18 @@ export function useSchemaField<T extends { [key: string]: any }, SP extends Path
|
|
|
96
96
|
return typeof field.$el === 'object' ? field.$el : componentMap[field.$el as keyof typeof componentMap] ?? field.$el ?? 'div'
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
function renderChild(child: SchemaChild<T,
|
|
99
|
+
function renderChild(child: SchemaChild<T, Path<T>>, slots?: BaseBagelField<T, Path<T>>['slots']) {
|
|
100
100
|
if (typeof child === 'string') return child
|
|
101
101
|
if (isVNode(child)) return child
|
|
102
102
|
return renderField(
|
|
103
|
-
child as BaseBagelField<T,
|
|
103
|
+
child as BaseBagelField<T, Path<T>>,
|
|
104
104
|
slots
|
|
105
105
|
)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function renderField(
|
|
109
|
-
field: BaseBagelField<T,
|
|
110
|
-
slots?: BaseBagelField<T,
|
|
109
|
+
field: BaseBagelField<T, Path<T>>,
|
|
110
|
+
slots?: BaseBagelField<T, Path<T>>['slots']
|
|
111
111
|
): VNode | undefined {
|
|
112
112
|
const Component = getComponent(field as Field<T>)
|
|
113
113
|
if (!Component) return
|
|
@@ -320,7 +320,7 @@ export function useSchemaField<T extends { [key: string]: any }, SP extends Path
|
|
|
320
320
|
return schemaField
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
-
return renderField(schemaField as BaseBagelField<T,
|
|
323
|
+
return renderField(schemaField as BaseBagelField<T, Path<T>>, slots)
|
|
324
324
|
})
|
|
325
325
|
}
|
|
326
326
|
}
|
|
@@ -329,7 +329,7 @@ export function useSchemaField<T extends { [key: string]: any }, SP extends Path
|
|
|
329
329
|
|
|
330
330
|
// Handle custom slot content from parent
|
|
331
331
|
|
|
332
|
-
const slotContent = field.id ? (slots?.[field.id] as VNodeFn<T,
|
|
332
|
+
const slotContent = field.id ? (slots?.[field.id] as VNodeFn<T, Path<T>> | undefined)?.({ row: rowData, field }) : undefined
|
|
333
333
|
// field.id && slots?.[field.id] && typeof slots[field.id] === 'function' && !Array.isArray(slots?.[field.id])
|
|
334
334
|
// ? (slots[field.id])({ row: rowData, field })
|
|
335
335
|
// : undefined
|
package/src/types/BagelForm.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type AttributeValue =
|
|
|
14
14
|
| { [key: string]: any }
|
|
15
15
|
|
|
16
16
|
export type AttributeFn<T, P extends Path<T>> = (
|
|
17
|
-
field:
|
|
17
|
+
field: SmartFieldVal<T, P>,
|
|
18
18
|
row?: T
|
|
19
19
|
) => AttributeValue
|
|
20
20
|
|
|
@@ -34,16 +34,16 @@ export type BagelFieldOptions<T, P extends Path<T>> =
|
|
|
34
34
|
| boolean
|
|
35
35
|
| { [key: string]: any }
|
|
36
36
|
)[]
|
|
37
|
-
| ((val?:
|
|
38
|
-
| ((query: string, val?:
|
|
37
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => Option[] | ((query: string) => Promise<Option[]>))
|
|
38
|
+
| ((query: string, val?: SmartFieldVal<T, P>, rowData?: T) => Promise<Option[]>)
|
|
39
39
|
|
|
40
40
|
export type VIfType<T, P extends Path<T>> =
|
|
41
41
|
| string
|
|
42
42
|
| boolean
|
|
43
|
-
| ((val?:
|
|
43
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => boolean)
|
|
44
44
|
|
|
45
45
|
export type ValidationFn<T, P extends Path<T>> = (
|
|
46
|
-
val?:
|
|
46
|
+
val?: SmartFieldVal<T, P>,
|
|
47
47
|
rowData?: T
|
|
48
48
|
) => string | undefined
|
|
49
49
|
|
|
@@ -59,7 +59,61 @@ export type _Path<
|
|
|
59
59
|
export type Path<T, PO extends PathsOptions = DefaultPathsOptions> =
|
|
60
60
|
FieldVal<T, _Path<T, PO>> extends Array<any>
|
|
61
61
|
? LiteralStringUnion<_Path<T, PO>>
|
|
62
|
-
: _Path<T, PO>
|
|
62
|
+
: _Path<T, PO> | string
|
|
63
|
+
|
|
64
|
+
// Smart field value type that preserves type information when possible
|
|
65
|
+
export type SmartFieldVal<T, P extends Path<T>> =
|
|
66
|
+
P extends string
|
|
67
|
+
? P extends keyof T
|
|
68
|
+
? T[P]
|
|
69
|
+
: any
|
|
70
|
+
: FieldVal<T, P>
|
|
71
|
+
|
|
72
|
+
// Smart bagel field options that preserve type information
|
|
73
|
+
export type SmartBagelFieldOptions<T, P extends Path<T>> =
|
|
74
|
+
| string
|
|
75
|
+
| (
|
|
76
|
+
| {
|
|
77
|
+
label?: string
|
|
78
|
+
value: string | number
|
|
79
|
+
}
|
|
80
|
+
| string
|
|
81
|
+
| number
|
|
82
|
+
| boolean
|
|
83
|
+
| { [key: string]: any }
|
|
84
|
+
)[]
|
|
85
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => Option[] | ((query: string) => Promise<Option[]>))
|
|
86
|
+
| ((query: string, val?: SmartFieldVal<T, P>, rowData?: T) => Promise<Option[]>)
|
|
87
|
+
|
|
88
|
+
// Smart VIf type that preserves type information
|
|
89
|
+
export type SmartVIfType<T, P extends Path<T>> =
|
|
90
|
+
| string
|
|
91
|
+
| boolean
|
|
92
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => boolean)
|
|
93
|
+
|
|
94
|
+
// Smart validation function that preserves type information
|
|
95
|
+
export type SmartValidationFn<T, P extends Path<T>> = (
|
|
96
|
+
val?: SmartFieldVal<T, P>,
|
|
97
|
+
rowData?: T
|
|
98
|
+
) => string | undefined
|
|
99
|
+
|
|
100
|
+
// Smart attribute function that preserves type information
|
|
101
|
+
export type SmartAttributeFn<T, P extends Path<T>> = (
|
|
102
|
+
field: SmartFieldVal<T, P>,
|
|
103
|
+
row?: T
|
|
104
|
+
) => AttributeValue
|
|
105
|
+
|
|
106
|
+
// Smart transform function that preserves type information
|
|
107
|
+
export type SmartTransformFn<T, P extends Path<T>> = (
|
|
108
|
+
val?: SmartFieldVal<T, P>,
|
|
109
|
+
rowData?: T
|
|
110
|
+
) => any
|
|
111
|
+
|
|
112
|
+
// Smart update function that preserves type information
|
|
113
|
+
export type SmartUpdateFn<T, P extends Path<T>> = (
|
|
114
|
+
val?: SmartFieldVal<T, P>,
|
|
115
|
+
rowData?: T
|
|
116
|
+
) => unknown
|
|
63
117
|
|
|
64
118
|
/** The value type at path P in object T. */
|
|
65
119
|
// Fall back to unknown if type resolution fails
|
|
@@ -104,20 +158,20 @@ export interface BaseBagelField<
|
|
|
104
158
|
'id'?: P
|
|
105
159
|
'label'?: string
|
|
106
160
|
'placeholder'?: string
|
|
107
|
-
'class'?: AttributeValue |
|
|
161
|
+
'class'?: AttributeValue | SmartAttributeFn<T, P>
|
|
108
162
|
'attrs'?: Attributes<T, P>
|
|
109
163
|
'required'?: boolean
|
|
110
164
|
'disabled'?: boolean
|
|
111
165
|
'helptext'?: string
|
|
112
|
-
'options'?:
|
|
166
|
+
'options'?: SmartBagelFieldOptions<T, P>
|
|
113
167
|
'children'?: SchemaChild<T, Path<T, PO>, PO>[]
|
|
114
168
|
'slots'?: { [key: string]: SchemaChild<T, Path<T, PO>, PO>[] }
|
|
115
169
|
'defaultValue'?: any
|
|
116
|
-
'vIf'?:
|
|
117
|
-
'v-if'?:
|
|
118
|
-
'transform'?:
|
|
119
|
-
'onUpdate'?:
|
|
120
|
-
'validate'?:
|
|
170
|
+
'vIf'?: SmartVIfType<T, P>
|
|
171
|
+
'v-if'?: SmartVIfType<T, P>
|
|
172
|
+
'transform'?: SmartTransformFn<T, P>
|
|
173
|
+
'onUpdate'?: SmartUpdateFn<T, P>
|
|
174
|
+
'validate'?: SmartValidationFn<T, P>
|
|
121
175
|
}
|
|
122
176
|
|
|
123
177
|
export type _MappedBaseBagelField<
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ArrayBagelField, ArrayFieldVal, Attributes, BaseBagelField, BglFormSchemaT, FieldByP, IconType, InputBagelField,
|
|
1
|
+
import type { ArrayBagelField, ArrayFieldVal, Attributes, BaseBagelField, BglFormSchemaT, FieldByP, IconType, InputBagelField, Path, SchemaChild, SelectBagelField, ShallowBglFormSchemaT, UploadInputProps } from '@bagelink/vue'
|
|
2
2
|
import type { DefaultPathsOptions, PathsOptions } from 'type-fest/source/paths'
|
|
3
3
|
import type { InputTypeHTMLAttribute, MaybeRefOrGetter } from 'vue'
|
|
4
4
|
|
|
@@ -85,70 +85,64 @@ export function richText<
|
|
|
85
85
|
|
|
86
86
|
export function txtField<
|
|
87
87
|
T,
|
|
88
|
-
P extends Path<T, PO>,
|
|
89
88
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
90
89
|
>(
|
|
91
|
-
id?:
|
|
90
|
+
id?: Path<T, PO>,
|
|
92
91
|
label?: string,
|
|
93
|
-
options?: TextInputOptions<T,
|
|
94
|
-
): InputBagelField<T,
|
|
92
|
+
options?: TextInputOptions<T, Path<T, PO>>,
|
|
93
|
+
): InputBagelField<T, Path<T, PO>, PO> {
|
|
95
94
|
return {
|
|
96
95
|
$el: 'text',
|
|
97
96
|
id,
|
|
98
97
|
label,
|
|
99
98
|
class: options?.class,
|
|
100
99
|
required: options?.required,
|
|
101
|
-
vIf: options?.vIf,
|
|
102
|
-
disabled: options?.disabled,
|
|
103
100
|
placeholder: options?.placeholder,
|
|
104
|
-
defaultValue: options?.defaultValue,
|
|
105
|
-
validate: options?.validate,
|
|
106
|
-
onUpdate: options?.onUpdate,
|
|
107
101
|
helptext: options?.helptext,
|
|
102
|
+
disabled: options?.disabled,
|
|
103
|
+
defaultValue: options?.defaultValue,
|
|
104
|
+
vIf: options?.vIf,
|
|
108
105
|
transform: options?.transform,
|
|
109
106
|
attrs: {
|
|
110
|
-
|
|
107
|
+
autocomplete: options?.autocomplete,
|
|
111
108
|
pattern: options?.pattern,
|
|
112
109
|
multiline: options?.multiline,
|
|
113
|
-
autocomplete: options?.autocomplete,
|
|
114
|
-
rows: options?.rows,
|
|
115
|
-
code: options?.code,
|
|
116
110
|
autoheight: options?.autoheight,
|
|
111
|
+
code: options?.code,
|
|
112
|
+
rows: options?.rows,
|
|
117
113
|
icon: options?.icon,
|
|
118
114
|
iconStart: options?.iconStart,
|
|
115
|
+
type: options?.type,
|
|
119
116
|
},
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
119
|
|
|
123
120
|
export function selectField<
|
|
124
121
|
T,
|
|
125
|
-
P extends Path<T, PO>,
|
|
126
122
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
127
123
|
>(
|
|
128
|
-
id?:
|
|
124
|
+
id?: Path<T, PO>,
|
|
129
125
|
label?: string,
|
|
130
|
-
options?:
|
|
131
|
-
|
|
132
|
-
): SelectBagelField<T,
|
|
126
|
+
options?: any[],
|
|
127
|
+
fieldOptions?: SlctInputOptions<T, Path<T, PO>>,
|
|
128
|
+
): SelectBagelField<T, Path<T, PO>, PO> {
|
|
133
129
|
return {
|
|
134
130
|
$el: 'select',
|
|
135
131
|
id,
|
|
136
|
-
options,
|
|
137
|
-
class: config?.class,
|
|
138
|
-
placeholder: config?.placeholder,
|
|
139
|
-
required: config?.required,
|
|
140
132
|
label,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
133
|
+
class: fieldOptions?.class,
|
|
134
|
+
required: fieldOptions?.required,
|
|
135
|
+
helptext: fieldOptions?.helptext,
|
|
136
|
+
disabled: fieldOptions?.disabled,
|
|
137
|
+
defaultValue: fieldOptions?.defaultValue,
|
|
138
|
+
vIf: fieldOptions?.vIf,
|
|
139
|
+
transform: fieldOptions?.transform,
|
|
140
|
+
options,
|
|
146
141
|
attrs: {
|
|
147
|
-
|
|
148
|
-
searchable:
|
|
149
|
-
multiselect:
|
|
150
|
-
clearable:
|
|
151
|
-
autocomplete: config?.autocomplete,
|
|
142
|
+
...fieldOptions?.attrs,
|
|
143
|
+
searchable: fieldOptions?.searchable,
|
|
144
|
+
multiselect: fieldOptions?.multiselect,
|
|
145
|
+
clearable: fieldOptions?.clearable,
|
|
152
146
|
},
|
|
153
147
|
}
|
|
154
148
|
}
|
|
@@ -162,22 +156,25 @@ interface CheckInputOptions<T, K extends Path<T>> extends Omit<InputOptions<T, K
|
|
|
162
156
|
|
|
163
157
|
export function checkField<
|
|
164
158
|
T,
|
|
165
|
-
P extends Path<T, PO>,
|
|
166
159
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
167
160
|
>(
|
|
168
|
-
id?:
|
|
161
|
+
id?: Path<T, PO>,
|
|
169
162
|
label?: string,
|
|
170
|
-
options?: CheckInputOptions<T,
|
|
171
|
-
): BaseBagelField<T,
|
|
163
|
+
options?: CheckInputOptions<T, Path<T, PO>>,
|
|
164
|
+
): BaseBagelField<T, Path<T, PO>, PO> {
|
|
172
165
|
return {
|
|
173
166
|
$el: 'check',
|
|
167
|
+
id,
|
|
168
|
+
label,
|
|
174
169
|
class: options?.class,
|
|
175
170
|
required: options?.required,
|
|
171
|
+
helptext: options?.helptext,
|
|
172
|
+
disabled: options?.disabled,
|
|
176
173
|
defaultValue: options?.defaultValue,
|
|
177
|
-
|
|
178
|
-
label,
|
|
174
|
+
vIf: options?.vIf,
|
|
179
175
|
transform: options?.transform,
|
|
180
176
|
attrs: {
|
|
177
|
+
...options?.attrs,
|
|
181
178
|
value: options?.value,
|
|
182
179
|
},
|
|
183
180
|
}
|
|
@@ -247,13 +244,12 @@ export function dateField<
|
|
|
247
244
|
|
|
248
245
|
export function numField<
|
|
249
246
|
T,
|
|
250
|
-
P extends Path<T, PO>,
|
|
251
247
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
252
248
|
>(
|
|
253
|
-
id?:
|
|
249
|
+
id?: Path<T, PO>,
|
|
254
250
|
label?: string,
|
|
255
|
-
options?: NumFieldOptions<T,
|
|
256
|
-
): BaseBagelField<T,
|
|
251
|
+
options?: NumFieldOptions<T, Path<T, PO>>,
|
|
252
|
+
): BaseBagelField<T, Path<T, PO>, PO> {
|
|
257
253
|
return {
|
|
258
254
|
$el: 'number',
|
|
259
255
|
class: options?.class,
|
|
@@ -281,11 +277,10 @@ export function numField<
|
|
|
281
277
|
|
|
282
278
|
export function frmRow<
|
|
283
279
|
T,
|
|
284
|
-
P extends Path<T, PO>,
|
|
285
280
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
286
281
|
>(
|
|
287
|
-
...children: SchemaChild<T,
|
|
288
|
-
):
|
|
282
|
+
...children: SchemaChild<T, Path<T, PO>, PO>[]
|
|
283
|
+
): { $el: string, class: string, children: SchemaChild<T, Path<T, PO>, PO>[] } {
|
|
289
284
|
return {
|
|
290
285
|
$el: 'div',
|
|
291
286
|
class: 'flex gap-1 m_block align-items-end',
|
|
@@ -297,17 +292,21 @@ export interface UploadOptions<T, K extends Path<T>> extends Omit<UploadInputPro
|
|
|
297
292
|
|
|
298
293
|
export function uploadField<
|
|
299
294
|
T,
|
|
300
|
-
P extends Path<T, PO>,
|
|
301
295
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
302
296
|
>(
|
|
303
|
-
id?:
|
|
297
|
+
id?: Path<T, PO>,
|
|
304
298
|
label?: string,
|
|
305
|
-
options?: UploadOptions<T,
|
|
306
|
-
): BaseBagelField<T,
|
|
299
|
+
options?: UploadOptions<T, Path<T, PO>>,
|
|
300
|
+
): BaseBagelField<T, Path<T, PO>, PO> {
|
|
307
301
|
return {
|
|
308
302
|
$el: 'upload',
|
|
309
303
|
id,
|
|
310
304
|
label,
|
|
305
|
+
class: options?.class,
|
|
306
|
+
required: options?.required,
|
|
307
|
+
helptext: options?.helptext,
|
|
308
|
+
disabled: options?.disabled,
|
|
309
|
+
defaultValue: options?.defaultValue,
|
|
311
310
|
vIf: options?.vIf,
|
|
312
311
|
transform: options?.transform,
|
|
313
312
|
attrs: {
|
|
@@ -353,20 +353,17 @@ export function img<
|
|
|
353
353
|
): BaseElementField<T, PO> {
|
|
354
354
|
// Handle different overload patterns
|
|
355
355
|
let id: Path<T, PO> | undefined
|
|
356
|
-
let finalSrc: string = ''
|
|
357
356
|
let finalOptions: ImgElementOptions<T, PO> = {}
|
|
358
357
|
|
|
359
358
|
if (typeof idOrOptions === 'object' && idOrOptions !== null) {
|
|
360
359
|
// img(options)
|
|
361
360
|
finalOptions = idOrOptions
|
|
362
|
-
const { id: optionId
|
|
361
|
+
const { id: optionId } = finalOptions
|
|
363
362
|
id = optionId as Path<T, PO> | undefined
|
|
364
|
-
finalSrc = optionSrc ?? ''
|
|
365
363
|
} else {
|
|
366
364
|
// img(id, ...) patterns
|
|
367
365
|
id = idOrOptions
|
|
368
366
|
if (src != null) {
|
|
369
|
-
finalSrc = src
|
|
370
367
|
if (typeof altOrOptions === 'string') {
|
|
371
368
|
// img(id, src, alt)
|
|
372
369
|
finalOptions = { alt: altOrOptions }
|
|
File without changes
|