# ngx-pretext-table
Variable-height virtual scrolling for PrimeNG `p-table`, powered by [@chenglou/pretext](https://github.com/chenglou/pretext).
PrimeNG's built-in virtual scroll only supports **fixed row heights** (`virtualScrollItemSize`). This library replaces it with pretext-calculated variable row heights — no DOM measurement, no layout thrashing, O(log n) scroll lookup.
## Install
```bash
npm install ngx-pretext-table @chenglou/pretext
```
## Usage
```typescript
import { Component } from '@angular/core';
import { TableModule } from 'primeng/table';
import {
PretextVirtualScrollDirective,
PretextScrollEvent,
PretextColumnDef,
} from 'ngx-pretext-table';
@Component({
standalone: true,
imports: [TableModule, PretextVirtualScrollDirective],
template: `
| {{ row.name }} |
{{ row.description }} |
`,
})
export class MyComponent {
data = [/* your data */];
// field + available text width (column width minus padding)
columns: PretextColumnDef[] = [
{ field: 'name', width: 184 },
{ field: 'description', width: 384 },
];
visibleData: any[] = [];
rowHeights: number[] = [];
onRange(e: PretextScrollEvent) {
this.visibleData = this.data.slice(e.start, e.end);
this.rowHeights = e.rowHeights;
}
}
```
## API
### `PretextVirtualScrollDirective`
| Input | Type | Default | Description |
|-------|------|---------|-------------|
| `data` | `any[]` | required | Full data array |
| `columns` | `PretextColumnDef[]` | required | Column field + text width |
| `font` | `string` | `'14px system-ui'` | CSS font shorthand |
| `lineHeight` | `number` | `20` | Line height in px |
| `rowPadding` | `number` | `16` | Vertical padding per row |
| `minRowHeight` | `number` | `32` | Minimum row height |
| `rowGap` | `number` | `0` | Gap between rows |
| `scrollHeight` | `string` | `'400px'` | Viewport height |
| `bufferRows` | `number` | `5` | Buffer rows above/below |
| Output | Type | Description |
|--------|------|-------------|
| `visibleRangeChange` | `PretextScrollEvent` | Emits when visible range changes |
| Method | Description |
|--------|-------------|
| `scrollToIndex(index, behavior?)` | Scroll to a specific row |
### `PretextRowHeightService`
Low-level service for direct control:
```typescript
const cache = service.prepareRows(data, columns, font);
const heights = service.calculateRowHeights(cache, columns, lineHeight, padding);
const positions = service.buildPositionIndex(heights);
const range = service.findVisibleRange(positions, scrollTop, viewportHeight);
```
## How it works
1. **Prepare** (once) — `@chenglou/pretext` segments text and measures via canvas
2. **Layout** (on resize) — pure arithmetic, ~0.0002ms per cell, no DOM access
3. **Scroll** (continuous) — O(log n) binary search in cumulative position arrays
## License
MIT