@bagelink/vue 1.6.43 → 1.6.49

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.
Files changed (179) hide show
  1. package/bin/experimentalGenTypedRoutes.ts +18 -19
  2. package/bin/utils.ts +4 -4
  3. package/dist/components/AddressSearch.vue.d.ts.map +1 -1
  4. package/dist/components/Alert.vue.d.ts.map +1 -1
  5. package/dist/components/BglVideo.vue.d.ts.map +1 -1
  6. package/dist/components/Card.vue.d.ts.map +1 -1
  7. package/dist/components/Carousel.vue.d.ts +2 -2
  8. package/dist/components/Carousel.vue.d.ts.map +1 -1
  9. package/dist/components/Dropdown.vue.d.ts.map +1 -1
  10. package/dist/components/Flag.vue.d.ts.map +1 -1
  11. package/dist/components/IframeVue.vue.d.ts.map +1 -1
  12. package/dist/components/ListItem.vue.d.ts.map +1 -1
  13. package/dist/components/Loading.vue.d.ts.map +1 -1
  14. package/dist/components/Modal.vue.d.ts.map +1 -1
  15. package/dist/components/ModalForm.vue.d.ts.map +1 -1
  16. package/dist/components/NavBar.vue.d.ts +1 -1
  17. package/dist/components/Pill.vue.d.ts.map +1 -1
  18. package/dist/components/Swiper.vue.d.ts +12 -4
  19. package/dist/components/Swiper.vue.d.ts.map +1 -1
  20. package/dist/components/Zoomer.vue.d.ts.map +1 -1
  21. package/dist/components/analytics/LineChart.vue.d.ts.map +1 -1
  22. package/dist/components/analytics/PieChart.vue.d.ts +2 -1
  23. package/dist/components/analytics/PieChart.vue.d.ts.map +1 -1
  24. package/dist/components/analytics/index.d.ts +1 -1
  25. package/dist/components/analytics/index.d.ts.map +1 -1
  26. package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
  27. package/dist/components/form/BglMultiStepForm.vue.d.ts.map +1 -1
  28. package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
  29. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  30. package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
  31. package/dist/components/form/inputs/RadioGroup.vue.d.ts.map +1 -1
  32. package/dist/components/form/inputs/RangeInput.vue.d.ts +11 -11
  33. package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
  34. package/dist/components/form/inputs/RichText/components/TableGridSelector.vue.d.ts.map +1 -1
  35. package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
  36. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  37. package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
  38. package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
  39. package/dist/components/layout/AppSidebar.vue.d.ts +1 -0
  40. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
  41. package/dist/components/layout/Layout.vue.d.ts.map +1 -1
  42. package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
  43. package/dist/components/layout/index.d.ts +3 -3
  44. package/dist/components/layout/index.d.ts.map +1 -1
  45. package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
  46. package/dist/index.cjs +24 -15
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.mjs +1530 -1404
  50. package/dist/plugins/modalTypes.d.ts +1 -8
  51. package/dist/plugins/modalTypes.d.ts.map +1 -1
  52. package/dist/plugins/useModal.d.ts.map +1 -1
  53. package/dist/style.css +1 -1
  54. package/package.json +1 -2
  55. package/src/components/AccordionItem.vue +13 -13
  56. package/src/components/AddToCalendar.vue +1 -1
  57. package/src/components/AddressSearch.vue +9 -8
  58. package/src/components/Alert.vue +2 -1
  59. package/src/components/Badge.vue +5 -5
  60. package/src/components/BglVideo.vue +44 -45
  61. package/src/components/Btn.vue +15 -15
  62. package/src/components/Card.vue +10 -8
  63. package/src/components/Carousel.vue +159 -162
  64. package/src/components/DataPreview.vue +1 -1
  65. package/src/components/DragOver.vue +6 -6
  66. package/src/components/Dropdown.vue +39 -38
  67. package/src/components/Flag.vue +7 -6
  68. package/src/components/Icon/Icon.vue +22 -22
  69. package/src/components/IframeVue.vue +5 -5
  70. package/src/components/Image.vue +17 -17
  71. package/src/components/ImportData.vue +79 -79
  72. package/src/components/ListItem.vue +12 -11
  73. package/src/components/Loading.vue +10 -9
  74. package/src/components/MapEmbed/Index.vue +24 -24
  75. package/src/components/Modal.vue +11 -9
  76. package/src/components/ModalForm.vue +15 -11
  77. package/src/components/NavBar.vue +6 -6
  78. package/src/components/Pagination.vue +27 -27
  79. package/src/components/Pill.vue +11 -12
  80. package/src/components/Rating.vue +2 -2
  81. package/src/components/Slider.vue +75 -75
  82. package/src/components/Spreadsheet/Index.vue +34 -34
  83. package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
  84. package/src/components/Swiper.vue +4 -4
  85. package/src/components/Zoomer.vue +282 -182
  86. package/src/components/analytics/BarChart.vue +6 -6
  87. package/src/components/analytics/KpiCard.vue +2 -2
  88. package/src/components/analytics/LineChart.vue +63 -61
  89. package/src/components/analytics/PieChart.vue +104 -90
  90. package/src/components/analytics/index.ts +2 -2
  91. package/src/components/calendar/CalendarPopover.vue +1 -1
  92. package/src/components/calendar/Index.vue +1 -1
  93. package/src/components/calendar/views/AgendaView.vue +3 -3
  94. package/src/components/calendar/views/DayView.vue +6 -6
  95. package/src/components/calendar/views/MonthView.vue +2 -2
  96. package/src/components/calendar/views/WeekView.vue +18 -18
  97. package/src/components/dataTable/DataTable.vue +4 -4
  98. package/src/components/dataTable/useSorting.ts +1 -1
  99. package/src/components/dataTable/useTableData.ts +15 -15
  100. package/src/components/dataTable/useTableSelection.ts +15 -15
  101. package/src/components/dataTable/useTableVirtualization.ts +1 -1
  102. package/src/components/draggable/useDraggable.ts +42 -42
  103. package/src/components/form/BagelForm.vue +15 -15
  104. package/src/components/form/BglFieldSet.vue +5 -3
  105. package/src/components/form/BglMultiStepForm.vue +20 -21
  106. package/src/components/form/inputs/CheckInput.vue +2 -2
  107. package/src/components/form/inputs/CodeEditor/format.ts +7 -7
  108. package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
  109. package/src/components/form/inputs/ColorInput.vue +5 -4
  110. package/src/components/form/inputs/DateInput.vue +8 -9
  111. package/src/components/form/inputs/DatePicker.vue +24 -24
  112. package/src/components/form/inputs/EmailInput.vue +24 -24
  113. package/src/components/form/inputs/NumberInput.vue +26 -26
  114. package/src/components/form/inputs/OTP.vue +7 -7
  115. package/src/components/form/inputs/PasswordInput.vue +3 -2
  116. package/src/components/form/inputs/RadioGroup.vue +28 -25
  117. package/src/components/form/inputs/RadioPillsInput.vue +12 -12
  118. package/src/components/form/inputs/RangeInput.vue +21 -21
  119. package/src/components/form/inputs/RichText/components/EditorToolbar.vue +107 -92
  120. package/src/components/form/inputs/RichText/components/TableGridSelector.vue +64 -64
  121. package/src/components/form/inputs/RichText/components/gridBox.vue +10 -8
  122. package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
  123. package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
  124. package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
  125. package/src/components/form/inputs/RichText/index.vue +138 -138
  126. package/src/components/form/inputs/RichText/utils/commands.ts +84 -85
  127. package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
  128. package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
  129. package/src/components/form/inputs/RichText/utils/media.ts +7 -7
  130. package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
  131. package/src/components/form/inputs/RichText/utils/table.ts +19 -19
  132. package/src/components/form/inputs/SelectBtn.vue +1 -1
  133. package/src/components/form/inputs/SelectInput.vue +54 -54
  134. package/src/components/form/inputs/SignaturePad.vue +40 -40
  135. package/src/components/form/inputs/TableField.vue +1 -1
  136. package/src/components/form/inputs/TelInput.vue +54 -53
  137. package/src/components/form/inputs/TextInput.vue +19 -19
  138. package/src/components/form/inputs/ToggleInput.vue +2 -2
  139. package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
  140. package/src/components/form/useBagelFormState.ts +5 -5
  141. package/src/components/layout/AppContent.vue +6 -3
  142. package/src/components/layout/AppLayout.vue +2 -2
  143. package/src/components/layout/AppSidebar.vue +83 -16
  144. package/src/components/layout/Layout.vue +12 -10
  145. package/src/components/layout/SidebarMenu.vue +4 -4
  146. package/src/components/layout/TabbedLayout.vue +17 -17
  147. package/src/components/layout/Tabs.vue +4 -5
  148. package/src/components/layout/TabsNav.vue +14 -14
  149. package/src/components/layout/index.ts +3 -5
  150. package/src/components/lightbox/Lightbox.vue +276 -126
  151. package/src/components/lightbox/index.ts +8 -8
  152. package/src/composables/index.ts +8 -8
  153. package/src/composables/useAddToCalendar.ts +13 -13
  154. package/src/composables/useDevice.ts +2 -2
  155. package/src/composables/useFormField.ts +4 -4
  156. package/src/composables/usePolling.ts +8 -8
  157. package/src/composables/useSchemaField.ts +38 -38
  158. package/src/composables/useTheme.ts +9 -9
  159. package/src/composables/useValidateFieldValue.ts +2 -2
  160. package/src/directives/pattern.ts +25 -25
  161. package/src/directives/ripple.ts +4 -4
  162. package/src/directives/vResize.ts +6 -6
  163. package/src/index.ts +1 -0
  164. package/src/plugins/bagel.ts +4 -4
  165. package/src/plugins/modalTypes.ts +1 -8
  166. package/src/plugins/useModal.ts +43 -18
  167. package/src/styles/layout.css +1 -1
  168. package/src/types/index.ts +1 -1
  169. package/src/utils/BagelFormUtils.ts +7 -7
  170. package/src/utils/calendar/Helpers.ts +8 -8
  171. package/src/utils/calendar/dateUtils.ts +22 -22
  172. package/src/utils/calendar/time.ts +25 -25
  173. package/src/utils/calendar/week.ts +25 -25
  174. package/src/utils/elementUtils.ts +27 -27
  175. package/src/utils/sizeParsing.ts +2 -2
  176. package/src/utils/strings.ts +5 -5
  177. package/src/utils/tapDetector.ts +11 -11
  178. package/src/utils/useSearch.ts +29 -29
  179. package/vite.config.ts +0 -2
