@bagelink/vue 1.5.15 → 1.5.20
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/experimentalGenTypedRoutes.ts +15 -15
- package/bin/generateFormSchema.ts +12 -12
- package/bin/utils.ts +4 -4
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/RouterWrapper.vue.d.ts.map +1 -1
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
- package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts +5 -4
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/CheckInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -0
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ToggleInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/composables/useFormField.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +68 -55
- package/dist/index.mjs +34035 -143
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/AccordionItem.vue +2 -2
- package/src/components/AddToCalendar.vue +1 -1
- package/src/components/BglVideo.vue +8 -8
- package/src/components/Btn.vue +9 -9
- package/src/components/Card.vue +4 -4
- package/src/components/Carousel.vue +44 -44
- package/src/components/DataPreview.vue +1 -1
- package/src/components/DragOver.vue +6 -6
- package/src/components/Dropdown.vue +14 -14
- package/src/components/Flag.vue +3 -3
- package/src/components/Icon/Icon.vue +13 -13
- package/src/components/Image.vue +4 -4
- package/src/components/ImportData.vue +79 -79
- package/src/components/ListItem.vue +7 -7
- package/src/components/MapEmbed/Index.vue +6 -6
- package/src/components/Modal.vue +10 -10
- package/src/components/ModalForm.vue +4 -4
- package/src/components/NavBar.vue +2 -2
- package/src/components/Pagination.vue +9 -9
- package/src/components/Pill.vue +1 -1
- package/src/components/Rating.vue +2 -2
- package/src/components/RouterWrapper.vue +3 -3
- package/src/components/Slider.vue +77 -77
- package/src/components/Spreadsheet/Index.vue +34 -34
- package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
- package/src/components/Zoomer.vue +28 -28
- package/src/components/analytics/BarChart.vue +6 -6
- package/src/components/analytics/KpiCard.vue +2 -2
- package/src/components/analytics/LineChart.vue +14 -14
- package/src/components/analytics/PieChart.vue +11 -11
- package/src/components/calendar/CalendarPopover.vue +1 -1
- package/src/components/calendar/Index.vue +1 -1
- package/src/components/calendar/views/AgendaView.vue +2 -2
- package/src/components/calendar/views/DayView.vue +6 -6
- package/src/components/calendar/views/MonthView.vue +2 -2
- package/src/components/calendar/views/WeekView.vue +18 -18
- package/src/components/dataTable/DataTable.vue +3 -3
- package/src/components/dataTable/useSorting.ts +1 -1
- package/src/components/dataTable/useTableData.ts +15 -15
- package/src/components/dataTable/useTableSelection.ts +8 -8
- package/src/components/dataTable/useTableVirtualization.ts +1 -1
- package/src/components/draggable/useDraggable.ts +42 -42
- package/src/components/form/BagelForm.vue +66 -23
- package/src/components/form/BglMultiStepForm.vue +18 -18
- package/src/components/form/FieldArray.vue +177 -67
- package/src/components/form/inputs/CheckInput.vue +2 -1
- package/src/components/form/inputs/CodeEditor/Index.vue +1 -1
- package/src/components/form/inputs/CodeEditor/format.ts +7 -7
- package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
- package/src/components/form/inputs/DateInput.vue +6 -6
- package/src/components/form/inputs/DatePicker.vue +19 -19
- package/src/components/form/inputs/EmailInput.vue +14 -14
- package/src/components/form/inputs/NumberInput.vue +6 -6
- package/src/components/form/inputs/OTP.vue +3 -3
- package/src/components/form/inputs/RadioGroup.vue +1 -1
- package/src/components/form/inputs/RadioPillsInput.vue +8 -8
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +10 -10
- package/src/components/form/inputs/RichText/components/TableGridSelector.vue +1 -1
- package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
- package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
- package/src/components/form/inputs/RichText/index.vue +300 -132
- package/src/components/form/inputs/RichText/utils/commands.ts +69 -69
- package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
- package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
- package/src/components/form/inputs/RichText/utils/media.ts +6 -6
- package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
- package/src/components/form/inputs/RichText/utils/table.ts +19 -19
- package/src/components/form/inputs/SelectBtn.vue +1 -1
- package/src/components/form/inputs/SelectInput.vue +50 -26
- package/src/components/form/inputs/SignaturePad.vue +15 -15
- package/src/components/form/inputs/TableField.vue +1 -1
- package/src/components/form/inputs/TelInput.vue +6 -6
- package/src/components/form/inputs/TextInput.vue +5 -5
- package/src/components/form/inputs/ToggleInput.vue +2 -1
- package/src/components/form/inputs/Upload/UploadInput.vue +155 -102
- package/src/components/form/inputs/Upload/upload.ts +1 -1
- package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
- package/src/components/form/useBagelFormState.ts +5 -5
- package/src/components/layout/AppContent.vue +1 -1
- package/src/components/layout/AppLayout.vue +1 -1
- package/src/components/layout/Layout.vue +4 -4
- package/src/components/layout/TabbedLayout.vue +1 -1
- package/src/components/layout/Tabs.vue +2 -2
- package/src/components/layout/TabsNav.vue +7 -7
- package/src/components/lightbox/Lightbox.vue +8 -8
- package/src/components/lightbox/index.ts +8 -8
- package/src/composables/index.ts +2 -2
- package/src/composables/useAddToCalendar.ts +13 -13
- package/src/composables/useDevice.ts +2 -2
- package/src/composables/useExcel.ts +6 -6
- package/src/composables/useFormField.ts +5 -9
- package/src/composables/usePolling.ts +8 -8
- package/src/composables/useSchemaField.ts +53 -38
- package/src/composables/useTheme.ts +9 -9
- package/src/composables/useValidateFieldValue.ts +2 -2
- package/src/directives/pattern.ts +25 -25
- package/src/directives/ripple.ts +4 -4
- package/src/directives/vResize.ts +6 -6
- package/src/plugins/bagel.ts +4 -4
- package/src/plugins/useModal.ts +3 -3
- package/src/styles/layout.css +7 -1
- package/src/utils/BagelFormUtils.ts +7 -7
- package/src/utils/calendar/Helpers.ts +8 -8
- package/src/utils/calendar/dateUtils.ts +22 -22
- package/src/utils/calendar/time.ts +25 -25
- package/src/utils/calendar/week.ts +25 -25
- package/src/utils/elementUtils.ts +27 -27
- package/src/utils/index.ts +22 -22
- package/src/utils/sizeParsing.ts +2 -2
- package/src/utils/strings.ts +5 -5
- package/src/utils/tapDetector.ts +11 -11
- package/src/utils/useSearch.ts +29 -29
- package/vite.config.ts +1 -1
|
@@ -10,12 +10,12 @@ import type {
|
|
|
10
10
|
Path
|
|
11
11
|
} from '@bagelink/vue'
|
|
12
12
|
import type { MaybeRefOrGetter } from 'vue'
|
|
13
|
-
import { BagelForm, Btn, Loading, Icon } from '@bagelink/vue'
|
|
14
|
-
import { ref, computed, watch, toValue } from 'vue'
|
|
13
|
+
import { BagelForm, Btn, Loading, Icon, Card } from '@bagelink/vue'
|
|
14
|
+
import { ref, computed, watch, toValue, onMounted } from 'vue'
|
|
15
15
|
|
|
16
16
|
export interface FieldArrayProps<T, P extends Path<T>> {
|
|
17
17
|
el?: any
|
|
18
|
-
id
|
|
18
|
+
id?: string
|
|
19
19
|
label?: string
|
|
20
20
|
placeholder?: string
|
|
21
21
|
children?: Field<T>[]
|
|
@@ -25,13 +25,14 @@ export interface FieldArrayProps<T, P extends Path<T>> {
|
|
|
25
25
|
disabled?: boolean
|
|
26
26
|
helptext?: string
|
|
27
27
|
options?: BagelFieldOptions<T, P>
|
|
28
|
-
defaultValue?:
|
|
28
|
+
defaultValue?: T[]
|
|
29
29
|
add?: boolean
|
|
30
30
|
delete?: boolean
|
|
31
|
+
collapsed?: boolean
|
|
31
32
|
transform?: (value: T) => T
|
|
32
33
|
schema?: MaybeRefOrGetter<BglFormSchemaT<T>>
|
|
33
|
-
modelValue
|
|
34
|
-
type?: 'object' | 'number' | 'text'
|
|
34
|
+
modelValue?: T[]
|
|
35
|
+
type?: 'object' | 'number' | 'text' | 'array'
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
export interface PrimitiveArrFieldT extends BaseBagelField<{ value: string }, 'value'> {
|
|
@@ -45,6 +46,7 @@ const props = withDefaults(
|
|
|
45
46
|
add: true,
|
|
46
47
|
el: 'div',
|
|
47
48
|
type: 'object',
|
|
49
|
+
collapsed: false,
|
|
48
50
|
}
|
|
49
51
|
)
|
|
50
52
|
|
|
@@ -56,27 +58,93 @@ const BagelFormFA = BagelForm<T, P>
|
|
|
56
58
|
const minimizedItems = ref<boolean[]>([])
|
|
57
59
|
const internalData = ref<any[]>(props.modelValue || [])
|
|
58
60
|
const schemaState = ref<'loading' | 'loaded' | 'error'>('loaded')
|
|
61
|
+
let lastEmittedValue = '' // Event handlers state
|
|
59
62
|
|
|
60
63
|
// Generate schema for primitive types
|
|
61
64
|
const primitiveSchema = computed<PrimitiveArrFieldT[]>(() => {
|
|
62
|
-
if (props.type
|
|
65
|
+
if ('text' === props.type) {
|
|
63
66
|
return [{ id: 'value', type: 'text', label: '', $el: 'text' }]
|
|
64
|
-
}
|
|
67
|
+
}if (props.type === 'number') {
|
|
65
68
|
return [{ id: 'value', type: 'number', label: '', $el: 'number' }]
|
|
66
69
|
}
|
|
67
70
|
return []
|
|
68
71
|
})
|
|
69
72
|
|
|
70
|
-
const resolvedSchemaData =
|
|
71
|
-
|
|
73
|
+
const resolvedSchemaData = computed(() => {
|
|
74
|
+
// Handle 'array' type as equivalent to 'object' type
|
|
75
|
+
const isObjectType = 'object' === props.type || 'array' === props.type
|
|
72
76
|
|
|
73
|
-
return
|
|
74
|
-
|
|
77
|
+
if (!isObjectType) {return primitiveSchema.value as BglFormSchemaT<T>}
|
|
78
|
+
|
|
79
|
+
// Use children prop first, then schema prop, then attrs.schema
|
|
80
|
+
const attrsSchema = props.attrs?.schema !== undefined ? toValue(props.attrs.schema) : null
|
|
81
|
+
const schemaToUse = props.children || toValue(props.schema) || attrsSchema
|
|
82
|
+
|
|
83
|
+
// If no schema but we have defaultValue, try to infer schema from first item
|
|
84
|
+
const noSchema = null === schemaToUse || schemaToUse === undefined
|
|
85
|
+
|| (Array.isArray(schemaToUse) && 0 === schemaToUse.length)
|
|
86
|
+
const hasDefaultValue = props.defaultValue !== undefined
|
|
87
|
+
&& null !== props.defaultValue
|
|
88
|
+
&& 0 < props.defaultValue.length
|
|
75
89
|
|
|
76
|
-
//
|
|
90
|
+
// Don't infer schema from defaultValue - this causes unwanted restoration
|
|
91
|
+
// Let the component work with empty arrays
|
|
92
|
+
return schemaToUse as BglFormSchemaT<T>
|
|
93
|
+
})// Watch for external changes to modelValue - simple and straightforward
|
|
77
94
|
watch(() => props.modelValue, (newValue) => {
|
|
78
|
-
|
|
79
|
-
|
|
95
|
+
// Simply sync with external changes, no automatic defaultValue restoration
|
|
96
|
+
if (newValue && Array.isArray(newValue)) {
|
|
97
|
+
internalData.value = [...newValue]
|
|
98
|
+
} else {
|
|
99
|
+
internalData.value = []
|
|
100
|
+
}
|
|
101
|
+
}, { deep: true, immediate: false })
|
|
102
|
+
|
|
103
|
+
// Watch for changes to internalData length to sync minimizedItems
|
|
104
|
+
watch(() => internalData.value.length, (newLength) => {
|
|
105
|
+
// Resize minimizedItems array to match internalData length
|
|
106
|
+
if (minimizedItems.value.length !== newLength) {
|
|
107
|
+
// If array grew, add new items with collapsed state
|
|
108
|
+
if (minimizedItems.value.length < newLength) {
|
|
109
|
+
const itemsToAdd = newLength - minimizedItems.value.length
|
|
110
|
+
for (let i = 0; i < itemsToAdd; i++) {
|
|
111
|
+
minimizedItems.value.push(props.collapsed || false)
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
// If array shrank, remove excess items
|
|
115
|
+
minimizedItems.value = minimizedItems.value.slice(0, newLength)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Initialize with existing data or defaultValue on mount - only once!
|
|
121
|
+
onMounted(() => {
|
|
122
|
+
// If no modelValue provided, use defaultValue as initial data (one time only)
|
|
123
|
+
if (!props.modelValue || 0 === props.modelValue.length) {
|
|
124
|
+
if (props.defaultValue && 0 < props.defaultValue.length) {
|
|
125
|
+
internalData.value = [...props.defaultValue]
|
|
126
|
+
emitValue() // This will set the initial value and then it becomes "regular" data
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Initialize minimized state based on collapsed prop
|
|
131
|
+
if (props.collapsed) {
|
|
132
|
+
minimizedItems.value = Array.from({ length: internalData.value.length }, () => true)
|
|
133
|
+
} else {
|
|
134
|
+
minimizedItems.value = Array.from({ length: internalData.value.length }, () => false)
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
// Function to load default values (explicit user action)
|
|
139
|
+
function loadDefaults() {
|
|
140
|
+
if (props.defaultValue && 0 < props.defaultValue.length) {
|
|
141
|
+
internalData.value = [...props.defaultValue]
|
|
142
|
+
emitValue()
|
|
143
|
+
} else {
|
|
144
|
+
// If no defaultValue in props, add a single empty item
|
|
145
|
+
addItem()
|
|
146
|
+
}
|
|
147
|
+
}
|
|
80
148
|
|
|
81
149
|
// Resolve schema
|
|
82
150
|
// async function resolveSchema() {
|
|
@@ -120,23 +188,43 @@ watch(() => props.modelValue, (newValue) => {
|
|
|
120
188
|
// onMounted(resolveSchema)
|
|
121
189
|
|
|
122
190
|
// Event handlers
|
|
191
|
+
|
|
123
192
|
function emitValue() {
|
|
124
|
-
emit
|
|
193
|
+
// Only emit if the value has actually changed to prevent recursive updates
|
|
194
|
+
const currentValue = JSON.stringify(props.modelValue || [])
|
|
195
|
+
const newValue = JSON.stringify(internalData.value || [])
|
|
196
|
+
|
|
197
|
+
// Double-check against last emitted value to prevent loops
|
|
198
|
+
if (currentValue !== newValue && lastEmittedValue !== newValue) {
|
|
199
|
+
lastEmittedValue = newValue
|
|
200
|
+
emit('update:modelValue', internalData.value)
|
|
201
|
+
// Reset after a short delay to allow for new changes
|
|
202
|
+
setTimeout(() => {
|
|
203
|
+
lastEmittedValue = ''
|
|
204
|
+
}, 50)
|
|
205
|
+
}
|
|
125
206
|
}
|
|
126
207
|
|
|
127
208
|
function deleteItem(i: number) {
|
|
128
209
|
internalData.value.splice(i, 1)
|
|
210
|
+
minimizedItems.value.splice(i, 1)
|
|
129
211
|
emitValue()
|
|
130
212
|
}
|
|
131
213
|
|
|
132
214
|
function addItem() {
|
|
133
215
|
// Add appropriate default value based on type
|
|
134
|
-
const defaultValues = {
|
|
216
|
+
const defaultValues: { [key: string]: any } = {
|
|
135
217
|
text: '',
|
|
136
218
|
number: 0,
|
|
137
|
-
object: {}
|
|
219
|
+
object: {},
|
|
220
|
+
array: {}
|
|
138
221
|
}
|
|
139
|
-
|
|
222
|
+
const defaultValue = defaultValues[props.type]
|
|
223
|
+
internalData.value.push(defaultValue !== undefined ? defaultValue : {})
|
|
224
|
+
|
|
225
|
+
// Add minimized state for new item - always open (false) when newly added
|
|
226
|
+
minimizedItems.value.push(false)
|
|
227
|
+
|
|
140
228
|
emitValue()
|
|
141
229
|
}
|
|
142
230
|
|
|
@@ -146,8 +234,8 @@ function toggleMinimized(index: number) {
|
|
|
146
234
|
|
|
147
235
|
function updateItem(index: number, value: any) {
|
|
148
236
|
// Handle primitive types by extracting the value property
|
|
149
|
-
if (
|
|
150
|
-
internalData.value[index] = props.type
|
|
237
|
+
if ('text' === props.type || 'number' === props.type) {
|
|
238
|
+
internalData.value[index] = 'number' === props.type ? Number(value.value) : value.value
|
|
151
239
|
} else {
|
|
152
240
|
internalData.value[index] = value
|
|
153
241
|
}
|
|
@@ -155,14 +243,25 @@ function updateItem(index: number, value: any) {
|
|
|
155
243
|
}
|
|
156
244
|
|
|
157
245
|
// Computed properties for rendering
|
|
158
|
-
const isPrimitiveType = computed(() =>
|
|
159
|
-
const canRenderItems = computed(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
246
|
+
const isPrimitiveType = computed(() => 'text' === props.type || 'number' === props.type)
|
|
247
|
+
const canRenderItems = computed(() => {
|
|
248
|
+
const schemaData = resolvedSchemaData.value
|
|
249
|
+
const hasValidSchema = (Array.isArray(schemaData) && 0 < schemaData.length)
|
|
250
|
+
|| (props.children && 0 < props.children.length)
|
|
251
|
+
const hasDefaultValue = props.defaultValue && 0 < props.defaultValue.length
|
|
252
|
+
|
|
253
|
+
// For primitive types or when we have schema or defaultValue
|
|
254
|
+
const isObjectType = 'object' === props.type || 'array' === props.type
|
|
255
|
+
const shouldRender = isPrimitiveType.value
|
|
256
|
+
|| (isObjectType && (true === hasValidSchema || true === hasDefaultValue))
|
|
257
|
+
return shouldRender
|
|
258
|
+
})
|
|
164
259
|
const showMinimizeButton = computed(() => {
|
|
165
|
-
|
|
260
|
+
const schemaData = resolvedSchemaData.value
|
|
261
|
+
const hasLongSchema = Array.isArray(schemaData) && 2 < schemaData.length
|
|
262
|
+
const hasRichText = Array.isArray(schemaData)
|
|
263
|
+
&& schemaData.some((schema: any) => 'richtext' === schema.$el)
|
|
264
|
+
return hasLongSchema || hasRichText
|
|
166
265
|
})
|
|
167
266
|
</script>
|
|
168
267
|
|
|
@@ -172,7 +271,7 @@ const showMinimizeButton = computed(() => {
|
|
|
172
271
|
<p v-if="label" class="label mb-05">
|
|
173
272
|
{{ label }}
|
|
174
273
|
</p>
|
|
175
|
-
<div class="ps-025
|
|
274
|
+
<div class="ps-025 mb-05">
|
|
176
275
|
<!-- Loading/Error States -->
|
|
177
276
|
<div v-if="schemaState !== 'loaded'" class="flex-center h-300px">
|
|
178
277
|
<Loading v-if="schemaState === 'loading'" />
|
|
@@ -180,54 +279,50 @@ const showMinimizeButton = computed(() => {
|
|
|
180
279
|
</div>
|
|
181
280
|
|
|
182
281
|
<!-- No Schema Available -->
|
|
183
|
-
<
|
|
282
|
+
<Card v-else-if="!canRenderItems" class="py-1 border mb-05">
|
|
184
283
|
<p class="opacity-7">
|
|
185
284
|
No schema available
|
|
186
285
|
</p>
|
|
187
|
-
</
|
|
286
|
+
</Card>
|
|
188
287
|
|
|
189
288
|
<!-- Items Rendering -->
|
|
190
289
|
<template v-else>
|
|
290
|
+
<!-- Empty Array Message -->
|
|
291
|
+
<Card v-if="internalData.length === 0" class="py-1 border mb-05">
|
|
292
|
+
<p class="opacity-7 txt-center txt14">
|
|
293
|
+
No {{ label?.toLowerCase() || 'items' }} added yet
|
|
294
|
+
</p>
|
|
295
|
+
<!-- Load defaults button if defaultValue exists -->
|
|
296
|
+
<Btn v-if="props.defaultValue && props.defaultValue.length > 0" thin color="primary" class="txt12 mb-05" @click="loadDefaults">
|
|
297
|
+
Load Default {{ label || 'Items' }}
|
|
298
|
+
</Btn>
|
|
299
|
+
</Card>
|
|
300
|
+
|
|
191
301
|
<!-- Array Items -->
|
|
192
302
|
<div
|
|
193
303
|
v-for="(item, i) in internalData"
|
|
194
304
|
:key="i"
|
|
195
305
|
outline
|
|
196
306
|
thin
|
|
197
|
-
class="mb-05 itemBox transition
|
|
307
|
+
class="mb-05 itemBox transition radius-05 overflow-hidden txt12 border"
|
|
308
|
+
style="--input-font-size: 12px"
|
|
198
309
|
:class="{ minimized: minimizedItems[i] }"
|
|
199
310
|
>
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
311
|
+
<div>
|
|
312
|
+
<!-- Minimized View -->
|
|
313
|
+
<div class="flex pointer">
|
|
314
|
+
<p class="minimizedText txt12 p-05 opacity-7 flex-grow-2" @click="toggleMinimized(i)">
|
|
315
|
+
{{ label }} {{ i + 1 }}
|
|
316
|
+
</p>
|
|
317
|
+
<Btn v-if="showMinimizeButton" class="rotate-180 txt10 opacity-7 p-025" flat thin icon="keyboard_arrow_down" @click="toggleMinimized(i)" />
|
|
318
|
+
</div>
|
|
204
319
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
:schema="resolvedSchemaData"
|
|
210
|
-
@update:model-value="val => updateItem(i, val)"
|
|
211
|
-
/>
|
|
212
|
-
|
|
213
|
-
<!-- Controls -->
|
|
214
|
-
<div class="bg-gray-80 -my-05 px-025 pt-065 pb-05 txt-center space-between flex column">
|
|
215
|
-
<Btn
|
|
216
|
-
v-if="showMinimizeButton"
|
|
217
|
-
class="block rotate-180 txt10 opacity-7 p-025"
|
|
218
|
-
flat
|
|
219
|
-
thin
|
|
220
|
-
icon="keyboard_arrow_down"
|
|
221
|
-
@click="toggleMinimized(i)"
|
|
222
|
-
/>
|
|
223
|
-
<Btn
|
|
224
|
-
v-if="props.delete"
|
|
225
|
-
icon="delete"
|
|
226
|
-
class="txt10 opacity-7"
|
|
227
|
-
thin
|
|
228
|
-
flat
|
|
229
|
-
@click="deleteItem(i)"
|
|
320
|
+
<!-- Form View -->
|
|
321
|
+
<BagelFormFA
|
|
322
|
+
v-if="!minimizedItems[i]" :model-value="isPrimitiveType ? { value: item } : item" :schema="resolvedSchemaData" class="bginputbg p-05 grid gap-05"
|
|
323
|
+
@update:model-value="val => updateItem(i, val)"
|
|
230
324
|
/>
|
|
325
|
+
<Btn v-if="props.delete" icon="delete" class="txt10 opacity-7" thin flat @click="deleteItem(i)" />
|
|
231
326
|
</div>
|
|
232
327
|
</div>
|
|
233
328
|
|
|
@@ -242,25 +337,34 @@ const showMinimizeButton = computed(() => {
|
|
|
242
337
|
|
|
243
338
|
<style>
|
|
244
339
|
.minimized {
|
|
245
|
-
height: 2.
|
|
340
|
+
height: 2.3rem;
|
|
246
341
|
overflow: hidden;
|
|
342
|
+
border-color: transparent !important;
|
|
343
|
+
|
|
247
344
|
}
|
|
345
|
+
|
|
248
346
|
.minimizedText {
|
|
249
|
-
display: none;
|
|
347
|
+
/* display: none; */
|
|
348
|
+
padding-top: 1rem !important;
|
|
250
349
|
}
|
|
350
|
+
|
|
251
351
|
.minimized .minimizedText {
|
|
252
352
|
display: block;
|
|
253
353
|
}
|
|
354
|
+
|
|
254
355
|
.minimized .rotate-180 {
|
|
255
356
|
transform: rotate(0deg);
|
|
256
357
|
}
|
|
358
|
+
|
|
257
359
|
.itemBox {
|
|
258
|
-
background: var(--
|
|
259
|
-
grid-template-columns: 1fr auto;
|
|
260
|
-
display: grid;
|
|
360
|
+
background: var(--btn-bg);
|
|
261
361
|
--label-font-size: 0.6rem;
|
|
262
362
|
--input-height: 30px;
|
|
263
|
-
--input-font-size:
|
|
363
|
+
--input-font-size: 7px;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.bginputbg {
|
|
367
|
+
background: var(--input-bg);
|
|
264
368
|
}
|
|
265
369
|
|
|
266
370
|
.pt-065 {
|
|
@@ -273,10 +377,16 @@ const showMinimizeButton = computed(() => {
|
|
|
273
377
|
.itemBox .custom-select .input {
|
|
274
378
|
background: var(--bgl-white) !important;
|
|
275
379
|
}
|
|
380
|
+
|
|
276
381
|
.itemBox .code-editor-wrap textarea {
|
|
277
382
|
background: transparent !important;
|
|
278
383
|
}
|
|
384
|
+
|
|
279
385
|
.itemBox .bagel-input {
|
|
280
386
|
margin-bottom: 0.15rem !important;
|
|
281
387
|
}
|
|
388
|
+
|
|
389
|
+
.itemBox .richtext-editor-content {
|
|
390
|
+
font-size: 1px !important;
|
|
391
|
+
}
|
|
282
392
|
</style>
|
|
@@ -17,7 +17,8 @@ const inputId = $computed(() => id || Math.random().toString(36).slice(7))
|
|
|
17
17
|
const checked = defineModel<T>('modelValue', { default: undefined })
|
|
18
18
|
|
|
19
19
|
onMounted(() => {
|
|
20
|
-
|
|
20
|
+
// Don't auto-restore defaultValue - let user control their own content
|
|
21
|
+
// if (checked.value === undefined) checked.value = defaultValue as T
|
|
21
22
|
})
|
|
22
23
|
</script>
|
|
23
24
|
|
|
@@ -38,7 +38,7 @@ const format = {
|
|
|
38
38
|
for (let i = 0; i < jsCode.length; i++) {
|
|
39
39
|
const char = jsCode[i]
|
|
40
40
|
const nextChar = jsCode[i + 1]
|
|
41
|
-
if (
|
|
41
|
+
if ('"' === char || '\'' === char || '`' === char) {
|
|
42
42
|
formatted += char
|
|
43
43
|
if (inString.length && inString === char) {
|
|
44
44
|
inString = ''
|
|
@@ -51,25 +51,25 @@ const format = {
|
|
|
51
51
|
formatted += char
|
|
52
52
|
continue
|
|
53
53
|
}
|
|
54
|
-
if (
|
|
54
|
+
if ('{' === char || '[' === char) {
|
|
55
55
|
formatted += `${char}\n${tab.repeat(++level)}`
|
|
56
56
|
continue
|
|
57
57
|
}
|
|
58
|
-
if (
|
|
58
|
+
if ('}' === char || ']' === char) {
|
|
59
59
|
formatted += `\n${tab.repeat(--level)}${char}`
|
|
60
60
|
continue
|
|
61
61
|
}
|
|
62
|
-
if (
|
|
62
|
+
if (';' === char || ',' === char) {
|
|
63
63
|
formatted += `${char}\n${tab.repeat(level)}`
|
|
64
64
|
continue
|
|
65
65
|
}
|
|
66
|
-
if (
|
|
66
|
+
if ('\n' === char) {
|
|
67
67
|
formatted += `\n${tab.repeat(level)}`
|
|
68
68
|
continue
|
|
69
69
|
}
|
|
70
70
|
if (
|
|
71
|
-
(
|
|
72
|
-
|| (
|
|
71
|
+
(')' === char && '{' === nextChar)
|
|
72
|
+
|| (')' === char && ' ' === nextChar)
|
|
73
73
|
) {
|
|
74
74
|
formatted += `${char}\n${tab.repeat(level)}`
|
|
75
75
|
continue
|
|
@@ -14,8 +14,8 @@ export function useHighlight(theme: HighlightTheme = 'dark') {
|
|
|
14
14
|
const currentTheme = ref<HighlightTheme>(theme)
|
|
15
15
|
|
|
16
16
|
const normalizeTheme = (t: HighlightTheme): HighlightTheme => {
|
|
17
|
-
if (
|
|
18
|
-
if (
|
|
17
|
+
if ('dark' === t) {return 'atom-one-dark'}
|
|
18
|
+
if ('light' === t) {return 'atom-one-light'}
|
|
19
19
|
return t
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -24,14 +24,14 @@ export function useHighlight(theme: HighlightTheme = 'dark') {
|
|
|
24
24
|
const removeExistingThemeLinks = () => {
|
|
25
25
|
document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
|
|
26
26
|
if (link instanceof HTMLLinkElement && link.href.includes('/styles/')) {
|
|
27
|
-
if (link.href.includes('highlight.js')) link.parentElement?.removeChild(link)
|
|
27
|
+
if (link.href.includes('highlight.js')) {link.parentElement?.removeChild(link)}
|
|
28
28
|
}
|
|
29
29
|
})
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const setTheme = async (theme: HighlightTheme) => {
|
|
33
33
|
const next = normalizeTheme(theme)
|
|
34
|
-
if (next === currentTheme.value) return
|
|
34
|
+
if (next === currentTheme.value) {return}
|
|
35
35
|
try {
|
|
36
36
|
removeExistingThemeLinks()
|
|
37
37
|
const url = getThemeCssUrl(next)
|
|
@@ -48,7 +48,7 @@ export function useHighlight(theme: HighlightTheme = 'dark') {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const loadHighlight = async () => {
|
|
51
|
-
if (loaded.value) return
|
|
51
|
+
if (loaded.value) {return}
|
|
52
52
|
|
|
53
53
|
try {
|
|
54
54
|
// Load highlight.js
|
|
@@ -80,7 +80,7 @@ export function useHighlight(theme: HighlightTheme = 'dark') {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const highlightCode = (code: string, language?: string, autodetect = true, ignoreIllegals = true) => {
|
|
83
|
-
if (!hljs.value) return escapeHtml(code)
|
|
83
|
+
if (!hljs.value) {return escapeHtml(code)}
|
|
84
84
|
|
|
85
85
|
try {
|
|
86
86
|
const lang = language || ''
|
|
@@ -45,7 +45,7 @@ const isOpen = ref(false)
|
|
|
45
45
|
// Date formatting composable
|
|
46
46
|
function useFormatting() {
|
|
47
47
|
const formatDisplayDate = (date: Date | string | undefined): string => {
|
|
48
|
-
if (!date) return ''
|
|
48
|
+
if (!date) {return ''}
|
|
49
49
|
return formatDate(date, { fmt: props.enableTime ? 'DD.MM.YY HH:mm' : 'DD.MM.YY' })
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -58,7 +58,7 @@ function useFormatting() {
|
|
|
58
58
|
|
|
59
59
|
// Try DD/MM/YYYY format
|
|
60
60
|
const parts = input.split(/[/.-]/)
|
|
61
|
-
if (parts.length
|
|
61
|
+
if (3 === parts.length) {
|
|
62
62
|
const [day, month, year] = parts.map(p => Number.parseInt(p, 10))
|
|
63
63
|
if (!Number.isNaN(day) && !Number.isNaN(month) && !Number.isNaN(year)) {
|
|
64
64
|
const parsedDate = new Date(year, month - 1, day)
|
|
@@ -79,12 +79,12 @@ function useFormatting() {
|
|
|
79
79
|
if (props.enableTime) {
|
|
80
80
|
// Keep the time when time is enabled
|
|
81
81
|
return date.toISOString()
|
|
82
|
-
}
|
|
82
|
+
}
|
|
83
83
|
// Normalize to midnight to emit exact date without time for server compatibility
|
|
84
84
|
const normalizedDate = new Date(date)
|
|
85
85
|
normalizedDate.setHours(0, 0, 0, 0)
|
|
86
86
|
return normalizedDate.toISOString().split('T')[0]
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
return {
|
|
@@ -123,9 +123,9 @@ function useInputHandling() {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
const handleKeydown = (event: KeyboardEvent) => {
|
|
126
|
-
if (event.key
|
|
126
|
+
if ('Escape' === event.key) {
|
|
127
127
|
isOpen.value = false
|
|
128
|
-
} else if (event.key
|
|
128
|
+
} else if ('Enter' === event.key && inputValue.value) {
|
|
129
129
|
const date = parseUserInput(inputValue.value)
|
|
130
130
|
if (date) {
|
|
131
131
|
selectedDate.value = normalizeDate(date)
|
|
@@ -40,34 +40,34 @@ const time = new Time(props.firstDayOfWeek, props.locale)
|
|
|
40
40
|
|
|
41
41
|
// Parse a date string or object into a Date object
|
|
42
42
|
function parseDate(value: string | Date | undefined): Date | null {
|
|
43
|
-
if (!value) return null
|
|
44
|
-
const date = typeof value
|
|
43
|
+
if (!value) {return null}
|
|
44
|
+
const date = 'string' === typeof value ? new Date(value) : value
|
|
45
45
|
return Number.isNaN(date.getTime()) ? null : date
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Date validation composable
|
|
49
49
|
function useDateValidation() {
|
|
50
50
|
const isDateDisabled = (date: Date | null) => {
|
|
51
|
-
if (!date) return true
|
|
51
|
+
if (!date) {return true}
|
|
52
52
|
const minDate = parseDate(props.min)
|
|
53
53
|
const maxDate = parseDate(props.max)
|
|
54
54
|
|
|
55
55
|
// Check if date is in min/max range
|
|
56
|
-
if (minDate && date < minDate) return true
|
|
57
|
-
if (maxDate && date > maxDate) return true
|
|
56
|
+
if (minDate && date < minDate) {return true}
|
|
57
|
+
if (maxDate && date > maxDate) {return true}
|
|
58
58
|
|
|
59
59
|
// Check if date is in the disabled dates array
|
|
60
|
-
if (Array.isArray(computedDisabledDates) && computedDisabledDates.length
|
|
60
|
+
if (Array.isArray(computedDisabledDates) && 0 < computedDisabledDates.length) {
|
|
61
61
|
const isInDisabledDates = computedDisabledDates.some((disabledDate) => {
|
|
62
62
|
const parsedDisabledDate = parseDate(disabledDate)
|
|
63
|
-
if (!parsedDisabledDate) return false
|
|
63
|
+
if (!parsedDisabledDate) {return false}
|
|
64
64
|
|
|
65
65
|
// Compare year, month, and day
|
|
66
66
|
return date.getFullYear() === parsedDisabledDate.getFullYear()
|
|
67
67
|
&& date.getMonth() === parsedDisabledDate.getMonth()
|
|
68
68
|
&& date.getDate() === parsedDisabledDate.getDate()
|
|
69
69
|
})
|
|
70
|
-
if (isInDisabledDates) return true
|
|
70
|
+
if (isInDisabledDates) {return true}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
return false
|
|
@@ -77,8 +77,8 @@ function useDateValidation() {
|
|
|
77
77
|
const minDate = parseDate(props.min)
|
|
78
78
|
const maxDate = parseDate(props.max)
|
|
79
79
|
|
|
80
|
-
if (minDate && year < minDate.getFullYear()) return true
|
|
81
|
-
if (maxDate && year > maxDate.getFullYear()) return true
|
|
80
|
+
if (minDate && year < minDate.getFullYear()) {return true}
|
|
81
|
+
if (maxDate && year > maxDate.getFullYear()) {return true}
|
|
82
82
|
return false
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -114,7 +114,7 @@ function useCalendarView() {
|
|
|
114
114
|
|
|
115
115
|
// Always ensure we have 6 rows (42 days) in our calendar
|
|
116
116
|
// If we have less than 6 weeks, add extra week(s) from the next month
|
|
117
|
-
while (weeksInMonth.length
|
|
117
|
+
while (6 > weeksInMonth.length) {
|
|
118
118
|
const lastWeek = weeksInMonth[weeksInMonth.length - 1]
|
|
119
119
|
const lastDay = lastWeek[lastWeek.length - 1]
|
|
120
120
|
const nextDay = new Date(lastDay.getFullYear(), lastDay.getMonth(), lastDay.getDate() + 1)
|
|
@@ -163,14 +163,14 @@ function useCalendarView() {
|
|
|
163
163
|
})
|
|
164
164
|
|
|
165
165
|
const isSelected = (date: Date | null) => {
|
|
166
|
-
if (!date || !selectedDate.value) return false
|
|
166
|
+
if (!date || !selectedDate.value) {return false}
|
|
167
167
|
return date.getFullYear() === selectedDate.value.getFullYear()
|
|
168
168
|
&& date.getMonth() === selectedDate.value.getMonth()
|
|
169
169
|
&& date.getDate() === selectedDate.value.getDate()
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
const isToday = (date: Date | null) => {
|
|
173
|
-
if (!date) return false
|
|
173
|
+
if (!date) {return false}
|
|
174
174
|
return time.dateIsToday(date)
|
|
175
175
|
}
|
|
176
176
|
|
|
@@ -190,7 +190,7 @@ function useCalendarView() {
|
|
|
190
190
|
|
|
191
191
|
return computedHighlightedDates.some((highlightedDate) => {
|
|
192
192
|
const parsedDate = parseDate(highlightedDate)
|
|
193
|
-
if (!parsedDate) return false
|
|
193
|
+
if (!parsedDate) {return false}
|
|
194
194
|
|
|
195
195
|
// Compare year, month, and day
|
|
196
196
|
return date.getFullYear() === parsedDate.getFullYear()
|
|
@@ -233,12 +233,12 @@ function useNavigation() {
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
const previousYear = () => {
|
|
236
|
-
const offset = currentView.value
|
|
236
|
+
const offset = 'months' === currentView.value ? 1 : 21
|
|
237
237
|
currentMonth.value = new Date(currentMonth.value.getFullYear() - offset, currentMonth.value.getMonth(), 1)
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
const nextYear = () => {
|
|
241
|
-
const offset = currentView.value
|
|
241
|
+
const offset = 'months' === currentView.value ? 1 : 21
|
|
242
242
|
currentMonth.value = new Date(currentMonth.value.getFullYear() + offset, currentMonth.value.getMonth(), 1)
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -258,14 +258,14 @@ function useTimeHandling() {
|
|
|
258
258
|
const minutes = computed(() => selectedDate.value?.getMinutes() ?? 0)
|
|
259
259
|
|
|
260
260
|
const handleHourInput = (value: number) => {
|
|
261
|
-
if (!selectedDate.value) return
|
|
261
|
+
if (!selectedDate.value) {return}
|
|
262
262
|
const newDate = new Date(selectedDate.value)
|
|
263
263
|
newDate.setHours(value)
|
|
264
264
|
emitDateValue(newDate)
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
const handleMinuteInput = (value: number) => {
|
|
268
|
-
if (!selectedDate.value) return
|
|
268
|
+
if (!selectedDate.value) {return}
|
|
269
269
|
const newDate = new Date(selectedDate.value)
|
|
270
270
|
newDate.setMinutes(value)
|
|
271
271
|
emitDateValue(newDate)
|
|
@@ -308,7 +308,7 @@ const { hours, minutes, handleHourInput, handleMinuteInput } = useTimeHandling()
|
|
|
308
308
|
|
|
309
309
|
// Date selection handler
|
|
310
310
|
function selectDate(date: Date | null) {
|
|
311
|
-
if (!date) return
|
|
311
|
+
if (!date) {return}
|
|
312
312
|
|
|
313
313
|
if (props.enableTime) {
|
|
314
314
|
// Create date with current time values
|