@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
|
@@ -5,7 +5,7 @@ import { watch, ref } from 'vue'
|
|
|
5
5
|
|
|
6
6
|
import { useFileUpload } from './useFileUpload'
|
|
7
7
|
|
|
8
|
-
const props = withDefaults(defineProps<UploadInputProps & { showIcon?: boolean
|
|
8
|
+
const props = withDefaults(defineProps<UploadInputProps & { showIcon?: boolean, icon?: string }>(), {
|
|
9
9
|
height: '215px',
|
|
10
10
|
theme: 'dropzone',
|
|
11
11
|
accept: '*',
|
|
@@ -44,16 +44,16 @@ const isDragOver = ref(false)
|
|
|
44
44
|
function handleDrag(e: DragEvent, isDragging = false) {
|
|
45
45
|
e.preventDefault()
|
|
46
46
|
e.stopPropagation()
|
|
47
|
-
if (!props.disabled) isDragOver.value = isDragging
|
|
47
|
+
if (!props.disabled) { isDragOver.value = isDragging }
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function updateModelValue() {
|
|
51
|
-
if (props.multiple) emit('update:modelValue', pathKeys.value)
|
|
52
|
-
else emit('update:modelValue', pathKeys.value[0] || undefined)
|
|
51
|
+
if (props.multiple) { emit('update:modelValue', pathKeys.value) }
|
|
52
|
+
else { emit('update:modelValue', pathKeys.value[0] || undefined) }
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
async function handleDrop(e: DragEvent) {
|
|
56
|
-
if (props.disabled) return
|
|
56
|
+
if (props.disabled) { return }
|
|
57
57
|
e.preventDefault()
|
|
58
58
|
e.stopPropagation()
|
|
59
59
|
emit('addFileStart')
|
|
@@ -62,114 +62,167 @@ async function handleDrop(e: DragEvent) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function fileName(pathKey: string) {
|
|
65
|
-
if (!pathKey || typeof pathKey !== 'string') return 'file'
|
|
65
|
+
if (!pathKey || typeof pathKey !== 'string') { return 'file' }
|
|
66
66
|
return pathKey.split('/').pop() || 'file'
|
|
67
67
|
}
|
|
68
68
|
</script>
|
|
69
69
|
|
|
70
70
|
<template>
|
|
71
|
-
<div class="bagel-input">
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
71
|
+
<div class="bagel-input">
|
|
72
|
+
<label v-if="label">{{ label }}</label>
|
|
73
|
+
<input v-if="required && !pathKeys.length" placeholder="required" type="text" required class="pixel">
|
|
74
|
+
<Card
|
|
75
|
+
v-if="theme === 'basic'" outline class="flex p-05 gap-1" @dragover="(e) => handleDrag(e, true)"
|
|
76
|
+
@drop="handleDrop"
|
|
77
|
+
>
|
|
78
|
+
<Btn
|
|
79
|
+
v-if="!pathKeys.length && !fileQueue.length" class="px-1-5" icon="upload" outline
|
|
80
|
+
:value="btnPlaceholder || 'Upload'" @click="browse()"
|
|
81
|
+
/>
|
|
82
|
+
<!-- Loading state during upload -->
|
|
83
|
+
<div v-if="fileQueue.length > 0" class="flex align-items-center gap-1 p-05">
|
|
84
|
+
<Loading size="20" />
|
|
85
|
+
<span class="txt-gray txt-12">
|
|
86
|
+
Uploading {{ fileQueue.length }} file{{ fileQueue.length > 1 ? 's' : '' }}...
|
|
87
|
+
</span>
|
|
88
|
+
</div>
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
<template v-for="path_key in pathKeys" :key="path_key">
|
|
91
|
+
<div class="txt-gray txt-12 flex">
|
|
92
|
+
<div class="m-05 flex opacity-8 z-99 gap-025">
|
|
93
|
+
<Btn v-tooltip="'Delete'" color="gray" thin icon="delete" @click="removeFile(path_key)" />
|
|
94
|
+
<Btn v-tooltip="'Replace'" color="gray" thin icon="autorenew" @click="browse()" />
|
|
95
|
+
<Btn
|
|
96
|
+
icon="download" color="gray" thin :href="pathKeyToURL(path_key)"
|
|
97
|
+
:download="fileName(path_key)"
|
|
98
|
+
/>
|
|
99
|
+
<div class="flex gap-025 rounded pe-1 ps-05 py-025 -my-1 ">
|
|
100
|
+
<Icon icon="draft" :size="1.5" />
|
|
101
|
+
<p
|
|
102
|
+
v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
|
|
103
|
+
class="ellipsis-1 word-break-all h-20 m-0 color-black txt16"
|
|
104
|
+
>
|
|
105
|
+
{{ fileName(path_key) }}
|
|
106
|
+
</p>
|
|
95
107
|
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<span v-if="!pathKeys.length && !fileQueue.length" class="txt-gray txt-12">
|
|
113
|
+
{{ noFilePlaceholder || 'No file selected' }}
|
|
114
|
+
</span>
|
|
115
|
+
</Card>
|
|
116
|
+
|
|
117
|
+
<div
|
|
118
|
+
v-else class="fileUploadWrap" :class="{
|
|
119
|
+
'fileDropZone': !pathKeys.length && !fileQueue.length,
|
|
120
|
+
'dragover': isDragOver,
|
|
121
|
+
'bgl_oval-upload': oval,
|
|
122
|
+
}" :style="{ width, height }" @click="browse()" @dragover="(e) => handleDrag(e, true)" @drop="handleDrop"
|
|
123
|
+
@dragleave="(e) => handleDrag(e)"
|
|
124
|
+
>
|
|
125
|
+
<slot name="files" :files="pathKeys" :fileQueue>
|
|
126
|
+
<div v-if="multiple" class="bgl-multi-preview">
|
|
127
|
+
<!-- Show uploaded files only if showFileList is true (default) -->
|
|
128
|
+
<template v-if="showFileList !== false">
|
|
129
|
+
<div
|
|
130
|
+
v-for="path_key in pathKeys" :key="path_key"
|
|
131
|
+
v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
|
|
132
|
+
class="multi-image-item-preview" :class="{ 'bgl_fill-image': fill }"
|
|
133
|
+
>
|
|
134
|
+
<Image v-if="isImage(path_key)" :pathKey="path_key" class="multi-preview" />
|
|
135
|
+
<Icon v-else icon="description" class="multi-preview" />
|
|
136
|
+
<p class="m-0">
|
|
137
|
+
{{ fileName(path_key) }}
|
|
138
|
+
</p>
|
|
139
|
+
<Btn thin flat icon="delete" color="red" @click="removeFile(path_key)" />
|
|
96
140
|
</div>
|
|
141
|
+
</template>
|
|
142
|
+
<!-- File count indicator when showFileList is false and multiple files -->
|
|
143
|
+
<div v-if="showFileList === false && pathKeys.length > 0" class="flex column gap-05 pt-1">
|
|
144
|
+
<p class="color-primary">
|
|
145
|
+
{{ pathKeys.length }} file{{ pathKeys.length > 1 ? 's' : '' }} uploaded
|
|
146
|
+
</p>
|
|
147
|
+
<Btn color="primary" thin icon="autorenew" value="Replace files" @click="browse()" />
|
|
148
|
+
</div>
|
|
149
|
+
<div
|
|
150
|
+
v-for="file in fileQueue" :key="file.name" class="multi-image-item-preview"
|
|
151
|
+
:class="{ 'bgl_fill-image': fill }"
|
|
152
|
+
>
|
|
153
|
+
<img v-if="isImage(file.file.type)" class="multi-preview" :src="file.url" alt="">
|
|
154
|
+
<Icon v-else icon="description" class="multi-preview" />
|
|
155
|
+
<p class="no-margin multi-preview-txt">
|
|
156
|
+
{{ file.name }}
|
|
157
|
+
</p>
|
|
158
|
+
<div
|
|
159
|
+
class="pie" :style="{ '--p': file.progress }" style="--b: 2px"
|
|
160
|
+
:class="{ complete: file.progress === 100 }"
|
|
161
|
+
>
|
|
162
|
+
<span v-if="file.progress < 100" class="progress">
|
|
163
|
+
{{ file.progress.toFixed(0) }}
|
|
164
|
+
</span>
|
|
165
|
+
<Icon class="success" icon="check_circle" />
|
|
97
166
|
</div>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
</p>
|
|
120
|
-
<Btn thin flat icon="delete" color="red" @click="removeFile(path_key)" />
|
|
121
|
-
</div>
|
|
122
|
-
<!-- File count indicator when showFileList is false and multiple files -->
|
|
123
|
-
<div v-if="showFileList === false && pathKeys.length > 0" class="flex column gap-05 pt-1">
|
|
124
|
-
<p class="color-primary">
|
|
125
|
-
{{ pathKeys.length }} file{{ pathKeys.length > 1 ? 's' : '' }} uploaded
|
|
126
|
-
</p>
|
|
127
|
-
<Btn color="primary" thin icon="autorenew" value="Replace files" @click="browse()" />
|
|
128
|
-
</div>
|
|
129
|
-
<div v-for="file in fileQueue" :key="file.name" class="multi-image-item-preview" :class="{ 'bgl_fill-image': fill }">
|
|
130
|
-
<img v-if="isImage(file.file.type)" class="multi-preview" :src="file.url" alt="">
|
|
131
|
-
<Icon v-else icon="description" class="multi-preview" />
|
|
132
|
-
<p class="no-margin multi-preview-txt">
|
|
133
|
-
{{ file.name }}
|
|
134
|
-
</p>
|
|
135
|
-
<div class="pie" :style="{ '--p': file.progress }" style="--b: 2px" :class="{ complete: file.progress === 100 }">
|
|
136
|
-
<span v-if="file.progress < 100" class="progress">
|
|
137
|
-
{{ file.progress.toFixed(0) }}
|
|
138
|
-
</span>
|
|
139
|
-
<Icon class="success" icon="check_circle" />
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
</div>
|
|
143
|
-
|
|
144
|
-
<div v-else-if="pathKeys.length > 0 || fileQueue.length > 0" class="bgl-single-preview">
|
|
145
|
-
<div v-for="path_key in pathKeys" :key="path_key" class="single-image-item-preview" :class="{ 'bgl_fill-image': fill }">
|
|
146
|
-
<div class="flex opacity-8 z-99 gap-025 absolute top-0 start-0" :class="{ 'mx-auto end-0 mt-1 justify-content-center': oval, 'm-05': !oval }">
|
|
147
|
-
<Btn v-tooltip="'Delete'" color="white" frame thin icon="delete" @click="removeFile(path_key)" />
|
|
148
|
-
<Btn v-tooltip="'Replace'" color="white" frame thin icon="autorenew" @click="browse()" />
|
|
149
|
-
<Btn v-tooltip="'Download'" color="white" frame thin icon="download" :href="pathKeyToURL(path_key)" :download="fileName(path_key)" />
|
|
150
|
-
</div>
|
|
151
|
-
<div v-if="isImage(path_key)" class="h-100">
|
|
152
|
-
<Image v-lightbox="{ src: pathKeyToURL(path_key), download: true }" class="single-preview" :pathKey="path_key" alt="" />
|
|
153
|
-
</div>
|
|
154
|
-
<Icon v-else v-lightbox="{ src: pathKeyToURL(path_key), download: true }" :size="4" weight="2" icon="description" class="color-primary w-100" />
|
|
155
|
-
</div>
|
|
156
|
-
<div v-for="file in fileQueue" :key="file.name" class="single-image-item-preview" :class="{ 'bgl_fill-image': fill }">
|
|
157
|
-
<Loading type="bar" :progress="file.progress" class="absolute bottom-05 end start w-100px mx-auto rounded overflow-hidden" />
|
|
158
|
-
<img v-if="isImage(file.file.type)" class="single-preview opacity-5" :src="file.url" alt="">
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
</slot>
|
|
162
|
-
|
|
163
|
-
<slot v-if="(!pathKeys.length && !fileQueue.length) || multiple" name="placeholder" :files="pathKeys" :fileQueue :browse>
|
|
164
|
-
<p class="p-1 flex column hover fileUploadPlaceHolder justify-content-center mb-05 ">
|
|
165
|
-
<Icon v-if="showIcon" :name="icon" class="user-select-none" />
|
|
166
|
-
<span class=" pretty balance user-select-none ">
|
|
167
|
-
{{ dropPlaceholder || 'Drag and Drop files here or click to upload' }}
|
|
168
|
-
</span>
|
|
169
|
-
</p>
|
|
170
|
-
</slot>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<div v-else-if="pathKeys.length > 0 || fileQueue.length > 0" class="bgl-single-preview">
|
|
171
|
+
<div
|
|
172
|
+
v-for="path_key in pathKeys" :key="path_key" class="single-image-item-preview"
|
|
173
|
+
:class="{ 'bgl_fill-image': fill }"
|
|
174
|
+
>
|
|
175
|
+
<div
|
|
176
|
+
class="flex opacity-8 z-99 gap-025 absolute top-0 start-0"
|
|
177
|
+
:class="{ 'mx-auto end-0 mt-1 justify-content-center': oval, 'm-05': !oval }"
|
|
178
|
+
>
|
|
179
|
+
<Btn
|
|
180
|
+
v-tooltip="'Delete'" color="white" frame thin icon="delete"
|
|
181
|
+
@click="removeFile(path_key)"
|
|
182
|
+
/>
|
|
183
|
+
<Btn v-tooltip="'Replace'" color="white" frame thin icon="autorenew" @click="browse()" />
|
|
184
|
+
<Btn
|
|
185
|
+
v-tooltip="'Download'" color="white" frame thin icon="download"
|
|
186
|
+
:href="pathKeyToURL(path_key)" :download="fileName(path_key)"
|
|
187
|
+
/>
|
|
171
188
|
</div>
|
|
189
|
+
<div v-if="isImage(path_key)" class="h-100">
|
|
190
|
+
<Image
|
|
191
|
+
v-lightbox="{ src: pathKeyToURL(path_key), download: true }" class="single-preview"
|
|
192
|
+
:pathKey="path_key" alt=""
|
|
193
|
+
/>
|
|
172
194
|
</div>
|
|
195
|
+
<Icon
|
|
196
|
+
v-else v-lightbox="{ src: pathKeyToURL(path_key), download: true }" :size="4" weight="2"
|
|
197
|
+
icon="description" class="color-primary w-100"
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
<div
|
|
201
|
+
v-for="file in fileQueue" :key="file.name" class="single-image-item-preview"
|
|
202
|
+
:class="{ 'bgl_fill-image': fill }"
|
|
203
|
+
>
|
|
204
|
+
<Loading
|
|
205
|
+
type="bar" :progress="file.progress"
|
|
206
|
+
class="absolute bottom-05 end start w-100px mx-auto rounded overflow-hidden"
|
|
207
|
+
/>
|
|
208
|
+
<img v-if="isImage(file.file.type)" class="single-preview opacity-5" :src="file.url" alt="">
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</slot>
|
|
212
|
+
|
|
213
|
+
<slot
|
|
214
|
+
v-if="(!pathKeys.length && !fileQueue.length) || multiple" name="placeholder" :files="pathKeys"
|
|
215
|
+
:fileQueue :browse
|
|
216
|
+
>
|
|
217
|
+
<p class="p-1 flex column hover fileUploadPlaceHolder justify-content-center mb-05 ">
|
|
218
|
+
<Icon v-if="showIcon" :name="icon" class="user-select-none" />
|
|
219
|
+
<span class=" pretty balance user-select-none ">
|
|
220
|
+
{{ dropPlaceholder || 'Drag and Drop files here or click to upload' }}
|
|
221
|
+
</span>
|
|
222
|
+
</p>
|
|
223
|
+
</slot>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
173
226
|
</template>
|
|
174
227
|
|
|
175
228
|
<style src="./upload.css" scoped></style>
|
|
@@ -8,7 +8,7 @@ const getFileVersion = () => getBagelInstance()?.fileVersion ?? 'files_v2'
|
|
|
8
8
|
|
|
9
9
|
export const files = {
|
|
10
10
|
setBaseUrl: (baseUrl?: string) => {
|
|
11
|
-
if (baseUrl === undefined ||
|
|
11
|
+
if (baseUrl === undefined || '' === baseUrl) {return}
|
|
12
12
|
baseUrl = baseUrl.replace(/\/$/, '')
|
|
13
13
|
axios.defaults.baseURL = baseUrl
|
|
14
14
|
},
|
|
@@ -32,7 +32,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
32
32
|
const fileToUrl = (file: File) => URL.createObjectURL(file)
|
|
33
33
|
|
|
34
34
|
function addFile(file?: File | File[] | FileList | null) {
|
|
35
|
-
if (!file) return
|
|
35
|
+
if (!file) {return}
|
|
36
36
|
|
|
37
37
|
let filesToAdd: File[] = []
|
|
38
38
|
|
|
@@ -58,18 +58,18 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Call the onFilesQueued callback if provided
|
|
61
|
-
if (props.onFileQueued && newQueueFiles.length
|
|
61
|
+
if (props.onFileQueued && 0 < newQueueFiles.length) {
|
|
62
62
|
props.onFileQueued(newQueueFiles)
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
async function removeFile(pathKeyOrFile: string | File | QueueFile) {
|
|
67
|
-
if (typeof pathKeyOrFile
|
|
67
|
+
if ('string' === typeof pathKeyOrFile) {
|
|
68
68
|
// Remove from both lists
|
|
69
69
|
storageFiles.value = storageFiles.value.filter(file => file.path_key !== pathKeyOrFile)
|
|
70
70
|
|
|
71
71
|
const pathKeyIndex = pk.value.indexOf(pathKeyOrFile)
|
|
72
|
-
if (
|
|
72
|
+
if (-1 !== pathKeyIndex) {
|
|
73
73
|
pk.value.splice(pathKeyIndex, 1)
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -88,7 +88,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
88
88
|
&& queueFile.namespace === namespace
|
|
89
89
|
)
|
|
90
90
|
|
|
91
|
-
if (
|
|
91
|
+
if (-1 !== index) {
|
|
92
92
|
fileQueue.value.splice(index, 1)
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -124,7 +124,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
124
124
|
|
|
125
125
|
// UI interaction
|
|
126
126
|
function browse(autoFlush = false) {
|
|
127
|
-
if (props.disabled) return
|
|
127
|
+
if (props.disabled) {return}
|
|
128
128
|
|
|
129
129
|
const input = document.createElement('input')
|
|
130
130
|
input.type = 'file'
|
|
@@ -13,11 +13,11 @@ export interface BagelFormState<T> {
|
|
|
13
13
|
|
|
14
14
|
// Helper function to safely clone objects without circular references
|
|
15
15
|
function safeClone(obj: any): any {
|
|
16
|
-
if (
|
|
16
|
+
if (null === obj || 'object' !== typeof obj) {return obj}
|
|
17
17
|
|
|
18
18
|
const seen = new WeakSet()
|
|
19
19
|
return JSON.parse(JSON.stringify(obj, (key, value) => {
|
|
20
|
-
if (
|
|
20
|
+
if ('object' === typeof value && null !== value) {
|
|
21
21
|
if (seen.has(value)) {
|
|
22
22
|
return undefined // Remove circular reference
|
|
23
23
|
}
|
|
@@ -37,7 +37,7 @@ export function provideBagelFormState<T>(initialData: T) {
|
|
|
37
37
|
const keys = path.split(/[.[]/)
|
|
38
38
|
|
|
39
39
|
// Initialize the root if it's not an object
|
|
40
|
-
if (typeof data.value
|
|
40
|
+
if ('object' !== typeof data.value || null === data.value) {
|
|
41
41
|
data.value = {} as T
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -46,7 +46,7 @@ export function provideBagelFormState<T>(initialData: T) {
|
|
|
46
46
|
// Build the path, ensuring each level is an object
|
|
47
47
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
48
48
|
const key = keys[i]
|
|
49
|
-
if (!(key in current) || typeof current[key]
|
|
49
|
+
if (!(key in current) || 'object' !== typeof current[key] || null === current[key]) {
|
|
50
50
|
current[key] = {}
|
|
51
51
|
}
|
|
52
52
|
current = current[key]
|
|
@@ -71,6 +71,6 @@ export function provideBagelFormState<T>(initialData: T) {
|
|
|
71
71
|
|
|
72
72
|
export function useBagelFormState<T>(injectionKey: typeof FORM_STATE_KEY = FORM_STATE_KEY): BagelFormState<T> {
|
|
73
73
|
const state = inject<BagelFormState<T>>(injectionKey)
|
|
74
|
-
if (!state) throw new Error('BagelFormState must be provided')
|
|
74
|
+
if (!state) {throw new Error('BagelFormState must be provided')}
|
|
75
75
|
return state
|
|
76
76
|
}
|
|
@@ -31,7 +31,7 @@ const sidebarCardStyle = inject('sidebarCardStyle', { value: false })
|
|
|
31
31
|
const hasSidebarCard = computed(() => {
|
|
32
32
|
// Check if there's an AppSidebar with card class in the DOM
|
|
33
33
|
const sidebar = document.querySelector('.app-sidebar .card')
|
|
34
|
-
return
|
|
34
|
+
return null !== sidebar || sidebarCardStyle?.value
|
|
35
35
|
})
|
|
36
36
|
</script>
|
|
37
37
|
|
|
@@ -20,19 +20,19 @@ const props = withDefaults(defineProps<LayoutProrps>(), {
|
|
|
20
20
|
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
const gridTemplateRows = $computed(() => (props.rows.length
|
|
23
|
+
const gridTemplateRows = $computed(() => (0 < props.rows.length ? props.rows.join(' ') : 'auto'))
|
|
24
24
|
const gapSize = $computed(() => `${props.gap}rem`)
|
|
25
25
|
const mGapSize = $computed(() => props.mGap !== undefined ? `${props.mGap}rem` : gapSize)
|
|
26
26
|
|
|
27
27
|
const mGridTemplateRows = $computed(() => {
|
|
28
|
-
if (props.mRows?.length) return props.mRows.join(' ')
|
|
28
|
+
if (props.mRows?.length) {return props.mRows.join(' ')}
|
|
29
29
|
return gridTemplateRows
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
const gridTemplateColumns = $computed(() => (props.columns.length
|
|
32
|
+
const gridTemplateColumns = $computed(() => (0 < props.columns.length ? props.columns.join(' ') : 'auto'))
|
|
33
33
|
|
|
34
34
|
const mGridTemplateColumns = $computed(() => {
|
|
35
|
-
if (props.mColumns?.length) return props.mColumns.join(' ')
|
|
35
|
+
if (props.mColumns?.length) {return props.mColumns.join(' ')}
|
|
36
36
|
return gridTemplateColumns
|
|
37
37
|
})
|
|
38
38
|
</script>
|
|
@@ -17,7 +17,7 @@ let activeTab = $ref<string>()
|
|
|
17
17
|
function changeTab(tab: string) {
|
|
18
18
|
activeTab = tab
|
|
19
19
|
emit('update:modelValue', activeTab)
|
|
20
|
-
if (!props.router) return
|
|
20
|
+
if (!props.router) {return}
|
|
21
21
|
void props.router.push({
|
|
22
22
|
path: props.router.currentRoute.value.path,
|
|
23
23
|
query: { ...props.router.currentRoute.value.query, t: tab },
|
|
@@ -17,7 +17,7 @@ const slots: SetupContext['slots'] = useSlots()
|
|
|
17
17
|
const group = Math.random().toString(36).slice(7)
|
|
18
18
|
const { currentTab } = useTabs(group)
|
|
19
19
|
|
|
20
|
-
const tabValue = (tab: Tab) => (typeof tab
|
|
20
|
+
const tabValue = (tab: Tab) => ('string' === typeof tab ? tab : tab.id)
|
|
21
21
|
|
|
22
22
|
const slctTab = $computed({
|
|
23
23
|
get: () => props.modelValue || tabValue(props.tabs[0]),
|
|
@@ -31,7 +31,7 @@ const tabComponent = defineComponent({
|
|
|
31
31
|
const currentTabIndex = props.tabs.findIndex(
|
|
32
32
|
tab => tabValue(tab) === currentTab.value
|
|
33
33
|
)
|
|
34
|
-
if (
|
|
34
|
+
if (-1 === currentTabIndex) {return}
|
|
35
35
|
const slotChildren = slots.default?.()[1]?.children
|
|
36
36
|
|
|
37
37
|
return h('div', (slotChildren as VNode[])[currentTabIndex])
|
|
@@ -23,7 +23,7 @@ const props = defineProps<{
|
|
|
23
23
|
const emit = defineEmits(['update:modelValue'])
|
|
24
24
|
const { currentTab } = useTabs(props.group)
|
|
25
25
|
currentTab.value
|
|
26
|
-
= props.modelValue || typeof props.tabs[0]
|
|
26
|
+
= props.modelValue || 'string' === typeof props.tabs[0]
|
|
27
27
|
? props.tabs[0]
|
|
28
28
|
: props.tabs[0].id
|
|
29
29
|
|
|
@@ -32,13 +32,13 @@ const tabs = ref<HTMLElement[]>([])
|
|
|
32
32
|
|
|
33
33
|
function updateIndicator() {
|
|
34
34
|
nextTick(() => {
|
|
35
|
-
if (!tabsWrap.value) return
|
|
35
|
+
if (!tabsWrap.value) {return}
|
|
36
36
|
const activeTab = tabs.value.find(tab => tab.classList.contains('active'))
|
|
37
37
|
if (activeTab) {
|
|
38
38
|
// Wait a bit more to ensure CSS is fully loaded and elements are properly sized
|
|
39
39
|
setTimeout(() => {
|
|
40
40
|
const { offsetLeft, offsetWidth } = activeTab
|
|
41
|
-
if (offsetLeft
|
|
41
|
+
if (0 <= offsetLeft && 0 < offsetWidth) { // Ensure valid measurements
|
|
42
42
|
tabsWrap.value?.style.setProperty('--indicator-left', `${offsetLeft}px`)
|
|
43
43
|
tabsWrap.value?.style.setProperty('--indicator-width', `${offsetWidth}px`)
|
|
44
44
|
tabsWrap.value?.style.setProperty('--indicator-opacity', '1')
|
|
@@ -49,25 +49,25 @@ function updateIndicator() {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function selectTab(tab: TabType | string) {
|
|
52
|
-
currentTab.value = typeof tab
|
|
52
|
+
currentTab.value = 'string' === typeof tab ? tab : tab.id
|
|
53
53
|
emit('update:modelValue', currentTab.value)
|
|
54
54
|
nextTick(() => { updateIndicator() })
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function isActive(tab: TabType | string) {
|
|
58
|
-
if (typeof tab
|
|
58
|
+
if ('string' === typeof tab) {return currentTab.value === tab}
|
|
59
59
|
return currentTab.value === tab.id
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function tabLabel(tab: TabType | string) {
|
|
63
|
-
if (typeof tab
|
|
63
|
+
if ('string' === typeof tab) {return tab}
|
|
64
64
|
return tab.label
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
watch(
|
|
68
68
|
() => props.modelValue,
|
|
69
69
|
(value) => {
|
|
70
|
-
if (value && !isActive(value)) currentTab.value = value
|
|
70
|
+
if (value && !isActive(value)) {currentTab.value = value}
|
|
71
71
|
nextTick(() => { updateIndicator() })
|
|
72
72
|
},
|
|
73
73
|
{ immediate: true }
|
|
@@ -22,14 +22,14 @@ function close() {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
function next() {
|
|
25
|
-
if (group.length
|
|
25
|
+
if (1 < group.length) {
|
|
26
26
|
currentIndex = (currentIndex + 1) % group.length
|
|
27
27
|
currentItem = group[currentIndex]
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function prev() {
|
|
32
|
-
if (group.length
|
|
32
|
+
if (1 < group.length) {
|
|
33
33
|
currentIndex = (currentIndex - 1 + group.length) % group.length
|
|
34
34
|
currentItem = group[currentIndex]
|
|
35
35
|
}
|
|
@@ -41,16 +41,16 @@ function selectItem(index: number) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
watch(() => isOpen, (val) => {
|
|
44
|
-
if (val) document.body.style.overflow = 'hidden'
|
|
45
|
-
else document.body.style.overflow = ''
|
|
44
|
+
if (val) {document.body.style.overflow = 'hidden'}
|
|
45
|
+
else {document.body.style.overflow = ''}
|
|
46
46
|
})
|
|
47
47
|
|
|
48
48
|
function handleKeydown(event: KeyboardEvent) {
|
|
49
|
-
if (event.key
|
|
49
|
+
if ('Escape' === event.key) {
|
|
50
50
|
close()
|
|
51
|
-
} else if (event.key
|
|
51
|
+
} else if ('ArrowLeft' === event.key) {
|
|
52
52
|
prev()
|
|
53
|
-
} else if (event.key
|
|
53
|
+
} else if ('ArrowRight' === event.key) {
|
|
54
54
|
next()
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -58,7 +58,7 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
58
58
|
const zoom = $ref(1)
|
|
59
59
|
|
|
60
60
|
function clickOutside() {
|
|
61
|
-
if (
|
|
61
|
+
if (1 === zoom) {close()}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
defineExpose({ open, close })
|
|
@@ -32,9 +32,9 @@ const lightboxDirective: Directive = {
|
|
|
32
32
|
|
|
33
33
|
function groupHandler(item: LightboxItem) {
|
|
34
34
|
if (item.group) {
|
|
35
|
-
if (!groups[item.group]) groups[item.group] = []
|
|
35
|
+
if (!groups[item.group]) {groups[item.group] = []}
|
|
36
36
|
const currentIndex = groups[item.group].findIndex(i => i.src === item.src)
|
|
37
|
-
if (
|
|
37
|
+
if (-1 === currentIndex) {groups[item.group].push(item)}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -42,7 +42,7 @@ function openClickHandler(e: MouseEvent, el: HTMLElement, binding: DirectiveBind
|
|
|
42
42
|
e.stopPropagation()
|
|
43
43
|
const item = bindingToItem(binding, el)
|
|
44
44
|
const lightboxInstance = getLightboxInstance()
|
|
45
|
-
if (!lightboxInstance || !lightboxInstance.open) return
|
|
45
|
+
if (!lightboxInstance || !lightboxInstance.open) {return}
|
|
46
46
|
const open = lightboxInstance.open as OpenFunction
|
|
47
47
|
const group = item && item.group ? groups[item.group] : undefined
|
|
48
48
|
open(item, group)
|
|
@@ -60,18 +60,18 @@ const youtubeRegex = /youtube\.com|youtu\.be/
|
|
|
60
60
|
const vimeoRegex = /vimeo\.com/
|
|
61
61
|
|
|
62
62
|
function urlToName(url: string): string {
|
|
63
|
-
if (!url || typeof url
|
|
63
|
+
if (!url || 'string' !== typeof url) {return ''}
|
|
64
64
|
const name = url.split('/').pop() || ''
|
|
65
65
|
return name.replace(/\.[^/.]+$/, '')
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function determineFileType(url: any): string {
|
|
69
|
-
if (typeof url
|
|
69
|
+
if ('string' !== typeof url || !url) {return 'unknown'}
|
|
70
70
|
const extension = (url.split('.').pop() || '').toLowerCase()
|
|
71
71
|
const altExtension = url.split('?')[0].split('.').pop()?.toLowerCase() || ''
|
|
72
|
-
if (IMAGE_FORMATS_REGEXP.test(extension) || IMAGE_FORMATS_REGEXP.test(altExtension)) return 'image'
|
|
73
|
-
if (VIDEO_FORMATS_REGEXP.test(extension) || youtubeRegex.test(url) || vimeoRegex.test(url)) return 'video'
|
|
74
|
-
if (['pdf'].includes(extension)) return 'pdf'
|
|
72
|
+
if (IMAGE_FORMATS_REGEXP.test(extension) || IMAGE_FORMATS_REGEXP.test(altExtension)) {return 'image'}
|
|
73
|
+
if (VIDEO_FORMATS_REGEXP.test(extension) || youtubeRegex.test(url) || vimeoRegex.test(url)) {return 'video'}
|
|
74
|
+
if (['pdf'].includes(extension)) {return 'pdf'}
|
|
75
75
|
return extension ?? 'unknown'
|
|
76
76
|
}
|
|
77
77
|
|
package/src/composables/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ export function useBglSchema<T = { [key: string]: unknown }>(
|
|
|
24
24
|
|
|
25
25
|
if (_schema) {
|
|
26
26
|
return (
|
|
27
|
-
_columns && _columns.length
|
|
27
|
+
_columns && 0 < _columns.length
|
|
28
28
|
? _schema.filter(f => _columns.includes(f.id as string))
|
|
29
29
|
: _schema
|
|
30
30
|
) as BglFormSchemaT<T>
|
|
@@ -39,7 +39,7 @@ export function localRef<T>(
|
|
|
39
39
|
IfAny<T, Ref<T, T>, T> :
|
|
40
40
|
Ref<UnwrapRef<T>, T | UnwrapRef<T>> {
|
|
41
41
|
const storedValue = localStorage.getItem(key)
|
|
42
|
-
const initial =
|
|
42
|
+
const initial = null !== storedValue ? JSON.parse(storedValue) : initialValue
|
|
43
43
|
const value = ref<T>(initial)
|
|
44
44
|
|
|
45
45
|
watch(() => value.value, (val) => {
|