@@ -1,127 +1,123 @@
1
1
  <script setup lang="ts">
2
2
  import type { LightboxItem } from './lightbox.types'
3
3
 
4
- import { BglVideo, Btn, Icon, Zoomer, Image, normalizeURL, Carousel, downloadFile } from '@bagelink/vue'
5
- import { watch } from 'vue'
4
+ import { BglVideo, Btn, Icon, Zoomer, Image, normalizeURL, Swiper, downloadFile } from '@bagelink/vue'
5
+ import { computed, ref, watch } from 'vue'
6
6
 
7
- let isOpen = $ref(false)
8
- let group = $ref<LightboxItem[]>([])
9
- let currentIndex = $ref(0)
10
- let currentItem = $computed<LightboxItem>(() => group[currentIndex])
7
+ const isOpen = ref(false)
8
+ const group = ref<LightboxItem[]>([])
9
+ const currentIndex = ref(0)
10
+ const currentItem = computed<LightboxItem>(() => group.value[currentIndex.value])
11
+ const zoom = ref(1)
12
+
13
+ const canSwipe = computed(() => zoom.value === 1)
14
+
15
+ // Advanced options that update reactively
16
+ const swiperAdvancedOptions = computed(() => ({
17
+ allowTouchMove: zoom.value === 1,
18
+ touchRatio: zoom.value === 1 ? 1 : 0,
19
+ simulateTouch: zoom.value === 1,
20
+ }))
11
21
 
