All files / src/components VirtualFor.ts

100% Statements 50/50
100% Branches 5/5
100% Functions 5/5
100% Lines 50/50

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 701x 1x 1x                         1x 3x   3x 3x 3x 3x 3x   3x 3x 3x 3x 3x 3x 3x 3x 3x 3x   3x 3x 3x 3x 3x 3x   3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x   3x 3x 3x 3x 68x 68x 68x 3x   3x 3x 3x   3x 3x  
import { h } from '../h';
import { For } from './For';
import { createVirtualizer } from './virtualizer';
import type { SignalGetter } from '../types';
 
interface VirtualForProps<T> {
  each: SignalGetter<T[]>;
  itemHeight: number;
  children: (item: T, index: number) => HTMLElement;
  placeholder?: HTMLElement;
  overscan?: number;
  class?: string;
  style?: Record<string, string | SignalGetter<string>>;
}
 
export function VirtualFor<T>(props: VirtualForProps<T>): HTMLElement {
  const { each, children, itemHeight, overscan, class: className, style } = props; //, placeholder
 
  const virtualizer = createVirtualizer({
    items: each,
    itemHeight,
    overscan,
  });
 
  const container = h.div({
    ref: virtualizer.setContainer,
    class: className,
    role: 'list',
    style: {
      overflow: 'auto',
      height: '100%',
      ...style,
    },
  });
 
  const sizer = h.div({
    style: {
      position: 'relative',
      height: () => `${virtualizer.totalHeight()}px`,
    },
  });
 
  const content = h.div({
    style: {
      position: 'absolute',
      top: '0',
      left: '0',
      width: '100%',
      willChange: 'transform',
      contain: 'layout',
      transform: () => `translate3d(0, ${virtualizer.visibleState().scrollOffset}px, 0)`,
    },
  });
 
  const renderedItems = For({
    each: virtualizer.visibleItems,
    key: (item) => item.index,
    children: (itemSignal) => {
      const it = itemSignal();
      return children(it.data as T, it.index);
    },
  });
 
  content.appendChild(renderedItems);
  sizer.appendChild(content);
  container.appendChild(sizer);
 
  return container;
}