# SilkeVirtualGrid

A high-performance virtualized grid component that only renders items visible in the viewport. Use this for displaying large lists or grids with thousands of items without performance degradation.

## Features

- **Virtualized rendering**: Only renders visible rows using IntersectionObserver
- **Automatic column calculation**: Computes columns based on container width and cell size
- **Responsive layout**: Recalculates on resize
- **Minimal DOM nodes**: Keeps DOM size small for massive datasets
- **Custom cell sizes**: Configure width and height per cell
- **Row attributes**: Attach custom attributes to individual rows

## Basic Usage

```js
const items = Array.from({ length: 100 }, (_, i) => ({ id: i, name: `Item ${i}` }));

<SilkeVirtualGrid items={items} cell={[100, 40]}>
  {(item) => (
    <SilkeBox key={item.id} pad="s" style={{ border: '1px solid var(--color-neutral-20)' }}>
      <SilkeText>{item.name}</SilkeText>
    </SilkeBox>
  )}
</SilkeVirtualGrid>;
```

## Icon Grid

Display a large grid of icons efficiently:

```js
const icons = Array.from({ length: 200 }, (_, i) => `icon-${i}`);

<SilkeBox style={{ height: 300, overflow: 'auto' }}>
  <SilkeVirtualGrid items={icons} cell={[48, 48]}>
    {(icon, index) => (
      <SilkeBox key={index} size="base" vAlign="center" hAlign="center">
        <SilkeIcon icon="star" />
      </SilkeBox>
    )}
  </SilkeVirtualGrid>
</SilkeBox>;
```

## Large Dataset

Handle thousands of items with smooth scrolling:

```js
const items = Array.from({ length: 5000 }, (_, i) => ({
  id: i,
  color: `hsl(${(i * 7) % 360}, 70%, 60%)`,
}));

<SilkeBox style={{ height: 400, overflow: 'auto' }}>
  <SilkeVirtualGrid items={items} cell={[40, 40]}>
    {(item) => (
      <div
        key={item.id}
        style={{
          width: 36,
          height: 36,
          background: item.color,
          borderRadius: 4,
        }}
      />
    )}
  </SilkeVirtualGrid>
</SilkeBox>;
```

## Custom Cell Dimensions

Adjust cell width and height for different layouts:

```js
const cards = Array.from({ length: 50 }, (_, i) => ({
  id: i,
  title: `Card ${i + 1}`,
  description: `Description for card ${i + 1}`,
}));

<SilkeBox style={{ height: 400, overflow: 'auto' }}>
  <SilkeVirtualGrid items={cards} cell={[200, 120]}>
    {(card) => (
      <SilkeCard key={card.id} style={{ width: 190, height: 110, margin: 4 }}>
        <SilkeBox column pad="s" gap="xs">
          <SilkeText weight="medium">{card.title}</SilkeText>
          <SilkeText size="s" color="neutral-60">
            {card.description}
          </SilkeText>
        </SilkeBox>
      </SilkeCard>
    )}
  </SilkeVirtualGrid>
</SilkeBox>;
```

## With Row Attributes

Add custom attributes or event handlers to rows:

```js
const items = Array.from({ length: 100 }, (_, i) => ({ id: i }));

<SilkeBox style={{ height: 300, overflow: 'auto' }}>
  <SilkeVirtualGrid
    items={items}
    cell={[60, 60]}
    rowAttrs={(rowIndex) => ({
      'data-row': rowIndex,
      style: { background: rowIndex % 2 === 0 ? 'var(--color-neutral-5)' : 'transparent' },
    })}
  >
    {(item) => (
      <SilkeBox key={item.id} size="base" vAlign="center" hAlign="center">
        <SilkeText>{item.id}</SilkeText>
      </SilkeBox>
    )}
  </SilkeVirtualGrid>
</SilkeBox>;
```

## Props

| Prop       | Type                                                              | Default    | Description                               |
| ---------- | ----------------------------------------------------------------- | ---------- | ----------------------------------------- |
| `items`    | `T[]`                                                             | Required   | Array of items to render                  |
| `children` | `(item: T, index: number) => React.ReactNode`                     | Required   | Render function for each item             |
| `cell`     | `[width: number, height: number]`                                 | `[32, 32]` | Cell dimensions in pixels                 |
| `rowAttrs` | `(rowIndex: number) => HTMLAttributes<HTMLDivElement>`            | -          | Custom attributes for each row            |
| `className`| `string`                                                          | -          | Additional CSS class name                 |
| `style`    | `React.CSSProperties`                                             | -          | Inline styles                             |

Also accepts all standard HTML `div` attributes.

## How It Works

1. **Column calculation**: The grid measures its container width and divides by cell width to determine columns
2. **Row chunking**: Items are split into rows based on column count
3. **IntersectionObserver**: Each row observes its visibility in the viewport
4. **Lazy rendering**: Only visible rows render their children
5. **Global observer**: A single shared IntersectionObserver handles all rows efficiently

## Performance Characteristics

- **Ideal for**: Lists/grids with 1000+ items
- **DOM efficiency**: Only visible rows + their cells exist in DOM
- **Memory**: Single IntersectionObserver for all rows
- **Cleanup**: Listeners are properly removed on unmount

## CSS Variable

The grid sets `--cell-height` CSS variable which can be used for styling:

```css
.my-grid-item {
  height: var(--cell-height);
}
```