12
22
  function open(item: LightboxItem, groupItems?: LightboxItem[]) {
13
- isOpen = true
14
- group = groupItems || [item]
15
- currentIndex = group.findIndex(({ src }) => item.src === src)
23
+ isOpen.value = true
24
+ group.value = groupItems || [item]
25
+ currentIndex.value = group.value.findIndex((groupItem) => {
26
+ const hasSrcMatch = item.src !== undefined && item.src !== null && item.src !== ''
27
+ && groupItem.src === item.src
28
+ const hasPathMatch = item.pathKey !== undefined && item.pathKey !== null && item.pathKey !== ''
29
+ && groupItem.pathKey === item.pathKey
30
+ return hasSrcMatch || hasPathMatch
31
+ })
32
+ if (currentIndex.value === -1) currentIndex.value = 0
33
+ zoom.value = 1
16
34
  document.addEventListener('keydown', handleKeydown)
17
35
  }
18
36
 
19
37
  function close() {
20
- isOpen = false
38
+ isOpen.value = false
21
39
  document.removeEventListener('keydown', handleKeydown)
22
40
  }
23
41
 
24
- function next() {
25
- if (group.length > 1) {
26
- currentIndex = (currentIndex + 1) % group.length
27
- currentItem = group[currentIndex]
28
- }
42
+ function selectItem(index: number) {
43
+ currentIndex.value = index
44
+ zoom.value = 1
45
+ // The v-model will handle updating the swiper
29
46
  }
30
47
 
31
- function prev() {
32
- if (group.length > 1) {
33
- currentIndex = (currentIndex - 1 + group.length) % group.length
34
- currentItem = group[currentIndex]
48
+ watch(() => isOpen.value, (val) => {
49
+ if (val) {
50
+ document.body.style.overflow = 'hidden'
51
+ } else {
52
+ document.body.style.overflow = ''
35
53
  }
36
- }
37
-
38
- function selectItem(index: number) {
39
- currentIndex = index
40
- currentItem = group[index]
41
- }
54
+ })
42
55
 
43
- watch(() => isOpen, (val) => {
44
- if (val) { document.body.style.overflow = 'hidden' }
45
- else { document.body.style.overflow = '' }
56
+ watch(() => currentIndex.value, () => {
57
+ // Reset zoom when changing slides
58
+ zoom.value = 1
46
59
  })
47
60
 
48
61
  function handleKeydown(event: KeyboardEvent) {
49
62
  if (event.key === 'Escape') {
50
63
  close()
51
- } else if (event.key === 'ArrowLeft') {
52
- prev()
53
- } else if (event.key === 'ArrowRight') {
54
- next()
55
64
  }
56
65
  }
57
66
 
58
- const zoom = $ref(1)
59
-
60
- function clickOutside() {
61
- if (zoom === 1) { close() }
62
- }
63
-
64
67
  defineExpose({ open, close })
65
68
  </script>
66
69
 
67
70
  <template>
68
71
  <transition name="fade">
69
- <div
70
- v-if="isOpen"
71
- class="bgl-lightbox-overlay fixed w-100 h-100 flex justify-content-center z-9999 inset mx-auto"
72
- @keydown.esc="close" @keydown.left="prev" @keydown.right="next" @click="clickOutside"
73
- >
74
- <div
75
- v-if="group && group.length > 1"
76
- class="navigation flex space-between px-3 w-100 absolute m_px-1 m_none z-9"
77
- >
78
- <Btn class="oval opacity-8" icon="arrow_back" color="black" @click="prev" />
79
-
80
- <Btn class="oval opacity-8" icon="arrow_forward" color="black" @click="next" />
81
- </div>
82
- <div class="bgl-lightbox relative txt-center" @click.stop>
83
- <div class="flex start fixed top-1 w-100 space-between px-1 z-9">
84
- <Btn flat class="color-white" icon="close" @click="close" />
85
- <div v-if="currentItem?.enableZoom && currentItem?.type === 'image'" class="center">
86
- <Btn flat class="color-white" icon="remove" :disabled="zoom === 1" @click="zoom--" />
87
- <Btn flat class="color-white" icon="zoom_in" :disabled="zoom === 1" @click="zoom = 1" />
88
- <Btn flat class="color-white" icon="add" :disabled="zoom === 3" @click="zoom++" />
89
- </div>
90
- <Btn
91
- v-if="currentItem?.openFile && currentItem?.src" class="color-white" round thin flat
92
- iconEnd="arrow_outward" value="Open File" :href="currentItem?.src" target="_blank"
93
- />
94
- <Btn
95
- v-if="currentItem?.download && currentItem?.src" class="color-white" round thin flat
96
- icon="download" value="Download File" @click="downloadFile(currentItem?.src)"
97
- />
98
- <div v-if="!currentItem?.openFile && !currentItem?.download" />
72
+ <div v-if="isOpen" class="bgl-lightbox-overlay" @keydown.esc="close">
73
+ <div class="flex start w-100 space-between p-025 z-9" @click="close">
74
+ <Btn flat class="color-white" icon="close" @click="close" />
75
+ <div v-if="currentItem?.enableZoom && currentItem?.type === 'image'" class="center">
76
+ <Btn flat class="color-white" icon="remove" :disabled="zoom === 1" @click="zoom--" />
77
+ <Btn flat class="color-white" icon="zoom_in" :disabled="zoom === 1" @click="zoom = 1" />
78
+ <Btn flat class="color-white" icon="add" :disabled="zoom === 3" @click="zoom++" />
99
79
  </div>
80
+ <Btn
81
+ v-if="currentItem?.openFile && currentItem?.src" class="color-white" round thin flat
82
+ iconEnd="arrow_outward" value="Open File" :href="currentItem?.src" target="_blank"
83
+ />
84
+ <Btn
85
+ v-if="currentItem?.download && currentItem?.src" class="color-white" round thin flat
86
+ icon="download" value="Download File" @click="downloadFile(currentItem?.src)"
87
+ />
88
+ <div v-if="!currentItem?.openFile && !currentItem?.download" />
89
+ </div>
100
90
 
101
- <Carousel
102
- v-model:index="currentIndex" :items="1" class="bgl-lightbox-item"
103
- :class="{ zoomed: zoom > 1 }" :freeDrag="zoom === 1"
104
- >
105
- <template v-for="item in group" :key="item.src">
91
+ <Swiper
92
+ v-if="group && group.length > 0" v-model:index="currentIndex" :items="group"
93
+ :initial-slide="currentIndex" class="bgl-lightbox-swiper" :class="{ zoomed: zoom > 1 }"
94
+ :navigation="group.length > 1" :grab-cursor="canSwipe" :keyboard="true" :loop="false" :speed="400"
95
+ :slides-per-view="1" :space-between="0" effect="slide" :advanced-options="swiperAdvancedOptions"
96
+ @click.stop
97
+ >
98
+ <template #default="{ item }">
99
+ <div class="bgl-lightbox-item">
106
100
  <Zoomer
107
101
  v-if="item.type === 'image'" v-model:zoom="zoom" :disabled="!item?.enableZoom"
108
- :mouse-wheel-to-zoom="false"
102
+ :mouse-wheel-to-zoom="false" :double-click-to-zoom="true" :max-scale="5" :min-scale="1"
103
+ :aspect-ratio="0" :limit-translation="true" @click.stop
109
104
  >
110
- <Image :draggable="false" :src="item?.src" alt="Preview" class="vw90 lightbox-image" />
105
+ <Image :draggable="false" :src="item?.src" alt="Preview" class="lightbox-image" />
111
106
  </Zoomer>
112
107
 
113
108
  <BglVideo
114
109
  v-else-if="item?.type === 'video' && item?.src" :src="item?.src" autoplay controls
115
- class="vw90"
110
+ class="lightbox-video"
116
111
  />
117
112
 
118
- <div v-else-if="item?.type === 'pdf' && item?.src" class="vw90">
113
+ <div v-else-if="item?.type === 'pdf' && item?.src" class="lightbox-pdf">
119
114
  <embed
120
115
  :src="normalizeURL(item?.src)" type="application/pdf" width="100%" height="1080"
121
- :title="item?.name" class="vw90"
116
+ :title="item?.name"
122
117
  >
123
118
  </div>
124
- <div v-else class="vw90">
119
+
120
+ <div v-else class="lightbox-file">
125
121
  <div class="file-info txt-white flex m_block align-items-start gap-025">
126
122
  <Icon class="m-0 m_none" icon="draft" :size="10" weight="12" />
127
123
  <Icon class="m-0 none m_block m_-mb-1" icon="draft" :size="4" weight="2" />
@@ -129,40 +125,39 @@ defineExpose({ open, close })
129
125
  <div class="txt-start">
130
126
  <p class="mx-0 light">
131
127
  File:
132
- <span class="semi word-break-all ">
133
- {{ item?.name }}
134
- </span>
128
+ <span class="semi word-break-all">{{ item?.name }}</span>
135
129
  </p>
136
- <p class="mx-0 ">
130
+ <p class="mx-0">
137
131
  Type:
138
- <span class="semi">
139
- {{ item?.type }}
140
- </span>
132
+ <span class="semi">{{ item?.type }}</span>
141
133
  </p>
142
134
  <Btn :href="item?.src" target="_blank" round thin class="mt-1" value="Open file" />
143
- <!-- <a :href="currentItem?.src" target="_blank">Open file</a> -->
144
135
  </div>
145
136
  </div>
146
137
  </div>
147
- </template>
148
- </Carousel>
149
- <div
150
- v-if="group && group.length > 1" class="flex justify-content-center mt-2 overflow
151
- p-1 fixed bottom start end gap-1 m_justify-content-start"
152
- >
153
- <template v-for="(item, index) in group" :key="index">
154
- <Image
155
- v-if="item.type === 'image'" class="thumbnail object-fit-cover hover
156
- opacity-5 rounded flex bg-popup justify-content-center align-items-center flex-shrink-0" :src="item.src" alt=""
157
- :class="{ active: currentIndex === index }" @click="selectItem(index)"
158
- />
159
- <Icon
160
- v-else class="thumbnail object-fit-cover hover
161
- opacity-5 ed flex bg-popup justify-content-center align-items-center flex-shrink-0" icon="description"
162
- :class="{ active: currentIndex === index }" @click="selectItem(index)"
163
- />
164
- </template>
165
- </div>
138
+ </div>
139
+ </template>
140
+
141
+ <template #prev-button="{ prev }">
142
+ <Btn icon="arrow_back" color="black" @click="prev" />
143
+ </template>
144
+
145
+ <template #next-button="{ next }">
146
+ <Btn icon="arrow_forward" color="black" @click="next" />
147
+ </template>
148
+ </Swiper>
149
+
150
+ <div v-if="group && group.length > 1" class="lightbox-thumbnails" @click.stop>
151
+ <template v-for="(item, index) in group" :key="index">
152
+ <Image
153
+ v-if="item.type === 'image'" class="thumbnail" :src="item.src" alt=""
154
+ :class="{ active: currentIndex === index }" @click.stop="selectItem(index)"
155
+ />
156
+ <Icon
157
+ v-else class="thumbnail thumbnail-icon" icon="description"
158
+ :class="{ active: currentIndex === index }" @click.stop="selectItem(index)"
159
+ />
160
+ </template>
166
161
  </div>
167
162
  </div>
168
163
  </transition>
@@ -189,70 +184,225 @@ defineExpose({ open, close })
189
184
  }
190
185
 
191
186
  .bgl-lightbox-overlay {
187
+ position: fixed;
188
+ width: 100vw;
189
+ height: 100vh;
190
+ display: grid;
191
+ grid-template-rows: 50px 1fr 100px;
192
+ z-index: 9999;
193
+ inset: 0;
192
194
  background: rgba(0, 0, 0, 0.8);
195
+ overflow: hidden;
193
196
  }
194
197
 
195
- .bgl-lightbox {
196
- max-height: 90%;
198
+ /* Top controls row */
199
+ .bgl-lightbox-overlay>.flex:first-child {
200
+ grid-row: 1;
201
+ align-self: start;
202
+ }
203
+
204
+ /* Main content row - Swiper */
205
+ .bgl-lightbox-swiper {
206
+ grid-row: 2;
207
+ width: 100vw;
208
+ height: 100%;
209
+ overflow: hidden;
210
+ }
211
+
212
+ /* Bottom thumbnails row */
213
+ .lightbox-thumbnails {
214
+ grid-row: 3;
215
+ align-self: end;
216
+ }
217
+
218
+ .bgl-lightbox-swiper .swiper {
219
+ width: 100%;
220
+ height: 100%;
221
+ }
222
+
223
+ .bgl-lightbox-swiper .swiper-wrapper {
224
+ align-items: center;
197
225
  }
198
226
 
199
227
  .bgl-lightbox-item {
200
- animation: 500ms ease bgl-lightbox-load;
228
+ display: flex;
229
+ align-items: center;
230
+ justify-content: center;
231
+ width: 100%;
232
+ height: 100%;
233
+ animation: 200ms ease bgl-lightbox-load;
234
+ }
235
+
236
+ /* Navigation button styling */
237
+ .lightbox-nav-btn {
238
+ background: rgba(0, 0, 0, 0.6);
239
+ backdrop-filter: blur(8px);
240
+ border-radius: 50%;
241
+ width: 48px;
242
+ height: 48px;
243
+ display: flex;
244
+ align-items: center;
245
+ justify-content: center;
246
+ color: white;
247
+ cursor: pointer;
248
+ transition: all 0.2s ease;
249
+ }
250
+
251
+ .lightbox-nav-btn:hover {
252
+ background: rgba(0, 0, 0, 0.8);
253
+ transform: scale(1.05);
254
+ }
255
+
256
+ .lightbox-nav-btn:active {
257
+ transform: scale(0.95);
258
+ }
259
+
260
+ /* Adjust swiper navigation positioning */
261
+ .bgl-lightbox-swiper :deep(.swi-ctrl) {
262
+ padding: 0 1.5rem !important;
263
+ }
264
+
265
+ @media screen and (max-width: 900px) {
266
+ .bgl-lightbox-swiper :deep(.swi-ctrl) {
267
+ padding: 0 1rem !important;
268
+ }
269
+
270
+ .lightbox-nav-btn {
271
+ width: 40px;
272
+ height: 40px;
273
+ }
201
274
  }
202
275
 
203
276
  @keyframes bgl-lightbox-load {
204
277
  from {
205
- scale: 0.7;
278
+ opacity: 0;
279
+ transform: scale(0.95);
206
280
  }
207
281
 
208
282
  to {
209
- scale: 1;
210
-
283
+ opacity: 1;
284
+ transform: scale(1);
211
285
  }
212
286
  }
213
287
 
214
- .bgl-lightbox-item * {
215
- max-height: calc(80vh - 90px);
288
+ .lightbox-image,
289
+ .lightbox-video,
290
+ .lightbox-pdf,
291
+ .lightbox-file {
292
+ max-width: 90vw;
293
+ max-height: calc(100vh - 140px);
294
+ object-fit: contain;
216
295
  border-radius: 3px;
217
296
  margin: auto;
218
- animation: 200ms ease bgl-lightbox-load;
219
- transition: max-height 200ms ease;
220
297
  }
221
298
 
222
- .bgl-lightbox-item.zoomed * {
299
+ .lightbox-image {
300
+ width: auto;
301
+ height: auto;
302
+ }
303
+
304
+ /* When zoomed, make image full width */
305
+ .bgl-lightbox-swiper.zoomed .lightbox-image {
306
+ max-width: 100vw;
307
+ width: 100vw;
308
+ max-height: 100vh;
309
+ height: 100vh;
310
+ object-fit: contain;
311
+ }
312
+
313
+ .bgl-lightbox-swiper.zoomed .vue-zoomer {
314
+ width: 100vw;
315
+ height: 100vh;
316
+ }
317
+
318
+ .bgl-lightbox-swiper.zoomed .bgl-lightbox-item * {
223
319
  max-height: calc(100vh - 90px);
224
320
  height: calc(100vh - 90px);
225
321
  }
226
322
 
227
- .bgl-lightbox-item.zoomed {
323
+ .bgl-lightbox-swiper.zoomed {
228
324
  pointer-events: none;
229
325
  }
230
326
 
231
- .bgl-lightbox-item.zoomed .vue-zoomer {
327
+ .bgl-lightbox-swiper.zoomed .vue-zoomer {
232
328
  pointer-events: auto;
233
329
  }
234
330
 
235
- .navigation {
236
- top: 50%;
237
- transform: translateY(-50%);
331
+ .lightbox-thumbnails {
332
+ display: flex;
333
+ justify-content: center;
334
+ align-items: center;
335
+ gap: 0.75rem;
336
+ padding: 1rem;
337
+ overflow-x: auto;
338
+ overflow-y: hidden;
339
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.4) 0%, transparent 100%);
340
+ width: 100%;
341
+ }
342
+
343
+ .lightbox-thumbnails::-webkit-scrollbar {
344
+ height: 4px;
345
+ }
346
+
347
+ .lightbox-thumbnails::-webkit-scrollbar-track {
348
+ background: transparent;
349
+ }
350
+
351
+ .lightbox-thumbnails::-webkit-scrollbar-thumb {
352
+ background: rgba(255, 255, 255, 0.3);
353
+ border-radius: 2px;
238
354
  }
239
355
 
240
356
  .thumbnail {
241
- height: 50px;
242
- width: 50px;
357
+ height: 60px;
358
+ width: 60px;
359
+ min-width: 60px;
360
+ object-fit: cover;
361
+ border-radius: 6px;
362
+ cursor: pointer;
363
+ opacity: 0.6;
364
+ transition: all 0.2s ease;
365
+ flex-shrink: 0;
366
+ }
367
+
368
+ .thumbnail-icon {
369
+ display: flex;
370
+ align-items: center;
371
+ justify-content: center;
372
+ background: rgba(255, 255, 255, 0.1);
243
373
  }
244
374
 
245
375
  .thumbnail:hover {
246
376
  opacity: 1;
377
+ transform: scale(1.05);
247
378
  }
248
379
 
249
380
  .thumbnail:active {
250
- opacity: 0.8;
381
+ transform: scale(0.95);
251
382
  }
252
383
 
253
384
  .thumbnail.active {
254
385
  opacity: 1;
255
- outline: 2px solid white;
386
+ outline: 3px solid white;
387
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
388
+ }
389
+
390
+ @media screen and (max-width: 910px) {
391
+ .bgl-lightbox-overlay {
392
+ grid-template-rows: 50px 1fr 70px;
393
+ }
394
+
395
+ .lightbox-thumbnails {
396
+ justify-content: flex-start;
397
+ gap: 0.5rem;
398
+ padding: 0.75rem 1rem;
399
+ }
400
+
401
+ .thumbnail {
402
+ height: 50px;
403
+ width: 50px;
404
+ min-width: 50px;
405
+ }
256
406
  }
257
407
 
258
408
  .file-info {
@@ -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 (-1 === currentIndex) {groups[item.group].push(item)}
37
+ if (currentIndex === -1) { 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 || 'string' !== typeof url) {return ''}
63
+ if (!url || typeof url !== 'string') { 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 ('string' !== typeof url || !url) {return 'unknown'}
69
+ if (typeof url !== 'string' || !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
 
@@ -2,7 +2,7 @@ import type { BglFormSchemaT, IfAny } from '@bagelink/vue'
2
2
 
3
3
  import type { MaybeRefOrGetter, Ref, UnwrapRef } from 'vue'
4
4
  import { getFallbackSchema } from '@bagelink/vue'
5
- import { ref, toValue, watch } from 'vue'
5
+ import { computed, ref, toValue, watch } from 'vue'
6
6
 
7
7
  export { useAddToCalendar } from './useAddToCalendar'
8
8
  export { getBagelInstance, setBagelInstance, useBagel } from './useBagel'
@@ -19,17 +19,17 @@ interface UseBglSchemaParamsT<T> {
19
19
  export function useBglSchema<T = { [key: string]: unknown }>(
20
20
  { schema, columns, data }: UseBglSchemaParamsT<T> = {}
21
21
  ): BglFormSchemaT<T> {
22
- const _schema = $computed(() => toValue(schema))
23
- const _columns = $computed(() => toValue(columns))
22
+ const _schema = computed(() => toValue(schema))
23
+ const _columns = computed(() => toValue(columns))
24
24
 
25
- if (_schema) {
25
+ if (_schema.value) {
26
26
  return (
27
- _columns && _columns.length > 0
28
- ? _schema.filter(f => _columns.includes(f.id as string))
29
- : _schema
27
+ _columns.value && _columns.value.length > 0
28
+ ? _schema.value.filter(f => _columns.value?.includes(f.id as string))
29
+ : _schema.value
30
30
  ) as BglFormSchemaT<T>
31
31
  }
32
- return getFallbackSchema(data, _columns)
32
+ return getFallbackSchema(data, _columns.value)
33
33
  }
34
34
 
35
35
  export function localRef<T>(