UNPKG

vite-plugin-entry-shaking-debugger

Version:
86 lines (74 loc) 2.66 kB
import type { Ref } from 'vue'; import { ref, computed, onMounted } from 'vue'; import { useResizeObserver } from '@vueuse/core'; import type { ShortEmits } from '#uitypes'; import type { VirtualScrollEvents, VirtualScrollProps } from './VirtualScroll.types'; export const VIRTUAL_SCROLL_WRAPPER_CLASS = '__virtual-scroll-wrapper'; export function useVirtualScroll( containerRef: Ref<HTMLElement | null>, contentRef: Ref<HTMLElement | null>, props: VirtualScrollProps, emit: ShortEmits<VirtualScrollEvents>, ) { const scroll = ref(0); const axisSizeProp = computed(() => (props.axis === 'x' ? 'width' : 'height')); const axisTranslateProp = computed(() => (props.axis === 'x' ? 'translateX' : 'translateY')); const totalCount = computed(() => props.items.length); const contentSize = computed(() => totalCount.value * props.itemSize); const startIndex = computed(() => Math.max( 0, Math.floor(scroll.value / props.itemSize) - (props.padding ?? 0) - (props.prerenderedBeforeStart ?? 0), ), ); const offset = computed(() => startIndex.value * props.itemSize); const nbVisible = computed(() => { const containerSize = containerRef.value?.getBoundingClientRect()[axisSizeProp.value] ?? 0; return ( Math.min( totalCount.value - startIndex.value, Math.ceil(containerSize / props.itemSize) + 2 * (props.padding ?? 0), ) + (props.prerenderAfterEnd ?? 0) ); }); const visibleItems = computed(() => props.items.slice(startIndex.value, startIndex.value + nbVisible.value), ); const itemStyle = computed( () => ({ position: 'relative', height: `${props.itemSize}px` }) as const, ); const containerStyle = computed(() => ({ overflow: 'auto' }) as const); const contentStyle = computed(() => getElementStyle(contentSize.value, 'hidden')); const wrapperStyle = computed( () => ({ transform: `${axisTranslateProp.value}(${offset.value}px)` }) as const, ); const getElementStyle = (size: number, overflow: 'auto' | 'hidden') => ({ [axisSizeProp.value]: `${size}px`, overflow, }); const updateScrollPosition = () => { scroll.value = containerRef.value?.scrollTop ?? 0; emit('scroll'); }; const observeResize = () => { useResizeObserver(containerRef, (entries) => { const entry = entries[0]; const { width, height } = entry.contentRect; emit('resize', { width, height }); }); }; onMounted(() => { updateScrollPosition(); }); return { observeResize, updateScrollPosition, visibleItems, containerStyle, contentStyle, wrapperStyle, itemStyle, }; }