or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-components.mddynamic-content.mdindex.mdlayout-components.mdnavigation-components.mdspecialized-layouts.mdtable-components.mdutilities.md

utilities.mddocs/

0

# Utility Functions

1

2

Helper functions and utilities for customizing virtualization behavior and enhancing performance.

3

4

## Capabilities

5

6

### Overscan Index Getters

7

8

Functions that calculate which additional (non-visible) items to render for smooth scrolling.

9

10

```javascript { .api }

11

/**

12

* Default overscan calculation for standard usage

13

* @param params - Overscan calculation parameters

14

*/

15

function defaultOverscanIndicesGetter(params: {

16

/** Total number of cells */

17

cellCount: number,

18

/** Number of extra cells to render */

19

overscanCellsCount: number,

20

/** Scroll direction (-1 for backward, 1 for forward) */

21

scrollDirection: number,

22

/** Index of first visible cell */

23

startIndex: number,

24

/** Index of last visible cell */

25

stopIndex: number

26

}): {

27

/** Index of first cell to render (including overscan) */

28

overscanStartIndex: number,

29

/** Index of last cell to render (including overscan) */

30

overscanStopIndex: number

31

};

32

33

/**

34

* Enhanced overscan calculation for accessibility

35

* Renders more cells to improve screen reader performance

36

* @param params - Overscan calculation parameters

37

*/

38

function accessibilityOverscanIndicesGetter(params: {

39

cellCount: number,

40

overscanCellsCount: number,

41

/** Scroll direction (-1 for backward, 1 for forward) */

42

scrollDirection: number,

43

startIndex: number,

44

stopIndex: number

45

}): {

46

overscanStartIndex: number,

47

overscanStopIndex: number

48

};

49

```

50

51

**Usage Examples:**

52

53

```javascript

54

import React from 'react';

55

import {

56

List,

57

Grid,

58

defaultOverscanIndicesGetter,

59

accessibilityOverscanIndicesGetter

60

} from 'react-virtualized';

61

62

// List with custom overscan calculation

63

function CustomOverscanList({ items, highPerformanceMode }) {

64

// Custom overscan getter that adjusts based on performance mode

65

const customOverscanGetter = (params) => {

66

if (highPerformanceMode) {

67

// Render fewer extra items for better performance

68

return defaultOverscanIndicesGetter({

69

...params,

70

overscanCellsCount: Math.min(params.overscanCellsCount, 2)

71

});

72

} else {

73

// Use accessibility mode for better UX

74

return accessibilityOverscanIndicesGetter(params);

75

}

76

};

77

78

const rowRenderer = ({ index, key, style }) => (

79

<div key={key} style={style} className="list-item">

80

{items[index]}

81

</div>

82

);

83

84

return (

85

<div>

86

<div className="performance-indicator">

87

Mode: {highPerformanceMode ? 'High Performance' : 'Accessibility'}

88

</div>

89

<List

90

height={400}

91

width={300}

92

rowCount={items.length}

93

rowHeight={50}

94

rowRenderer={rowRenderer}

95

overscanIndicesGetter={customOverscanGetter}

96

overscanRowCount={5}

97

/>

98

</div>

99

);

100

}

101

102

// Grid with accessibility-focused overscan

103

function AccessibleGrid({ data }) {

104

const cellRenderer = ({ columnIndex, key, rowIndex, style }) => (

105

<div key={key} style={style} className="grid-cell">

106

{data[rowIndex][columnIndex]}

107

</div>

108

);

109

110

return (

111

<Grid

112

cellRenderer={cellRenderer}

113

columnCount={data[0].length}

114

columnWidth={100}

115

height={400}

116

rowCount={data.length}

117

rowHeight={50}

118

width={500}

119

overscanIndicesGetter={accessibilityOverscanIndicesGetter}

120

overscanColumnCount={3}

121

overscanRowCount={3}

122

/>

123

);

124

}

125

```

126

127

### Cell Range Renderer

128

129

Controls how cells are rendered within the visible and overscan ranges.

130

131

