@fy-/fws-vue 2.3.16 → 2.3.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.
@@ -155,67 +155,74 @@ function adjustImageSize(img: HTMLImageElement, availableHeightPx: number) {
155
155
  }
156
156
  }
157
157
 
158
- // Image size and positioning
158
+ // Image size and positioning - improved to prevent overflow
159
159
  const calculateImageSize = useDebounceFn(() => {
160
160
  if (!imageContainerRef.value) return
161
161
 
162
- nextTick(() => {
163
- const imageElements = imageContainerRef.value?.querySelectorAll('.image-display img, .image-display .video-component') as NodeListOf<HTMLElement>
162
+ // Execute immediately without waiting for nextTick to prevent delayed resizing
163
+ const imageElements = imageContainerRef.value?.querySelectorAll('.image-display img, .image-display .video-component') as NodeListOf<HTMLElement>
164
164
 
165
- if (!imageElements || imageElements.length === 0) return
165
+ if (!imageElements || imageElements.length === 0) return
166
166
 
167
- // Get current panel heights for accurate calculations
168
- const topControlsCurrentHeight = topControlsRef.value?.offsetHeight || 0
169
- const infoPanelCurrentHeight = infoPanel.value && infoPanelRef.value ? infoPanelRef.value.offsetHeight : 0
167
+ // Get current panel heights for accurate calculations
168
+ const topControlsCurrentHeight = topControlsRef.value?.offsetHeight || 0
169
+ const infoPanelCurrentHeight = infoPanel.value && infoPanelRef.value ? infoPanelRef.value.offsetHeight : 0
170
170
 
171
- // Prepare for image sizing calculation
171
+ // Apply sizing to all images
172
+ imageElements.forEach((img) => {
173
+ // Reset immediately to ensure proper recalculation
174
+ img.style.maxHeight = '0'
175
+ img.style.maxWidth = '0'
172
176
 
173
- imageElements.forEach((img) => {
174
- // Reset to ensure proper recalculation
175
- img.style.maxHeight = ''
176
- img.style.maxWidth = ''
177
- // Force browser to recalculate styles
178
- void img.offsetHeight
177
+ // Force browser to recalculate styles
178
+ void img.offsetHeight
179
179
 
180
- // Apply exact pixel measurements based on actual UI elements
181
- const topHeight = topControlsCurrentHeight || 0
182
- const infoHeight = infoPanelCurrentHeight || 0
183
- const availableHeightPx = windowHeight.value - topHeight - infoHeight - 32 // 32px for padding
180
+ // Apply exact pixel measurements based on actual UI elements
181
+ const topHeight = topControlsCurrentHeight || 0
182
+ const infoHeight = infoPanelCurrentHeight || 0
183
+ // Increase padding for reliable containment - prevent overflow
184
+ const availableHeightPx = windowHeight.value - topHeight - infoHeight - 48
184
185
 
185
- if (windowWidth.value <= 768) {
186
- // Mobile specific sizing - use pixel values directly
187
- img.style.maxHeight = `${availableHeightPx}px`
188
- img.style.maxWidth = '90vw'
189
- }
190
- else {
191
- // Desktop sizing - account for sidebar if present
192
- const sidebarWidth = sidePanel.value ? sidePanelRef.value?.offsetWidth || 256 : 0
193
- const availableWidthPx = windowWidth.value - sidebarWidth - 48 // 48px for padding
186
+ if (windowWidth.value <= 768) {
187
+ // Mobile specific sizing - more conservative to guarantee fit
188
+ img.style.maxHeight = `${availableHeightPx}px`
189
+ img.style.maxWidth = '85vw' // Reduce from 90vw to ensure it fits
190
+ }
191
+ else {
192
+ // Desktop sizing - account for sidebar if present
193
+ const sidebarWidth = sidePanel.value ? sidePanelRef.value?.offsetWidth || 256 : 0
194
+ // More conservative width calculation to prevent overflow
195
+ const availableWidthPx = windowWidth.value - sidebarWidth - 64
194
196
 
195
- img.style.maxHeight = `${availableHeightPx}px`
196
- img.style.maxWidth = `${availableWidthPx}px`
197
- }
197
+ img.style.maxHeight = `${availableHeightPx}px`
198
+ img.style.maxWidth = `${availableWidthPx}px`
199
+ }
198
200
 
199
- // For images, add special handling for natural dimensions
200
- if (img instanceof HTMLImageElement) {
201
- if (img.complete) {
202
- adjustImageSize(img, availableHeightPx)
203
- }
204
- else {
205
- img.onload = () => adjustImageSize(img, availableHeightPx)
206
- }
201
+ // For images, add special handling for natural dimensions
202
+ if (img instanceof HTMLImageElement) {
203
+ if (img.complete) {
204
+ adjustImageSize(img, availableHeightPx)
207
205
  }
208
- })
206
+ else {
207
+ img.onload = () => adjustImageSize(img, availableHeightPx)
208
+ }
209
+ }
209
210
  })
210
- }, 50)
211
+ }, 10) // Reduced debounce time for faster response
211
212
 
212
213
  // Update all layout measurements when any relevant state changes
214
+ // More aggressive calculation to prevent layout issues
213
215
  const updateLayout = useDebounceFn(() => {
214
- // Recalculate image size with a small delay to ensure all DOM updates are processed
216
+ // Calculate immediately
217
+ calculateImageSize()
218
+
219
+ // Then again after a small delay to catch any delayed DOM updates
215
220
  setTimeout(() => {
216
221
  calculateImageSize()
222
+ // And one more time for extra safety after all transitions
223
+ setTimeout(() => calculateImageSize(), 100)
217
224
  }, 10)
218
- }, 50)
225
+ }, 10) // Reduced debounce time for faster response
219
226
 
