@bagelink/vue 1.4.111 → 1.4.118
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 +14 -14
- 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/composables/useEditor.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.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/plugins/modalTypes.d.ts +2 -1
- package/dist/plugins/modalTypes.d.ts.map +1 -1
- package/dist/plugins/useModal.d.ts +1 -1
- package/dist/plugins/useModal.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/BagelForm.d.ts +40 -19
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/types/NavLink.d.ts +1 -1
- package/dist/types/NavLink.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +20 -5
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/elementUtils.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.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 +8 -9
- package/src/components/layout/AppContent.vue +21 -1
- package/src/composables/useSchemaField.ts +7 -7
- package/src/plugins/modalTypes.ts +10 -2
- package/src/plugins/useModal.ts +23 -7
- package/src/styles/layout.css +6 -0
- package/src/types/BagelForm.ts +97 -22
- package/src/types/NavLink.ts +1 -1
- package/src/utils/BagelFormUtils.ts +63 -34
- package/src/utils/elementUtils.ts +1 -4
- package/src/utils/index.ts +7 -5
- /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,8 +1,7 @@
|
|
|
1
|
-
import type { BaseBagelField } from '@bagelink/vue'
|
|
2
1
|
import type { ModalApi } from '../../../../../plugins/useModal'
|
|
3
2
|
|
|
4
3
|
import type { EditorState } from '../richTextTypes'
|
|
5
|
-
import { bagelFormUtils as
|
|
4
|
+
import { bagelFormUtils as frm } from '../../../../../utils'
|
|
6
5
|
|
|
7
6
|
export function insertImage(modal: ModalApi, state: EditorState) {
|
|
8
7
|
const { range, doc } = state
|
|
@@ -19,9 +18,9 @@ export function insertImage(modal: ModalApi, state: EditorState) {
|
|
|
19
18
|
schema: [
|
|
20
19
|
{ id: 'src', $el: 'file', attrs: { bindkey: 'url' } },
|
|
21
20
|
{ id: 'alt', $el: 'text', label: 'Alt Text' },
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
frm.frmRow(
|
|
22
|
+
frm.numField('width', 'Width', { min: 1 }),
|
|
23
|
+
frm.numField('height', 'Height', { min: 1 }),
|
|
25
24
|
),
|
|
26
25
|
{ id: 'figcaption', $el: 'check', label: 'Show Caption' },
|
|
27
26
|
],
|
|
@@ -86,11 +85,11 @@ export function insertEmbed(modal: ModalApi, state: EditorState) {
|
|
|
86
85
|
title: 'Insert Embed',
|
|
87
86
|
schema: [
|
|
88
87
|
{ id: 'url', $el: 'text', label: 'URL', attrs: { placeholder: 'Enter URL (YouTube, Vimeo, etc.)' } },
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
frm.frmRow(
|
|
89
|
+
frm.numField('width', 'Width', { min: 200, placeholder: '560' }),
|
|
90
|
+
frm.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
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { BglFormSchemaT, BtnOptions, ThemeType } from '@bagelink/vue'
|
|
2
1
|
import type { MaybeRefOrGetter } from 'vue'
|
|
2
|
+
import type { BtnOptions, ThemeType } from '../types'
|
|
3
|
+
import type { BglFormSchemaT } from '../types/BagelForm'
|
|
3
4
|
|
|
4
5
|
export interface ModalOptions {
|
|
5
6
|
title?: string
|
|
@@ -25,7 +26,14 @@ export interface ModalConfirmOptions {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export type ModalType = 'modal' | 'modalForm' | 'confirmModal'
|
|
28
|
-
export type ConfirmModalUserOptions = string | {
|
|
29
|
+
export type ConfirmModalUserOptions = string | {
|
|
30
|
+
title: string
|
|
31
|
+
message: string
|
|
32
|
+
confirmText?: string
|
|
33
|
+
cancelText?: string
|
|
34
|
+
confirmBtnColor?: string
|
|
35
|
+
cancelBtnColor?: string
|
|
36
|
+
}
|
|
29
37
|
|
|
30
38
|
export interface ModalComponentProps<T extends { [key: string]: any }> {
|
|
31
39
|
componentSlots: { [key: string]: any }
|
package/src/plugins/useModal.ts
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
import type { InjectionKey, Plugin } from 'vue'
|
|
2
2
|
import type { ComponentProps } from 'vue-component-type-helpers'
|
|
3
|
-
import type {
|
|
4
|
-
|
|
3
|
+
import type {
|
|
4
|
+
ModalComponentProps,
|
|
5
|
+
ModalFormComponentProps,
|
|
6
|
+
ModalFormOptions,
|
|
7
|
+
ModalOptions,
|
|
8
|
+
ModalType,
|
|
9
|
+
ConfirmModalUserOptions,
|
|
10
|
+
ModalConfirmOptions
|
|
11
|
+
} from './modalTypes'
|
|
5
12
|
import { defineComponent, h, inject } from 'vue'
|
|
13
|
+
import { Modal, ModalConfirm, ModalForm } from '../components'
|
|
6
14
|
|
|
7
15
|
export interface ModalApi {
|
|
8
|
-
showModal: <T extends { [key: string]: any }>(
|
|
9
|
-
|
|
16
|
+
showModal: <T extends { [key: string]: any }>(
|
|
17
|
+
options: ModalOptions,
|
|
18
|
+
slots?: { [key: string]: any }
|
|
19
|
+
) => ModalComponentProps<T> | undefined
|
|
20
|
+
showModalForm: <T extends { [key: string]: any }>(
|
|
21
|
+
options: ModalFormOptions<T>,
|
|
22
|
+
slots?: { [key: string]: any }
|
|
23
|
+
) => ModalFormComponentProps<T> | undefined
|
|
10
24
|
hideModal: (index?: number) => void
|
|
11
25
|
confirmModal: (options: ConfirmModalUserOptions) => Promise<boolean>
|
|
12
26
|
}
|
|
@@ -21,7 +35,7 @@ export function useModal(): ModalApi {
|
|
|
21
35
|
|
|
22
36
|
export const ModalPlugin: Plugin = {
|
|
23
37
|
install: (app) => {
|
|
24
|
-
const modalStack
|
|
38
|
+
const modalStack: ModalComponentProps<object>[] = []
|
|
25
39
|
|
|
26
40
|
const hideModal = (index: number) => {
|
|
27
41
|
modalStack.splice(index, 1)
|
|
@@ -59,7 +73,10 @@ export const ModalPlugin: Plugin = {
|
|
|
59
73
|
app.provide(ModalSymbol, {
|
|
60
74
|
showModal: (options: ModalOptions, slots?: { [key: string]: any }) => showModal('modal', options, slots),
|
|
61
75
|
|
|
62
|
-
showModalForm: <T extends { [key: string]: any }>(
|
|
76
|
+
showModalForm: <T extends { [key: string]: any }>(
|
|
77
|
+
options: ModalFormOptions<T>,
|
|
78
|
+
slots?: { [key: string]: any }
|
|
79
|
+
) => showModal<T>('modalForm', options, slots) as ModalFormComponentProps<T>,
|
|
63
80
|
|
|
64
81
|
confirmModal: (options: ConfirmModalUserOptions) => confirmModal(options),
|
|
65
82
|
|
|
@@ -80,7 +97,6 @@ export const ModalPlugin: Plugin = {
|
|
|
80
97
|
case 'modalForm':
|
|
81
98
|
return h(ModalForm, props as ComponentProps<typeof ModalForm>, modal.componentSlots)
|
|
82
99
|
case 'confirmModal':
|
|
83
|
-
|
|
84
100
|
return h(ModalConfirm, props as ModalConfirmOptions, {})
|
|
85
101
|
default:
|
|
86
102
|
return h(Modal, props, modal.componentSlots)
|
package/src/styles/layout.css
CHANGED
package/src/types/BagelForm.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
// Local type definitions for internal use only
|
|
2
|
+
type ArrayAttrs = any
|
|
3
|
+
interface Option { label: string, value: any }
|
|
2
4
|
import type { Paths, Get, IterableElement, OmitIndexSignature } from 'type-fest'
|
|
3
5
|
import type { ToString } from 'type-fest/source/internal'
|
|
4
6
|
import type { LiteralStringUnion } from 'type-fest/source/literal-union'
|
|
5
7
|
import type { PathsOptions, DefaultPathsOptions } from 'type-fest/source/paths'
|
|
6
8
|
import type { VNode } from 'vue'
|
|
7
|
-
import type { ComponentExposed } from 'vue-component-type-helpers'
|
|
8
9
|
|
|
9
10
|
export type AttributeValue =
|
|
10
11
|
| string
|
|
@@ -14,7 +15,7 @@ export type AttributeValue =
|
|
|
14
15
|
| { [key: string]: any }
|
|
15
16
|
|
|
16
17
|
export type AttributeFn<T, P extends Path<T>> = (
|
|
17
|
-
field:
|
|
18
|
+
field: SmartFieldVal<T, P>,
|
|
18
19
|
row?: T
|
|
19
20
|
) => AttributeValue
|
|
20
21
|
|
|
@@ -34,16 +35,16 @@ export type BagelFieldOptions<T, P extends Path<T>> =
|
|
|
34
35
|
| boolean
|
|
35
36
|
| { [key: string]: any }
|
|
36
37
|
)[]
|
|
37
|
-
| ((val?:
|
|
38
|
-
| ((query: string, val?:
|
|
38
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => Option[] | ((query: string) => Promise<Option[]>))
|
|
39
|
+
| ((query: string, val?: SmartFieldVal<T, P>, rowData?: T) => Promise<Option[]>)
|
|
39
40
|
|
|
40
41
|
export type VIfType<T, P extends Path<T>> =
|
|
41
42
|
| string
|
|
42
43
|
| boolean
|
|
43
|
-
| ((val?:
|
|
44
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => boolean)
|
|
44
45
|
|
|
45
46
|
export type ValidationFn<T, P extends Path<T>> = (
|
|
46
|
-
val?:
|
|
47
|
+
val?: SmartFieldVal<T, P>,
|
|
47
48
|
rowData?: T
|
|
48
49
|
) => string | undefined
|
|
49
50
|
|
|
@@ -56,10 +57,84 @@ export type _Path<
|
|
|
56
57
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
57
58
|
> = ToString<Paths<OmitIndexSignature<T>, PO>>
|
|
58
59
|
|
|
60
|
+
// Utility type for open-ended object paths
|
|
61
|
+
export type OpenEndedPath<T> =
|
|
62
|
+
keyof T extends infer K ?
|
|
63
|
+
K extends keyof T ?
|
|
64
|
+
T[K] extends { [key: string]: any } ?
|
|
65
|
+
`${K & string}.${string}`
|
|
66
|
+
: never
|
|
67
|
+
: never
|
|
68
|
+
: never
|
|
69
|
+
|
|
70
|
+
// Enhanced Path type that allows flexibility for nested open-ended objects
|
|
59
71
|
export type Path<T, PO extends PathsOptions = DefaultPathsOptions> =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
FieldVal<T, _Path<T, PO>> extends Array<any>
|
|
73
|
+
? 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
|
+
)
|
|
84
|
+
|
|
85
|
+
// Smart field value type that preserves type information when possible
|
|
86
|
+
export type SmartFieldVal<T, P extends Path<T>> =
|
|
87
|
+
P extends string
|
|
88
|
+
? P extends keyof T
|
|
89
|
+
? T[P]
|
|
90
|
+
: any
|
|
91
|
+
: FieldVal<T, P>
|
|
92
|
+
|
|
93
|
+
// Smart bagel field options that preserve type information
|
|
94
|
+
export type SmartBagelFieldOptions<T, P extends Path<T>> =
|
|
95
|
+
| string
|
|
96
|
+
| (
|
|
97
|
+
| {
|
|
98
|
+
label?: string
|
|
99
|
+
value: string | number
|
|
100
|
+
}
|
|
101
|
+
| string
|
|
102
|
+
| number
|
|
103
|
+
| boolean
|
|
104
|
+
| { [key: string]: any }
|
|
105
|
+
)[]
|
|
106
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => Option[] | ((query: string) => Promise<Option[]>))
|
|
107
|
+
| ((query: string, val?: SmartFieldVal<T, P>, rowData?: T) => Promise<Option[]>)
|
|
108
|
+
|
|
109
|
+
// Smart VIf type that preserves type information
|
|
110
|
+
export type SmartVIfType<T, P extends Path<T>> =
|
|
111
|
+
| string
|
|
112
|
+
| boolean
|
|
113
|
+
| ((val?: SmartFieldVal<T, P>, rowData?: T) => boolean)
|
|
114
|
+
|
|
115
|
+
// Smart validation function that preserves type information
|
|
116
|
+
export type SmartValidationFn<T, P extends Path<T>> = (
|
|
117
|
+
val?: SmartFieldVal<T, P>,
|
|
118
|
+
rowData?: T
|
|
119
|
+
) => string | undefined
|
|
120
|
+
|
|
121
|
+
// Smart attribute function that preserves type information
|
|
122
|
+
export type SmartAttributeFn<T, P extends Path<T>> = (
|
|
123
|
+
field: SmartFieldVal<T, P>,
|
|
124
|
+
row?: T
|
|
125
|
+
) => AttributeValue
|
|
126
|
+
|
|
127
|
+
// Smart transform function that preserves type information
|
|
128
|
+
export type SmartTransformFn<T, P extends Path<T>> = (
|
|
129
|
+
val?: SmartFieldVal<T, P>,
|
|
130
|
+
rowData?: T
|
|
131
|
+
) => any
|
|
132
|
+
|
|
133
|
+
// Smart update function that preserves type information
|
|
134
|
+
export type SmartUpdateFn<T, P extends Path<T>> = (
|
|
135
|
+
val?: SmartFieldVal<T, P>,
|
|
136
|
+
rowData?: T
|
|
137
|
+
) => unknown
|
|
63
138
|
|
|
64
139
|
/** The value type at path P in object T. */
|
|
65
140
|
// Fall back to unknown if type resolution fails
|
|
@@ -93,7 +168,7 @@ export type SchemaChild<
|
|
|
93
168
|
T,
|
|
94
169
|
P extends Path<T, PO>,
|
|
95
170
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
96
|
-
> = Field<T, PO> | ElementField<T, PO> | VNode | VNodeFn<T, P> | string
|
|
171
|
+
> = Field<T, PO> | ElementField<T, PO> | VNode | VNodeFn<T, P> | string | BaseBagelField<T, P, PO>
|
|
97
172
|
|
|
98
173
|
export interface BaseBagelField<
|
|
99
174
|
T,
|
|
@@ -104,20 +179,20 @@ export interface BaseBagelField<
|
|
|
104
179
|
'id'?: P
|
|
105
180
|
'label'?: string
|
|
106
181
|
'placeholder'?: string
|
|
107
|
-
'class'?: AttributeValue |
|
|
182
|
+
'class'?: AttributeValue | SmartAttributeFn<T, P>
|
|
108
183
|
'attrs'?: Attributes<T, P>
|
|
109
184
|
'required'?: boolean
|
|
110
185
|
'disabled'?: boolean
|
|
111
186
|
'helptext'?: string
|
|
112
|
-
'options'?:
|
|
187
|
+
'options'?: SmartBagelFieldOptions<T, P>
|
|
113
188
|
'children'?: SchemaChild<T, Path<T, PO>, PO>[]
|
|
114
189
|
'slots'?: { [key: string]: SchemaChild<T, Path<T, PO>, PO>[] }
|
|
115
190
|
'defaultValue'?: any
|
|
116
|
-
'vIf'?:
|
|
117
|
-
'v-if'?:
|
|
118
|
-
'transform'?:
|
|
119
|
-
'onUpdate'?:
|
|
120
|
-
'validate'?:
|
|
191
|
+
'vIf'?: SmartVIfType<T, P>
|
|
192
|
+
'v-if'?: SmartVIfType<T, P>
|
|
193
|
+
'transform'?: SmartTransformFn<T, P>
|
|
194
|
+
'onUpdate'?: SmartUpdateFn<T, P>
|
|
195
|
+
'validate'?: SmartValidationFn<T, P>
|
|
121
196
|
}
|
|
122
197
|
|
|
123
198
|
export type _MappedBaseBagelField<
|
|
@@ -170,7 +245,7 @@ export interface InputBagelField<
|
|
|
170
245
|
PO extends PathsOptions = DefaultPathsOptions
|
|
171
246
|
>
|
|
172
247
|
extends BaseBagelField<T, P, PO> {
|
|
173
|
-
$el: 'text' |
|
|
248
|
+
$el: 'text' | any
|
|
174
249
|
type?: string
|
|
175
250
|
}
|
|
176
251
|
|
|
@@ -180,7 +255,7 @@ export interface SelectBagelField<
|
|
|
180
255
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
181
256
|
>
|
|
182
257
|
extends BaseBagelField<T, P, PO> {
|
|
183
|
-
$el: 'select' |
|
|
258
|
+
$el: 'select' | any
|
|
184
259
|
type?: string
|
|
185
260
|
}
|
|
186
261
|
|
|
@@ -190,8 +265,8 @@ export interface ArrayBagelField<
|
|
|
190
265
|
PO extends PathsOptions = DefaultPathsOptions,
|
|
191
266
|
>
|
|
192
267
|
extends BaseBagelField<T, P, PO> {
|
|
193
|
-
$el: 'array' |
|
|
194
|
-
attrs?: ArrayAttrs
|
|
268
|
+
$el: 'array' | any
|
|
269
|
+
attrs?: ArrayAttrs
|
|
195
270
|
}
|
|
196
271
|
|
|
197
272
|
export interface ValidateInputBaseT {
|
package/src/types/NavLink.ts
CHANGED