```javascript { .api }

132

/**

133

* Default cell range renderer

134

* @param params - Cell range rendering parameters

135

*/

136

function defaultCellRangeRenderer(params: {

137

/** Cache of rendered cells */

138

cellCache: object,

139

/** Cell rendering function */

140

cellRenderer: (params: {columnIndex: number, key: string, rowIndex: number, style: object}) => React.Node,

141

/** First visible column index */

142

columnStartIndex: number,

143

/** Last visible column index */

144

columnStopIndex: number,

145

/** Deferred measurement cache */

146

deferredMeasurementCache?: object,

147

/** Horizontal scroll adjustment */

148

horizontalOffsetAdjustment: number,

149

/** Whether scrolling is in progress */

150

isScrolling: boolean,

151

/** Parent component reference */

152

parent: object,

153

/** First visible row index */

154

rowStartIndex: number,

155

/** Last visible row index */

156

rowStopIndex: number,

157

/** Cache of computed styles */

158

styleCache: object,

159

/** Vertical scroll adjustment */

160

verticalOffsetAdjustment: number,

161

/** Map of visible column indices */

162

visibleColumnIndices: object,

163

/** Map of visible row indices */

164

visibleRowIndices: object

165

}): React.Node[];

166

```

167

168

**Usage Examples:**

169

170

```javascript

171

import React from 'react';

172

import { Grid, defaultCellRangeRenderer } from 'react-virtualized';

173

174

// Grid with custom cell range renderer for performance optimization

175

function OptimizedGrid({ data, enableDebugMode }) {

176

const customCellRangeRenderer = (params) => {

177

if (enableDebugMode) {

178

// Add debug information to rendered cells

179

console.log('Rendering cells:', {

180

columns: `${params.columnStartIndex}-${params.columnStopIndex}`,

181

rows: `${params.rowStartIndex}-${params.rowStopIndex}`,

182

isScrolling: params.isScrolling

183

});

184

}

185

186

// Use default renderer but with custom caching strategy

187

const cells = defaultCellRangeRenderer(params);

188

189

if (enableDebugMode) {

190

// Add debug borders to cells during scrolling

191

return cells.map(cell =>

192

React.cloneElement(cell, {

193

...cell.props,

194

style: {

195

...cell.props.style,

196

border: params.isScrolling ? '1px solid red' : '1px solid #ddd'

197

}

198

})

199

);

200

}

201

202

return cells;

203

};

204

205

const cellRenderer = ({ columnIndex, key, rowIndex, style }) => (

206

<div key={key} style={style} className="grid-cell">

207

{data[rowIndex][columnIndex]}

208

</div>

209

);

210

211

return (

212

<Grid

213

cellRenderer={cellRenderer}

214

cellRangeRenderer={customCellRangeRenderer}

215

columnCount={data[0].length}

216

columnWidth={120}

217

height={400}

218

rowCount={data.length}

219

rowHeight={50}

220

width={600}

221

/>

222

);

223

}

224

```

225

226

### Multi-Column Sort Utility

227

228

Advanced sorting utility for tables with multiple column sorting capabilities.

229

230

```javascript { .api }

231

/**

232

* Multi-column sort utility for tables

233

* @param sortFunction - Function to handle sort events

234

* @param options - Configuration options

235

*/

236

function createTableMultiSort(

237

sortFunction: (params: {sortBy: string, sortDirection: string}) => void,

238

options?: {

239

/** Default columns to sort by */

240

defaultSortBy?: Array<string>,

241

/** Default sort directions for columns */

242

defaultSortDirection?: {[key: string]: string}

243

}

244

): (params: {event: Event, sortBy: string, sortDirection: string}) => void;

245

```

246

247

**Usage Examples:**

248

249