220
227
  // Modal controls
221
228
  function setModal(value: boolean) {
@@ -272,9 +279,14 @@ const openGalleryImage = useDebounceFn((index: number | undefined) => {
272
279
  })
273
280
  }, 50)
274
281
 
275
- // Navigation functions
282
+ // Navigation functions - improved for immediate sizing
276
283
  function goNextImage() {
277
284
  direction.value = 'next'
285
+
286
+ // Calculate size immediately before changing the image
287
+ // This ensures we have proper sizing before transition starts
288
+ calculateImageSize()
289
+
278
290
  if (modelValue.value < props.images.length - 1) {
279
291
  modelValue.value++
280
292
  }
@@ -283,14 +295,23 @@ function goNextImage() {
283
295
  }
284
296
  resetControlsTimer()
285
297
 
286
- // Force layout update when image changes
298
+ // Force immediate layout update when image changes
299
+ calculateImageSize()
300
+
301
+ // Another calculation after DOM is updated to ensure correct sizing
287
302
  nextTick(() => {
288
- updateLayout()
303
+ calculateImageSize()
304
+ // Second calculation after a small delay to catch any late DOM changes
305
+ setTimeout(() => calculateImageSize(), 50)
289
306
  })
290
307
  }
291
308
 
292
309
  function goPrevImage() {
293
310
  direction.value = 'prev'
311
+
312
+ // Calculate size immediately before changing the image
313
+ calculateImageSize()
314
+
294
315
  if (modelValue.value > 0) {
295
316
  modelValue.value--
296
317
  }
@@ -299,9 +320,14 @@ function goPrevImage() {
299
320
  }
300
321
  resetControlsTimer()
301
322
 
302
- // Force layout update when image changes
323
+ // Force immediate layout update when image changes
324
+ calculateImageSize()
325
+
326
+ // Another calculation after DOM is updated to ensure correct sizing
303
327
  nextTick(() => {
304
- updateLayout()
328
+ calculateImageSize()
329
+ // Second calculation after a small delay to catch any late DOM changes
330
+ setTimeout(() => calculateImageSize(), 50)
305
331
  })
306
332
  }
307
333
 
@@ -678,6 +704,7 @@ onUnmounted(() => {
678
704
  <div
679
705
  :key="`image-display-${modelValue}`"
680
706
  class="image-display relative w-full h-full flex flex-col items-center justify-center"
707
+ @transitionend="calculateImageSize"
681
708
  >
682
709
  <!-- Actual Image/Video Content -->
683
710
  <template v-if="videoComponent && isVideo(images[modelValue])">
@@ -697,7 +724,7 @@ onUnmounted(() => {
697
724
  :style="{ maxHeight: availableHeight }"
698
725
  :src="modelValueSrc"
699
726
  :alt="`Gallery image ${modelValue + 1}`"
700
- @load="updateLayout"
727
+ @load="() => { calculateImageSize(); nextTick(() => calculateImageSize()) }"
701
728
  >
702
729
  <component
703
730
  :is="imageComponent"
@@ -773,7 +800,7 @@ onUnmounted(() => {
773
800
  v-if="sidePanel"
774
801
  ref="sidePanelRef"
775
802
  class="side-panel hidden lg:block absolute right-0 top-0 bottom-0 w-64 bg-fv-neutral-800/90 backdrop-blur-md overflow-y-auto z-40 cool-scroll"
776
- :style="{ 'padding-top': `${topControlsHeight}px` }"
803
+ :style="{ 'padding-top': `${topControlsHeight + 8}px` }"
777
804
  >
778
805
  <!-- Paging Controls if needed -->
779
806
  <div v-if="paging" class="flex items-center justify-center pt-2">
@@ -839,10 +866,13 @@ onUnmounted(() => {
839
866
  >
840
867
  <div
841
868
  v-if="showControls && images.length > 1 && !sidePanel"
842
- class="absolute bottom-0 left-0 right-0 p-2 lg:hidden bg-gradient-to-t from-fv-neutral-900/90 to-transparent backdrop-blur-sm z-45"
843
- :class="{ 'pb-20': infoPanel }"
869
+ class="absolute bottom-0 left-0 right-0 p-1 pb-2 lg:hidden bg-gradient-to-t from-fv-neutral-900/90 to-transparent backdrop-blur-sm z-45"
870
+ :class="{ 'pb-4': infoPanel }"
871
+ @touchstart.stop
872
+ @touchmove.stop
873
+ @touchend.stop
844
874
  >
845
- <div class="overflow-x-auto flex space-x-2 pb-1 px-1">
875
+ <div class="overflow-x-auto flex space-x-2 px-1 no-scrollbar">
846
876
  <div
847
877
  v-for="(image, idx) in images"
848
878
  :key="`mobile_thumb_${id}_${idx}`"
@@ -1172,4 +1202,14 @@ onUnmounted(() => {
1172
1202
  font-size: 0.75rem;
1173
1203
  z-index: 10;
1174
1204
  }
1205
+
1206
+ /* Special class to hide scrollbars on mobile */
1207
+ .no-scrollbar {
1208
+ -ms-overflow-style: none; /* IE and Edge */
1209
+ scrollbar-width: none; /* Firefox */
1210
+ }
1211
+
1212
+ .no-scrollbar::-webkit-scrollbar {
1213
+ display: none; /* Chrome, Safari and Opera */
1214
+ }
1175
1215
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fy-/fws-vue",
3
- "version": "2.3.16",
3
+ "version": "2.3.17",
4
4
  "author": "Florian 'Fy' Gasquez <m@fy.to>",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/fy-to/FWJS#readme",