vite-plugin-entry-shaking-debugger
Version:
Debugger for vite-plugin-entry-shaking
86 lines (74 loc) • 2.66 kB
text/typescript
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,
};
}