```javascript

250

import React, { useState } from 'react';

251

import { Table, Column, createTableMultiSort, SortDirection } from 'react-virtualized';

252

253

// Advanced table with multi-column sorting

254

function MultiSortTable({ employees }) {

255

const [sortState, setSortState] = useState({

256

sortBy: ['department', 'name'],

257

sortDirection: { department: 'ASC', name: 'ASC' }

258

});

259

const [sortedData, setSortedData] = useState(employees);

260

261

const performMultiSort = (data, sortBy, sortDirection) => {

262

return [...data].sort((a, b) => {

263

for (const column of sortBy) {

264

const aVal = a[column];

265

const bVal = b[column];

266

const direction = sortDirection[column];

267

268

let result = 0;

269

if (aVal < bVal) result = -1;

270

else if (aVal > bVal) result = 1;

271

272

if (result !== 0) {

273

return direction === SortDirection.DESC ? -result : result;

274

}

275

}

276

return 0;

277

});

278

};

279

280

const multiSortHandler = createTableMultiSort(

281

({ sortBy, sortDirection }) => {

282

// Handle multi-column sort

283

const newSortBy = [sortBy];

284

const newSortDirection = { [sortBy]: sortDirection };

285

286

// Add existing sorts for multi-column sorting

287

sortState.sortBy.forEach(existingSort => {

288

if (existingSort !== sortBy) {

289

newSortBy.push(existingSort);

290

newSortDirection[existingSort] = sortState.sortDirection[existingSort];

291

}

292

});

293

294

const newSortState = {

295

sortBy: newSortBy.slice(0, 3), // Limit to 3 columns

296

sortDirection: newSortDirection

297

};

298

299

setSortState(newSortState);

300

setSortedData(performMultiSort(employees, newSortState.sortBy, newSortState.sortDirection));

301

},

302

{

303

defaultSortBy: ['department', 'name'],

304

defaultSortDirection: { department: 'ASC', name: 'ASC' }

305

}

306

);

307

308

const rowGetter = ({ index }) => sortedData[index];

309

310

// Custom header renderer showing sort priority

311

const multiSortHeaderRenderer = ({ label, dataKey, sortBy, sortDirection }) => {

312

const sortIndex = sortState.sortBy.indexOf(dataKey);

313

const isSorted = sortIndex !== -1;

314

315

return (

316

<div className="multi-sort-header">

317

<span>{label}</span>

318

{isSorted && (

319

<div className="sort-info">

320

<span className="sort-priority">{sortIndex + 1}</span>

321

<span className="sort-direction">

322

{sortState.sortDirection[dataKey] === 'ASC' ? '▲' : '▼'}

323

</span>

324

</div>

325

)}

326

</div>

327

);

328

};

329

330

return (

331

<div>

332

<div className="sort-info-panel">

333

<h4>Current Sort:</h4>

334

<ul>

335

{sortState.sortBy.map((column, index) => (

336

<li key={column}>

337

{index + 1}. {column} ({sortState.sortDirection[column]})

338

</li>

339

))}

340

</ul>

341

</div>

342

343

<Table

344

width={800}

345

height={400}

346

headerHeight={60}

347

rowHeight={40}

348

rowCount={sortedData.length}

349

rowGetter={rowGetter}

350

onHeaderClick={multiSortHandler}

351

>

352

<Column

353

label="Department"

354

dataKey="department"

355

width={150}

356

headerRenderer={multiSortHeaderRenderer}

357

/>

358

<Column

359

label="Name"

360

dataKey="name"

361

width={200}

362

headerRenderer={multiSortHeaderRenderer}

363

/>

364

<Column

365

label="Position"

366

dataKey="position"

367

width={180}

368

headerRenderer={multiSortHeaderRenderer}

369

/>

370

<Column

371

label="Salary"

372

dataKey="salary"

373

width={120}

374

headerRenderer={multiSortHeaderRenderer}

375

cellRenderer={({ cellData }) => `$${cellData.toLocaleString()}`}

376

/>

377

<Column

378

label="Start Date"

379

dataKey="startDate"

380

width={120}

381

headerRenderer={multiSortHeaderRenderer}

382

cellRenderer={({ cellData }) => new Date(cellData).toLocaleDateString()}

383

/>

384

</Table>

385

</div>

386

);

387

}

388

```

389

390

### Masonry Cell Positioner

391

392

Utility for creating position managers for masonry layouts.

393

394

```javascript { .api }

395

/**

396

* Creates a cell positioner for masonry layouts

397

* @param params - Positioner configuration

398

*/

399

function createMasonryCellPositioner(params: {

400

/** Cache for cell measurements */

401

cellMeasurerCache: CellMeasurerCache,

402

/** Number of columns in the masonry */

403

columnCount: number,

404

/** Width of each column */

405

columnWidth: number,

406

/** Space between items */

407

spacer?: number

408

}): {

409

/** Reset the positioner state */

410

reset: (params: {columnCount: number, columnWidth: number, spacer?: number}) => void;

411

};

412

```

413

414

**Usage Examples:**

415

416

