import React, { HTMLAttributes, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useSize } from '../../hooks'; import { SilkeVirtualRow } from './silke-virtual-row'; import styles from './silke-virtual.scss'; type SilkeVirtualGridProps = { cell?: [width: number, height: number]; items: T[]; children: (item: T, index: number) => React.ReactNode; rowAttrs?: (rowIndex: number) => Omit, 'children'>; } & Omit, 'children'>; export function SilkeVirtualGrid({ items, cell, children, rowAttrs, className, style, ...rest }: SilkeVirtualGridProps) { let cl = styles.grid; if (className) cl += ' ' + className; const [columns, setColumns] = useState(1); const ref = useRef(null); const [width, height] = cell || [32, 32]; useSize(ref, (entry) => { const newColumns = Math.floor(entry.contentRect.width / width); if (newColumns !== columns && newColumns > 0) setColumns(newColumns); }); useLayoutEffect(() => { const el = ref.current; if (el) { setColumns(Math.max(Math.floor(el.getBoundingClientRect().width / width), 1)); } }, [width]); const list = useMemo(() => { const list: any[] = []; if (columns === 0) return list; const rows = Math.ceil(items.length / columns); for (let i = 0; i < rows; i++) { const start = i * columns; const end = Math.min(start + columns, items.length); list.push( {children} , ); } return list; }, [columns, items, children, rowAttrs]); return (
{list}
); }