@bagelink/vue 1.6.7 → 1.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Swiper.vue.d.ts +2322 -2
- package/dist/components/Swiper.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/index.cjs +16 -38
- package/dist/index.mjs +5893 -6969
- package/dist/style.css +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Carousel.vue +43 -43
- package/src/components/ListItem.vue +2 -2
- package/src/components/Swiper.vue +85 -79
- package/src/components/form/FieldArray.vue +56 -50
- package/src/components/form/inputs/CodeEditor/Index.vue +1 -1
- package/src/composables/useExcel.ts +6 -6
- package/src/styles/colors.css +176 -0
- package/src/styles/layout.css +231 -0
- package/src/styles/mobilLayout.css +232 -0
- package/src/styles/mobileColors.css +176 -0
- package/src/utils/index.ts +46 -25
- package/vite.config.ts +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts" generic="T = any">
|
|
2
|
-
import type {
|
|
2
|
+
import type { Swiper as SwiperType } from 'swiper'
|
|
3
3
|
import type { AutoplayOptions, CoverflowEffectOptions, PaginationOptions, SwiperOptions } from 'swiper/types'
|
|
4
4
|
import { Icon } from '@bagelink/vue'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { Autoplay, EffectCoverflow, EffectCube, EffectFade, EffectFlip, Navigation, Pagination, EffectCards } from 'swiper/modules'
|
|
6
|
+
import { Swiper, SwiperSlide } from 'swiper/vue'
|
|
7
|
+
import { computed, ref, watch } from 'vue'
|
|
7
8
|
import 'swiper/css'
|
|
8
9
|
import 'swiper/css/navigation'
|
|
9
10
|
import 'swiper/css/pagination'
|
|
@@ -11,8 +12,9 @@ import 'swiper/css/effect-fade'
|
|
|
11
12
|
import 'swiper/css/effect-coverflow'
|
|
12
13
|
import 'swiper/css/effect-cube'
|
|
13
14
|
import 'swiper/css/effect-flip'
|
|
15
|
+
import 'swiper/css/effect-cards'
|
|
14
16
|
|
|
15
|
-
type SwiperEffect = 'slide' | 'fade' | 'cube' | 'coverflow' | 'flip'
|
|
17
|
+
type SwiperEffect = 'slide' | 'fade' | 'cube' | 'coverflow' | 'flip' | 'cards'
|
|
16
18
|
type SwiperDirection = 'horizontal' | 'vertical'
|
|
17
19
|
type SwiperVariant = 'default' | 'testimonial' | 'gallery' | 'cards' | 'coverflow' | 'hero'
|
|
18
20
|
|
|
@@ -178,15 +180,13 @@ const variantPresets: Record<SwiperVariant, VariantConfig> = {
|
|
|
178
180
|
},
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const swiperEl = $ref<SwiperContainer | null>(null)
|
|
183
|
+
const swiperEl = ref<SwiperType | null>(null)
|
|
184
184
|
const isFirstSlide = ref(true)
|
|
185
185
|
const isLastSlide = ref(false)
|
|
186
186
|
const currentIndex = ref(props.index ?? props.initialSlide ?? 0)
|
|
187
187
|
let isUpdatingFromExternal = false // Guard to prevent update loops
|
|
188
188
|
|
|
189
|
-
const slideStyles =
|
|
189
|
+
const slideStyles = computed(() => {
|
|
190
190
|
const styles: Record<string, string> = {}
|
|
191
191
|
|
|
192
192
|
if (props.slideWidth !== undefined) {
|
|
@@ -197,18 +197,18 @@ const slideStyles = $computed(() => {
|
|
|
197
197
|
})
|
|
198
198
|
|
|
199
199
|
// Apply variant preset configuration
|
|
200
|
-
const variantConfig =
|
|
200
|
+
const variantConfig = computed(() => variantPresets[props.variant])
|
|
201
201
|
|
|
202
202
|
// Smart default: if slideWidth is set and slidesPerView wasn't set,
|
|
203
203
|
// automatically use 'auto' to let slides determine their own width
|
|
204
|
-
const effectiveSlidesPerView =
|
|
204
|
+
const effectiveSlidesPerView = computed(() => {
|
|
205
205
|
// Priority: explicit prop > variant config > smart default
|
|
206
206
|
if (props.slidesPerView !== undefined) {
|
|
207
207
|
return props.slidesPerView
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
if (variantConfig.slidesPerView !== undefined) {
|
|
211
|
-
return variantConfig.slidesPerView
|
|
210
|
+
if (variantConfig.value.slidesPerView !== undefined) {
|
|
211
|
+
return variantConfig.value.slidesPerView
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
// Smart default: if slideWidth is provided, use 'auto'
|
|
@@ -228,46 +228,42 @@ const swiperParams = computed((): SwiperOptions => {
|
|
|
228
228
|
defaultValue: any
|
|
229
229
|
) => {
|
|
230
230
|
if (propValue !== undefined) return propValue
|
|
231
|
-
if (variantConfig[variantKey] !== undefined) return variantConfig[variantKey]
|
|
231
|
+
if (variantConfig.value[variantKey] !== undefined) return variantConfig.value[variantKey]
|
|
232
232
|
return defaultValue
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
const params: SwiperOptions = {
|
|
236
|
+
modules: [Navigation, Pagination, Autoplay, EffectFade, EffectCoverflow, EffectCube, EffectFlip, EffectCards],
|
|
236
237
|
effect: getValue(props.effect, 'effect', 'slide'),
|
|
237
238
|
direction: props.direction ?? 'horizontal',
|
|
238
239
|
speed: getValue(props.speed, 'speed', 300),
|
|
239
240
|
loop: getValue(props.loop, 'loop', false),
|
|
240
241
|
initialSlide: props.index ?? props.initialSlide,
|
|
241
|
-
slidesPerView: effectiveSlidesPerView,
|
|
242
|
+
slidesPerView: effectiveSlidesPerView.value,
|
|
242
243
|
spaceBetween: getValue(props.spaceBetween, 'spaceBetween', 0),
|
|
243
244
|
centeredSlides: getValue(props.centeredSlides, 'centeredSlides', false),
|
|
244
245
|
grabCursor: props.grabCursor,
|
|
245
|
-
keyboard: props.keyboard
|
|
246
|
-
mousewheel: props.mousewheel
|
|
246
|
+
keyboard: props.keyboard,
|
|
247
|
+
mousewheel: props.mousewheel,
|
|
247
248
|
autoHeight: props.autoHeight,
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
// Navigation (priority: prop > variant > default)
|
|
251
|
-
const navigationEnabled = getValue(props.navigation, 'navigation', false)
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
252
|
+
// const navigationEnabled = getValue(props.navigation, 'navigation', false)
|
|
253
|
+
// // Note: We use custom navigation controls, not Swiper's built-in navigation
|
|
254
|
+
// // params.navigation = !!navigationEnabled
|
|
255
255
|
|
|
256
256
|
// Pagination (priority: prop > variant > default)
|
|
257
257
|
const paginationConfig = getValue(props.pagination, 'pagination', false)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
: paginationConfig
|
|
262
|
-
}
|
|
258
|
+
params.pagination = paginationConfig
|
|
259
|
+
? (typeof paginationConfig === 'boolean' ? { clickable: true } : paginationConfig)
|
|
260
|
+
: false
|
|
263
261
|
|
|
264
262
|
// Autoplay (priority: prop > variant > default)
|
|
265
263
|
const autoplayConfig = getValue(props.autoplay, 'autoplay', false)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
: autoplayConfig
|
|
270
|
-
}
|
|
264
|
+
params.autoplay = autoplayConfig
|
|
265
|
+
? (typeof autoplayConfig === 'boolean' ? { delay: 3000 } : autoplayConfig)
|
|
266
|
+
: false
|
|
271
267
|
|
|
272
268
|
// Effect-specific options (merge variant and explicit)
|
|
273
269
|
const effectType = params.effect || 'slide'
|
|
@@ -281,7 +277,7 @@ const swiperParams = computed((): SwiperOptions => {
|
|
|
281
277
|
}
|
|
282
278
|
params.coverflowEffect = {
|
|
283
279
|
...baseCoverflowEffect,
|
|
284
|
-
...variantConfig.coverflowEffect,
|
|
280
|
+
...variantConfig.value.coverflowEffect,
|
|
285
281
|
...props.coverflowEffect,
|
|
286
282
|
}
|
|
287
283
|
}
|
|
@@ -300,16 +296,38 @@ const swiperParams = computed((): SwiperOptions => {
|
|
|
300
296
|
return params
|
|
301
297
|
})
|
|
302
298
|
|
|
303
|
-
|
|
299
|
+
// Format params for Swiper Vue component with proper types
|
|
300
|
+
const swiperVueProps = computed(() => ({
|
|
301
|
+
modules: swiperParams.value.modules,
|
|
302
|
+
effect: swiperParams.value.effect as 'slide' | 'fade' | 'cube' | 'coverflow' | 'flip' | 'cards',
|
|
303
|
+
direction: swiperParams.value.direction,
|
|
304
|
+
speed: swiperParams.value.speed,
|
|
305
|
+
loop: swiperParams.value.loop,
|
|
306
|
+
initialSlide: swiperParams.value.initialSlide,
|
|
307
|
+
slidesPerView: swiperParams.value.slidesPerView,
|
|
308
|
+
spaceBetween: swiperParams.value.spaceBetween as number,
|
|
309
|
+
centeredSlides: swiperParams.value.centeredSlides,
|
|
310
|
+
grabCursor: swiperParams.value.grabCursor,
|
|
311
|
+
keyboard: swiperParams.value.keyboard as boolean | undefined,
|
|
312
|
+
mousewheel: swiperParams.value.mousewheel as boolean | undefined,
|
|
313
|
+
autoHeight: swiperParams.value.autoHeight,
|
|
314
|
+
navigation: swiperParams.value.navigation as boolean | undefined,
|
|
315
|
+
pagination: swiperParams.value.pagination,
|
|
316
|
+
autoplay: swiperParams.value.autoplay,
|
|
317
|
+
coverflowEffect: swiperParams.value.coverflowEffect,
|
|
318
|
+
breakpoints: swiperParams.value.breakpoints,
|
|
319
|
+
}))
|
|
320
|
+
|
|
321
|
+
const swiperInstance = computed(() => swiperEl.value)
|
|
304
322
|
|
|
305
323
|
function updateNavigationState() {
|
|
306
|
-
if (swiperEl
|
|
307
|
-
isFirstSlide.value = swiperEl.
|
|
308
|
-
isLastSlide.value = swiperEl.
|
|
324
|
+
if (swiperEl.value && !isUpdatingFromExternal) {
|
|
325
|
+
isFirstSlide.value = swiperEl.value.isBeginning
|
|
326
|
+
isLastSlide.value = swiperEl.value.isEnd
|
|
309
327
|
|
|
310
328
|
// Emit index update for v-model support
|
|
311
329
|
// Use activeIndex for non-loop mode, realIndex for loop mode
|
|
312
|
-
const newIndex = props.loop ? swiperEl.
|
|
330
|
+
const newIndex = props.loop ? swiperEl.value.realIndex : swiperEl.value.activeIndex
|
|
313
331
|
currentIndex.value = newIndex
|
|
314
332
|
|
|
315
333
|
// Emit to keep external state in sync
|
|
@@ -318,46 +336,32 @@ function updateNavigationState() {
|
|
|
318
336
|
}
|
|
319
337
|
|
|
320
338
|
function slideTo(index: number) {
|
|
321
|
-
if (!swiperEl
|
|
322
|
-
swiperEl.
|
|
339
|
+
if (!swiperEl.value) return
|
|
340
|
+
swiperEl.value.slideTo(index)
|
|
323
341
|
}
|
|
324
342
|
|
|
325
343
|
function handleSlideNav(dir: 'prev' | 'next') {
|
|
326
|
-
if (!swiperEl
|
|
344
|
+
if (!swiperEl.value) return
|
|
327
345
|
|
|
328
346
|
if (dir === 'next') {
|
|
329
|
-
swiperEl.
|
|
347
|
+
swiperEl.value.slideNext()
|
|
330
348
|
} else {
|
|
331
|
-
swiperEl.
|
|
349
|
+
swiperEl.value.slidePrev()
|
|
332
350
|
}
|
|
333
351
|
}
|
|
334
352
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const params = {
|
|
340
|
-
...swiperParams.value,
|
|
341
|
-
on: {
|
|
342
|
-
...swiperParams.value.on,
|
|
343
|
-
init: updateNavigationState,
|
|
344
|
-
slideChange: updateNavigationState,
|
|
345
|
-
slideChangeTransitionEnd: updateNavigationState,
|
|
346
|
-
reachBeginning: updateNavigationState,
|
|
347
|
-
reachEnd: updateNavigationState,
|
|
348
|
-
fromEdge: updateNavigationState,
|
|
349
|
-
},
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
Object.assign(swiperEl, params)
|
|
353
|
-
swiperEl.initialize()
|
|
354
|
-
})
|
|
353
|
+
function onSwiper(swiper: SwiperType) {
|
|
354
|
+
swiperEl.value = swiper
|
|
355
|
+
updateNavigationState()
|
|
356
|
+
}
|
|
355
357
|
|
|
356
358
|
watch(
|
|
357
359
|
() => props.initialSlide,
|
|
358
360
|
(index) => {
|
|
359
|
-
if (index !== undefined && swiperEl
|
|
360
|
-
setTimeout(() =>
|
|
361
|
+
if (index !== undefined && swiperEl.value) {
|
|
362
|
+
setTimeout(() => {
|
|
363
|
+
if (swiperEl.value) swiperEl.value.slideTo(index)
|
|
364
|
+
}, 1)
|
|
361
365
|
}
|
|
362
366
|
},
|
|
363
367
|
{ immediate: true },
|
|
@@ -370,11 +374,11 @@ watch(
|
|
|
370
374
|
if (newIndex !== undefined) {
|
|
371
375
|
currentIndex.value = newIndex
|
|
372
376
|
|
|
373
|
-
if (swiperEl
|
|
374
|
-
const activeIndex = props.loop ? swiperEl.
|
|
377
|
+
if (swiperEl.value) {
|
|
378
|
+
const activeIndex = props.loop ? swiperEl.value.realIndex : swiperEl.value.activeIndex
|
|
375
379
|
if (newIndex !== activeIndex) {
|
|
376
380
|
isUpdatingFromExternal = true
|
|
377
|
-
swiperEl.
|
|
381
|
+
swiperEl.value.slideTo(newIndex)
|
|
378
382
|
// Reset guard after a short delay to allow transition
|
|
379
383
|
setTimeout(() => {
|
|
380
384
|
isUpdatingFromExternal = false
|
|
@@ -389,9 +393,9 @@ watch(
|
|
|
389
393
|
watch(
|
|
390
394
|
swiperParams,
|
|
391
395
|
(newParams) => {
|
|
392
|
-
if (swiperEl
|
|
393
|
-
Object.assign(swiperEl.
|
|
394
|
-
swiperEl.
|
|
396
|
+
if (swiperEl.value) {
|
|
397
|
+
Object.assign(swiperEl.value.params, newParams)
|
|
398
|
+
swiperEl.value.update()
|
|
395
399
|
}
|
|
396
400
|
},
|
|
397
401
|
{ deep: true },
|
|
@@ -402,7 +406,7 @@ defineExpose({
|
|
|
402
406
|
slideNext: () => { handleSlideNav('next') },
|
|
403
407
|
slidePrev: () => { handleSlideNav('prev') },
|
|
404
408
|
slideTo,
|
|
405
|
-
update: () => swiperEl?.
|
|
409
|
+
update: () => swiperEl.value?.update(),
|
|
406
410
|
isFirst: isFirstSlide,
|
|
407
411
|
isLast: isLastSlide,
|
|
408
412
|
currentIndex,
|
|
@@ -411,11 +415,15 @@ defineExpose({
|
|
|
411
415
|
|
|
412
416
|
<template>
|
|
413
417
|
<div class="swi-wrap">
|
|
414
|
-
<
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
418
|
+
<Swiper
|
|
419
|
+
v-bind="swiperVueProps" class="swiper" @swiper="onSwiper" @slide-change="updateNavigationState"
|
|
420
|
+
@reach-beginning="updateNavigationState" @reach-end="updateNavigationState"
|
|
421
|
+
@from-edge="updateNavigationState"
|
|
422
|
+
>
|
|
423
|
+
<SwiperSlide v-for="(item, idx) in items" :key="idx" :style="slideStyles">
|
|
424
|
+
<slot :item="item" :index="idx" :currentIndex="currentIndex" />
|
|
425
|
+
</SwiperSlide>
|
|
426
|
+
</Swiper>
|
|
419
427
|
|
|
420
428
|
<!-- Custom Navigation Slot -->
|
|
421
429
|
<slot
|
|
@@ -427,12 +435,12 @@ defineExpose({
|
|
|
427
435
|
<div v-if="navigation" class="swi-ctrl">
|
|
428
436
|
<div class="swi-prev hover" @click="handleSlideNav('prev')">
|
|
429
437
|
<slot name="prev-button">
|
|
430
|
-
<Icon name="chevron_left" />
|
|
438
|
+
<Icon name="chevron_left" class="user-select-none hover z-99 color-primary" :size="2" />
|
|
431
439
|
</slot>
|
|
432
440
|
</div>
|
|
433
441
|
<div class="swi-next hover" @click="handleSlideNav('next')">
|
|
434
442
|
<slot name="next-button">
|
|
435
|
-
<Icon name="chevron_right" />
|
|
443
|
+
<Icon name="chevron_right" class="user-select-none hover z-99 color-primary" :size="2" />
|
|
436
444
|
</slot>
|
|
437
445
|
</div>
|
|
438
446
|
</div>
|
|
@@ -446,8 +454,6 @@ defineExpose({
|
|
|
446
454
|
<style>
|
|
447
455
|
.swiper {
|
|
448
456
|
width: 100%;
|
|
449
|
-
padding-top: 50px;
|
|
450
|
-
padding-bottom: 50px;
|
|
451
457
|
}
|
|
452
458
|
|
|
453
459
|
:root {
|
|
@@ -62,9 +62,9 @@ let lastEmittedValue = '' // Event handlers state
|
|
|
62
62
|
|
|
63
63
|
// Generate schema for primitive types
|
|
64
64
|
const primitiveSchema = computed<PrimitiveArrFieldT[]>(() => {
|
|
65
|
-
if ('text'
|
|
65
|
+
if (props.type === 'text') {
|
|
66
66
|
return [{ id: 'value', type: 'text', label: '', $el: 'text' }]
|
|
67
|
-
}if (props.type === 'number') {
|
|
67
|
+
} if (props.type === 'number') {
|
|
68
68
|
return [{ id: 'value', type: 'number', label: '', $el: 'number' }]
|
|
69
69
|
}
|
|
70
70
|
return []
|
|
@@ -72,20 +72,20 @@ const primitiveSchema = computed<PrimitiveArrFieldT[]>(() => {
|
|
|
72
72
|
|
|
73
73
|
const resolvedSchemaData = computed(() => {
|
|
74
74
|
// Handle 'array' type as equivalent to 'object' type
|
|
75
|
-
const isObjectType = 'object'
|
|
75
|
+
const isObjectType = props.type === 'object' || props.type === 'array'
|
|
76
76
|
|
|
77
|
-
if (!isObjectType) {return primitiveSchema.value as BglFormSchemaT<T>}
|
|
77
|
+
if (!isObjectType) { return primitiveSchema.value as BglFormSchemaT<T> }
|
|
78
78
|
|
|
79
79
|
// Use children prop first, then schema prop, then attrs.schema
|
|
80
80
|
const attrsSchema = props.attrs?.schema !== undefined ? toValue(props.attrs.schema) : null
|
|
81
81
|
const schemaToUse = props.children || toValue(props.schema) || attrsSchema
|
|
82
82
|
|
|
83
|
-
// If no schema but we have defaultValue, try to infer schema from first item
|
|
84
|
-
const noSchema = null === schemaToUse || schemaToUse === undefined
|
|
85
|
-
|
|
86
|
-
const hasDefaultValue = props.defaultValue !== undefined
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
89
89
|
|
|
90
90
|
// Don't infer schema from defaultValue - this causes unwanted restoration
|
|
91
91
|
// Let the component work with empty arrays
|
|
@@ -120,8 +120,8 @@ watch(() => internalData.value.length, (newLength) => {
|
|
|
120
120
|
// Initialize with existing data or defaultValue on mount - only once!
|
|
121
121
|
onMounted(() => {
|
|
122
122
|
// If no modelValue provided, use defaultValue as initial data (one time only)
|
|
123
|
-
if (!props.modelValue ||
|
|
124
|
-
if (props.defaultValue &&
|
|
123
|
+
if (!props.modelValue || props.modelValue.length === 0) {
|
|
124
|
+
if (props.defaultValue && props.defaultValue.length > 0) {
|
|
125
125
|
internalData.value = [...props.defaultValue]
|
|
126
126
|
emitValue() // This will set the initial value and then it becomes "regular" data
|
|
127
127
|
}
|
|
@@ -137,7 +137,7 @@ onMounted(() => {
|
|
|
137
137
|
|
|
138
138
|
// Function to load default values (explicit user action)
|
|
139
139
|
function loadDefaults() {
|
|
140
|
-
if (props.defaultValue &&
|
|
140
|
+
if (props.defaultValue && props.defaultValue.length > 0) {
|
|
141
141
|
internalData.value = [...props.defaultValue]
|
|
142
142
|
emitValue()
|
|
143
143
|
} else {
|
|
@@ -234,8 +234,8 @@ function toggleMinimized(index: number) {
|
|
|
234
234
|
|
|
235
235
|
function updateItem(index: number, value: any) {
|
|
236
236
|
// Handle primitive types by extracting the value property
|
|
237
|
-
if ('text'
|
|
238
|
-
internalData.value[index] = 'number'
|
|
237
|
+
if (props.type === 'text' || props.type === 'number') {
|
|
238
|
+
internalData.value[index] = props.type === 'number' ? Number(value.value) : value.value
|
|
239
239
|
} else {
|
|
240
240
|
internalData.value[index] = value
|
|
241
241
|
}
|
|
@@ -243,24 +243,24 @@ function updateItem(index: number, value: any) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
// Computed properties for rendering
|
|
246
|
-
const isPrimitiveType = computed(() => 'text'
|
|
246
|
+
const isPrimitiveType = computed(() => props.type === 'text' || props.type === 'number')
|
|
247
247
|
const canRenderItems = computed(() => {
|
|
248
248
|
const schemaData = resolvedSchemaData.value
|
|
249
|
-
const hasValidSchema = (Array.isArray(schemaData) &&
|
|
250
|
-
|| (props.children &&
|
|
251
|
-
const hasDefaultValue = props.defaultValue &&
|
|
249
|
+
const hasValidSchema = (Array.isArray(schemaData) && schemaData.length > 0)
|
|
250
|
+
|| (props.children && props.children.length > 0)
|
|
251
|
+
const hasDefaultValue = props.defaultValue && props.defaultValue.length > 0
|
|
252
252
|
|
|
253
253
|
// For primitive types or when we have schema or defaultValue
|
|
254
|
-
const isObjectType = 'object'
|
|
254
|
+
const isObjectType = props.type === 'object' || props.type === 'array'
|
|
255
255
|
const shouldRender = isPrimitiveType.value
|
|
256
|
-
|| (isObjectType && (
|
|
256
|
+
|| (isObjectType && (hasValidSchema === true || hasDefaultValue === true))
|
|
257
257
|
return shouldRender
|
|
258
258
|
})
|
|
259
259
|
const showMinimizeButton = computed(() => {
|
|
260
260
|
const schemaData = resolvedSchemaData.value
|
|
261
|
-
const hasLongSchema = Array.isArray(schemaData) &&
|
|
261
|
+
const hasLongSchema = Array.isArray(schemaData) && schemaData.length > 2
|
|
262
262
|
const hasRichText = Array.isArray(schemaData)
|
|
263
|
-
&& schemaData.some((schema: any) => 'richtext'
|
|
263
|
+
&& schemaData.some((schema: any) => schema.$el === 'richtext')
|
|
264
264
|
return hasLongSchema || hasRichText
|
|
265
265
|
})
|
|
266
266
|
</script>
|
|
@@ -293,20 +293,19 @@ const showMinimizeButton = computed(() => {
|
|
|
293
293
|
No {{ label?.toLowerCase() || 'items' }} added yet
|
|
294
294
|
</p>
|
|
295
295
|
<!-- Load defaults button if defaultValue exists -->
|
|
296
|
-
<Btn
|
|
296
|
+
<Btn
|
|
297
|
+
v-if="props.defaultValue && props.defaultValue.length > 0" thin color="primary"
|
|
298
|
+
class="txt12 mb-05" @click="loadDefaults"
|
|
299
|
+
>
|
|
297
300
|
Load Default {{ label || 'Items' }}
|
|
298
301
|
</Btn>
|
|
299
302
|
</Card>
|
|
300
303
|
|
|
301
304
|
<!-- Array Items -->
|
|
302
305
|
<div
|
|
303
|
-
v-for="(item, i) in internalData"
|
|
304
|
-
:key="i"
|
|
305
|
-
outline
|
|
306
|
-
thin
|
|
306
|
+
v-for="(item, i) in internalData" :key="i" outline thin
|
|
307
307
|
class="mb-05 itemBox transition radius-05 overflow-hidden txt12 border"
|
|
308
|
-
style="--input-font-size: 12px"
|
|
309
|
-
:class="{ minimized: minimizedItems[i] }"
|
|
308
|
+
style="--input-font-size: 12px" :class="{ minimized: minimizedItems[i] }"
|
|
310
309
|
>
|
|
311
310
|
<div>
|
|
312
311
|
<!-- Minimized View -->
|
|
@@ -314,15 +313,22 @@ const showMinimizeButton = computed(() => {
|
|
|
314
313
|
<p class="minimizedText txt12 p-05 opacity-7 flex-grow-2" @click="toggleMinimized(i)">
|
|
315
314
|
{{ label }} {{ i + 1 }}
|
|
316
315
|
</p>
|
|
317
|
-
<Btn
|
|
316
|
+
<Btn
|
|
317
|
+
v-if="showMinimizeButton" class="rotate-180 txt10 opacity-7 p-025" flat thin
|
|
318
|
+
icon="keyboard_arrow_down" @click="toggleMinimized(i)"
|
|
319
|
+
/>
|
|
318
320
|
</div>
|
|
319
321
|
|
|
320
322
|
<!-- Form View -->
|
|
321
323
|
<BagelFormFA
|
|
322
|
-
v-if="!minimizedItems[i]" :model-value="isPrimitiveType ? { value: item } : item"
|
|
324
|
+
v-if="!minimizedItems[i]" :model-value="isPrimitiveType ? { value: item } : item"
|
|
325
|
+
:schema="resolvedSchemaData" class="bginputbg p-05 grid gap-05"
|
|
323
326
|
@update:model-value="val => updateItem(i, val)"
|
|
324
327
|
/>
|
|
325
|
-
<Btn
|
|
328
|
+
<Btn
|
|
329
|
+
v-if="props.delete" icon="delete" class="txt10 opacity-7" thin flat
|
|
330
|
+
@click="deleteItem(i)"
|
|
331
|
+
/>
|
|
326
332
|
</div>
|
|
327
333
|
</div>
|
|
328
334
|
|
|
@@ -388,27 +394,27 @@ const showMinimizeButton = computed(() => {
|
|
|
388
394
|
|
|
389
395
|
.itemBox .richtext-editor-content {
|
|
390
396
|
--richtext-font-size: 12px !important;
|
|
391
|
-
|
|
392
|
-
|
|
397
|
+
font-size: 12px !important;
|
|
398
|
+
}
|
|
393
399
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
400
|
+
.itemBox iframe.editableContent {
|
|
401
|
+
--richtext-font-size: 12px !important;
|
|
402
|
+
}
|
|
397
403
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
404
|
+
.itemBox .bagel-input.richtext-input {
|
|
405
|
+
--richtext-font-size: 12px !important;
|
|
406
|
+
}
|
|
401
407
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
408
|
+
/* More specific selectors to override richtext font size */
|
|
409
|
+
.itemBox .richtext-input iframe {
|
|
410
|
+
font-size: 12px !important;
|
|
411
|
+
}
|
|
406
412
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
413
|
+
.itemBox .richtext-input .editableContent body {
|
|
414
|
+
font-size: 12px !important;
|
|
415
|
+
}
|
|
410
416
|
|
|
411
|
-
|
|
412
|
-
|
|
417
|
+
.itemBox .richtext-input {
|
|
418
|
+
font-size: 12px !important;
|
|
413
419
|
}
|
|
414
420
|
</style>
|
|
@@ -65,7 +65,7 @@ export function useExcel() {
|
|
|
65
65
|
const XLSX = await ensureXLSXLoaded()
|
|
66
66
|
|
|
67
67
|
const formattedData = formatData(data, schema)
|
|
68
|
-
const headers =
|
|
68
|
+
const headers = schema.length > 0
|
|
69
69
|
? schema.map((sf) => {
|
|
70
70
|
const { id, label } = sf as unknown as Field<T>
|
|
71
71
|
return { v: (label as any) || (id as any), t: 's' }
|
|
@@ -73,7 +73,7 @@ export function useExcel() {
|
|
|
73
73
|
: []
|
|
74
74
|
const ws = XLSX.utils.json_to_sheet(formattedData)
|
|
75
75
|
|
|
76
|
-
if (
|
|
76
|
+
if (headers.length > 0) {
|
|
77
77
|
XLSX.utils.sheet_add_aoa(ws, [headers.map(h => h.v)], { origin: 'A1' })
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -124,7 +124,7 @@ export function useExcel() {
|
|
|
124
124
|
// Read the raw sheet data as arrays
|
|
125
125
|
const rawSheetData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }) as any[][]
|
|
126
126
|
|
|
127
|
-
if (
|
|
127
|
+
if (rawSheetData.length === 0) {
|
|
128
128
|
return { headers: [], data: [] }
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -196,10 +196,10 @@ export function useExcel() {
|
|
|
196
196
|
// Helper function for date detection and conversion
|
|
197
197
|
function isExcelSerialDate(value: any): boolean {
|
|
198
198
|
return (
|
|
199
|
-
|
|
199
|
+
typeof value === 'number'
|
|
200
200
|
&& Number.isInteger(value)
|
|
201
|
-
&&
|
|
202
|
-
&&
|
|
201
|
+
&& value >= 20000
|
|
202
|
+
&& value <= 50000
|
|
203
203
|
)
|
|
204
204
|
}
|
|
205
205
|
|