```javascript

417

import React, { useMemo, useCallback } from 'react';

418

import {

419

Masonry,

420

CellMeasurerCache,

421

createMasonryCellPositioner,

422

AutoSizer

423

} from 'react-virtualized';

424

425

// Responsive masonry with dynamic positioner

426

function ResponsiveMasonryGrid({ items, containerWidth }) {

427

const cache = useMemo(() => new CellMeasurerCache({

428

defaultHeight: 200,

429

fixedWidth: true

430

}), []);

431

432

// Calculate columns based on container width

433

const columnCount = Math.max(1, Math.floor(containerWidth / 250));

434

const columnWidth = Math.floor((containerWidth - (columnCount + 1) * 10) / columnCount);

435

436

const cellPositioner = useMemo(() => {

437

return createMasonryCellPositioner({

438

cellMeasurerCache: cache,

439

columnCount,

440

columnWidth,

441

spacer: 10

442

});

443

}, [cache, columnCount, columnWidth]);

444

445

// Reset positioner when layout changes

446

const resetPositioner = useCallback(() => {

447

cellPositioner.reset({

448

columnCount,

449

columnWidth,

450

spacer: 10

451

});

452

}, [cellPositioner, columnCount, columnWidth]);

453

454

// Reset when dimensions change

455

React.useEffect(() => {

456

resetPositioner();

457

}, [resetPositioner]);

458

459

const cellRenderer = ({ index, key, parent, style }) => (

460

<CellMeasurer

461

cache={cache}

462

index={index}

463

key={key}

464

parent={parent}

465

>

466

<div style={style} className="masonry-item">

467

<img

468

src={items[index].imageUrl}

469

alt={items[index].title}

470

style={{ width: '100%', height: 'auto' }}

471

onLoad={() => cache.clear(index, 0)}

472

/>

473

<div className="item-content">

474

<h3>{items[index].title}</h3>

475

<p>{items[index].description}</p>

476

</div>

477

</div>

478

</CellMeasurer>

479

);

480

481

return (

482

<div style={{ height: 600, width: '100%' }}>

483

<AutoSizer>

484

{({ height, width }) => (

485

<Masonry

486

cellCount={items.length}

487

cellMeasurerCache={cache}

488

cellPositioner={cellPositioner}

489

cellRenderer={cellRenderer}

490

height={height}

491

width={width}

492

/>

493

)}

494

</AutoSizer>

495

</div>

496

);

497

}

498

499

// Masonry with custom spacing and layout

500

function CustomMasonry({ photos, spacing = 15 }) {

501

const cache = useMemo(() => new CellMeasurerCache({

502

defaultHeight: 300,

503

fixedWidth: true

504

}), []);

505

506

const cellPositioner = useMemo(() => {

507

return createMasonryCellPositioner({

508

cellMeasurerCache: cache,

509

columnCount: 4,

510

columnWidth: 200,

511

spacer: spacing

512

});

513

}, [cache, spacing]);

514

515

const cellRenderer = ({ index, key, parent, style }) => {

516

const photo = photos[index];

517

518

return (

519

<CellMeasurer

520

cache={cache}

521

index={index}

522

key={key}

523

parent={parent}

524

>

525

{({ measure, registerChild }) => (

526

<div

527

ref={registerChild}

528

style={{

529

...style,

530

borderRadius: '8px',

531

overflow: 'hidden',

532

boxShadow: '0 2px 8px rgba(0,0,0,0.1)'

533

}}

534

className="photo-item"

535

>

536

<img

537

src={photo.url}

538

alt={photo.title}

539

onLoad={measure}

540

style={{ width: '100%', height: 'auto', display: 'block' }}

541

/>

542

<div style={{ padding: 12, backgroundColor: 'white' }}>

543

<h4 style={{ margin: '0 0 8px 0' }}>{photo.title}</h4>

544

<p style={{ margin: 0, color: '#666', fontSize: '14px' }}>

545

{photo.description}

546

</p>

547

</div>

548

</div>

549

)}

550

</CellMeasurer>

551

);

552

};

553

554

return (

555

<div style={{ height: 600, width: 850 }}>

556

<Masonry

557

cellCount={photos.length}

558

cellMeasurerCache={cache}

559

cellPositioner={cellPositioner}

560

cellRenderer={cellRenderer}

561

height={600}

562

width={850}

563

/>

564

</div>

565

);

566

}

567

```

568

569

### Constants and Configuration

570

571

```javascript { .api }

572

/** Default timeout for scrolling reset (in milliseconds) */

573

const DEFAULT_SCROLLING_RESET_TIME_INTERVAL: 150;

574

575

/** Timeout for window scroll detection */

576

const IS_SCROLLING_TIMEOUT: 150;

577

578

/** Scroll direction constants for internal use */

579

const SCROLL_DIRECTION_BACKWARD: 'backward';

580

const SCROLL_DIRECTION_FORWARD: 'forward';

581

```