DefinitelyTyped/types/react-virtualized/react-virtualized-tests.tsx
Jessica Franco 9039892f8e Add more of the new features added in React 16.6 (#30054)
* Add definitions for React.memo

* Add missing semicolons

* Give a better name to the second argument to React.memo

* Fix test to reflect correct usage of React.memo's second argument

* Fix no-unnecessary-qualifier lints

* Update other special components to be SpecialSFC

* Ensure ordinary functions aren't assignable to SpecialSFC

* createElement was resolving P to "{} | null" in some tests; add extends to prevent that

* Fix the props of Fragment and StrictMode

* Add tests for SpecialSFC assignability

* Add scary doc comment to SpecialSFC's call signature

Hopefully this trips tslint's deprecation rule.

* Rename SpecialSFC to ExoticComponent

* Add overload to React.memo to make it more ergonomic and avoid implicit any

* Disable test that requires TS 3.1

* Add support for displayName in the exotic components that support it

* Tone down the call signature's doc comment

* Correct $ExpectType assertion

* Try to implement LibraryManagedAttributes for the ExoticComponents that should support them

This doesn't actually work because it seems only class components get them checked?

* Add type definitions for new React 16.6 features

This also attempts to add support for LibraryManagedAttributes to the ExoticComponents.

* The fallback prop is required by Suspense

* Declare legacy context on tests that use legacy context
2018-11-09 06:35:23 +00:00

1689 lines
54 KiB
TypeScript

import * as React from "react";
import { PureComponent } from "react";
import {
ArrowKeyStepper,
AutoSizer,
Grid,
Index,
CollectionCellRendererParams,
IndexRange,
CellMeasurerProps,
Size,
TableHeaderProps
} from "react-virtualized";
export class ArrowKeyStepperExample extends PureComponent<any, any> {
state: any;
render() {
const { mode } = this.state;
return (
<ArrowKeyStepper
columnCount={100}
mode={mode as "edges"}
rowCount={100}
>
{({ onSectionRendered, scrollToColumn, scrollToRow }) => (
<div>
<AutoSizer disableHeight>
{({ width }) => (
<Grid
className={"styles.Grid"}
columnWidth={this._getColumnWidth}
columnCount={100}
height={200}
onSectionRendered={onSectionRendered}
cellRenderer={({
columnIndex,
key,
rowIndex,
style
}) =>
this._cellRenderer({
columnIndex,
key,
rowIndex,
scrollToColumn,
scrollToRow,
style
})
}
rowHeight={this._getRowHeight}
rowCount={100}
scrollToColumn={scrollToColumn}
scrollToRow={scrollToRow}
width={width}
/>
)}
</AutoSizer>
</div>
)}
</ArrowKeyStepper>
);
}
_getColumnWidth({ index }: Index) {
return (1 + index % 3) * 60;
}
_getRowHeight({ index }: Index) {
return (1 + index % 3) * 30;
}
_cellRenderer({
columnIndex,
key,
rowIndex,
scrollToColumn,
scrollToRow,
style
}: any) {
return (
<div className={"className"} key={key} style={style}>
{`r:${rowIndex}, c:${columnIndex}`}
</div>
);
}
}
import { List } from "react-virtualized";
export class AutoSizerExample extends PureComponent<any, any> {
context: any;
state: any;
render() {
const { list } = this.context;
const { hideDescription } = this.state;
return (
<AutoSizer>
{({ width, height }) => (
<List
className={"styles.List"}
height={height}
rowCount={list.size}
rowHeight={30}
rowRenderer={this._rowRenderer}
width={width}
/>
)}
</AutoSizer>
);
}
_rowRenderer({ index, key, style }: any) {
const { list } = this.context;
const row = list.get(index);
return (
<div key={key} className={"styles.row"} style={style}>
{row.name}
</div>
);
}
}
import {} from "react";
import {
CellMeasurer,
CellMeasurerCache,
ListRowProps
} from "react-virtualized";
export class DynamicHeightList extends PureComponent<any> {
_cache: CellMeasurerCache;
constructor(props: any, context: any) {
super(props, context);
this._cache = new CellMeasurerCache({
fixedWidth: true,
minHeight: 50
});
}
render() {
const { width } = this.props;
return (
<List
className={"styles.BodyGrid"}
deferredMeasurementCache={this._cache}
height={400}
overscanRowCount={0}
rowCount={1000}
rowHeight={this._cache.rowHeight}
rowRenderer={this._rowRenderer}
width={width}
/>
);
}
_rowRenderer({ index, isScrolling, key, parent, style }: ListRowProps) {
const { getClassName, list } = this.props;
const datum = list.get(index % list.size);
const classNames = getClassName({ columnIndex: 0, rowIndex: index });
const imageWidth = 300;
const imageHeight = datum.size * 2;
const source = `http://fillmurray.com/${imageWidth}/${imageHeight}`;
return (
<CellMeasurer
cache={this._cache}
columnIndex={0}
key={key}
rowIndex={index}
parent={parent}
>
{({ measure }) => (
<div className={classNames} style={style}>
<img
onLoad={measure}
src={source}
style={{
width: imageWidth
}}
/>
</div>
)}
</CellMeasurer>
);
}
}
import { Collection } from "react-virtualized";
// Defines a pattern of sizes and positions for a range of 10 rotating cells
// These cells cover an area of 600 (wide) x 400 (tall)
const GUTTER_SIZE = 3;
const CELL_WIDTH = 75;
export class CollectionExample extends PureComponent<any, any> {
context: any;
state: any;
_columnYMap: any;
constructor(props: any, context: any) {
super(props, context);
this.context = context;
this.state = {
cellCount: context.list.size,
columnCount: this._getColumnCount(context.list.size),
height: 300,
horizontalOverscanSize: 0,
scrollToCell: undefined,
showScrollingPlaceholder: false,
verticalOverscanSize: 0
};
this._columnYMap = [];
}
render() {
const {
cellCount,
height,
horizontalOverscanSize,
scrollToCell,
showScrollingPlaceholder,
verticalOverscanSize
} = this.state;
return (
<AutoSizer disableHeight>
{({ width }) => (
<Collection
cellCount={cellCount}
cellRenderer={this._cellRenderer}
cellSizeAndPositionGetter={
this._cellSizeAndPositionGetter
}
className={"styles.collection"}
height={height}
horizontalOverscanSize={horizontalOverscanSize}
noContentRenderer={this._noContentRenderer}
scrollToCell={scrollToCell}
verticalOverscanSize={verticalOverscanSize}
width={width}
/>
)}
</AutoSizer>
);
}
_cellRenderer({
index,
isScrolling,
key,
style
}: CollectionCellRendererParams) {
const { list } = this.context;
const { showScrollingPlaceholder } = this.state;
const datum = list.get(index % list.size);
return (
<div className={"styles.cell"} key={key} style={style}>
{showScrollingPlaceholder && isScrolling ? "..." : index}
</div>
);
}
_cellSizeAndPositionGetter({ index }: Index) {
const { list } = this.context;
const { columnCount } = this.state;
const columnPosition = index % (columnCount || 1);
const datum = list.get(index % list.size);
// Poor man's Masonry layout; columns won't all line up equally with the bottom.
const height = datum.size;
const width = CELL_WIDTH;
const x = columnPosition * (GUTTER_SIZE + width);
const y = this._columnYMap[columnPosition] || 0;
this._columnYMap[columnPosition] = y + height + GUTTER_SIZE;
return {
height,
width,
x,
y
};
}
_getColumnCount(cellCount: number) {
return Math.round(Math.sqrt(cellCount));
}
_noContentRenderer() {
return <div className={"styles.noCells"}>No cells</div>;
}
}
import { ColumnSizer } from "react-virtualized";
export class ColumnSizerExample extends PureComponent<any, any> {
state: any;
render() {
const { columnMaxWidth, columnMinWidth, columnCount } = this.state;
return (
<div>
<AutoSizer disableHeight>
{({ width }) => (
<ColumnSizer
columnMaxWidth={columnMaxWidth}
columnMinWidth={columnMinWidth}
columnCount={columnCount}
key="GridColumnSizer"
width={width}
>
{({
adjustedWidth,
getColumnWidth,
registerChild
}) => (
<div
className={"styles.GridContainer"}
style={{
height: 50,
width: adjustedWidth
}}
>
<Grid
ref={registerChild}
columnWidth={getColumnWidth}
columnCount={columnCount}
height={50}
noContentRenderer={
this._noContentRenderer
}
cellRenderer={this._cellRenderer}
rowHeight={50}
rowCount={1}
width={adjustedWidth}
/>
</div>
)}
</ColumnSizer>
)}
</AutoSizer>
</div>
);
}
_noContentRenderer() {
return <div className={"styles.noCells"}>No cells</div>;
}
_cellRenderer({ columnIndex, key, rowIndex, style }: GridCellProps) {
const className =
columnIndex === 0 ? "styles.firstCell" : "styles.cell";
return (
<div className={className} key={key} style={style}>
{`R:${rowIndex}, C:${columnIndex}`}
</div>
);
}
}
export class GridExample extends PureComponent<any, any> {
context: any;
state = {
columnCount: 1000,
height: 300,
overscanColumnCount: 0,
overscanRowCount: 10,
rowHeight: 40,
rowCount: 1000,
scrollToColumn: undefined,
scrollToRow: undefined,
useDynamicRowHeight: false
};
render() {
const {
columnCount,
height,
overscanColumnCount,
overscanRowCount,
rowHeight,
rowCount,
scrollToColumn,
scrollToRow,
useDynamicRowHeight
} = this.state;
return (
<AutoSizer disableHeight>
{({ width }) => (
<Grid
cellRenderer={this._cellRenderer}
className={"styles.BodyGrid"}
columnWidth={this._getColumnWidth}
columnCount={columnCount}
height={height}
noContentRenderer={this._noContentRenderer}
overscanColumnCount={overscanColumnCount}
overscanRowCount={overscanRowCount}
rowHeight={
useDynamicRowHeight ? this._getRowHeight : rowHeight
}
rowCount={rowCount}
scrollToColumn={scrollToColumn}
scrollToRow={scrollToRow}
width={width}
/>
)}
</AutoSizer>
);
}
_cellRenderer(params: GridCellProps) {
if (params.columnIndex === 0) {
return this._renderLeftSideCell(params);
} else {
return this._renderBodyCell(params);
}
}
_getColumnWidth({ index }: Index) {
switch (index) {
case 0:
return 50;
case 1:
return 100;
case 2:
return 300;
default:
return 80;
}
}
_getDatum(index: number) {
const { list } = this.context;
return list.get(index % list.size);
}
_getRowClassName(row: number) {
return row % 2 === 0 ? "styles.evenRow" : "styles.oddRow";
}
_getRowHeight({ index }: Index) {
return this._getDatum(index).size;
}
_noContentRenderer() {
return <div className={"styles.noCells"}>No cells</div>;
}
_renderBodyCell({ columnIndex, key, rowIndex, style }: GridCellProps) {
const rowClass = this._getRowClassName(rowIndex);
const datum = this._getDatum(rowIndex);
let content;
switch (columnIndex) {
case 1:
content = datum.name;
break;
case 2:
content = datum.random;
break;
default:
content = `r:${rowIndex}, c:${columnIndex}`;
break;
}
return (
<div className={"classNames"} key={key} style={style}>
{content}
</div>
);
}
_renderLeftSideCell({ key, rowIndex, style }: GridCellProps) {
const datum = this._getDatum(rowIndex);
// Don't modify styles.
// These are frozen by React now (as of 16.0.0).
// Since Grid caches and re-uses them, they aren't safe to modify.
style = {
...style,
backgroundColor: datum.color
};
return (
<div className={"classNames"} key={key} style={style}>
{datum.name.charAt(0)}
</div>
);
}
}
import { InfiniteLoader } from "react-virtualized";
const STATUS_LOADING = 1;
const STATUS_LOADED = 2;
export class InfiniteLoaderExample extends PureComponent<any, any> {
context: any;
state: any;
_timeoutIds = new Set<number>();
componentWillUnmount() {
this._timeoutIds.forEach(clearTimeout);
}
render() {
const { list } = this.context;
const { loadedRowCount, loadingRowCount } = this.state;
return (
<InfiniteLoader
isRowLoaded={this._isRowLoaded}
loadMoreRows={this._loadMoreRows}
rowCount={list.size}
>
{({ onRowsRendered, registerChild }) => (
<AutoSizer disableHeight>
{({ width }) => (
<List
ref={registerChild}
className={"styles.List"}
height={200}
onRowsRendered={onRowsRendered}
rowCount={list.size}
rowHeight={30}
rowRenderer={this._rowRenderer}
width={width}
/>
)}
</AutoSizer>
)}
</InfiniteLoader>
);
}
_isRowLoaded({ index }: Index) {
const { loadedRowsMap } = this.state;
return !!loadedRowsMap[index]; // STATUS_LOADING or STATUS_LOADED
}
_loadMoreRows({ startIndex, stopIndex }: IndexRange) {
const { loadedRowsMap, loadingRowCount } = this.state;
const increment = stopIndex - startIndex + 1;
for (let i = startIndex; i <= stopIndex; i++) {
loadedRowsMap[i] = STATUS_LOADING;
}
this.setState({
loadingRowCount: loadingRowCount + increment
});
const timeoutId = setTimeout(() => {
const { loadedRowCount, loadingRowCount } = this.state;
this._timeoutIds.delete(timeoutId);
for (let i = startIndex; i <= stopIndex; i++) {
loadedRowsMap[i] = STATUS_LOADED;
}
this.setState({
loadingRowCount: loadingRowCount - increment,
loadedRowCount: loadedRowCount + increment
});
promiseResolver();
}, 1000 + Math.round(Math.random() * 2000));
this._timeoutIds.add(timeoutId);
let promiseResolver: () => void;
return new Promise(resolve => {
promiseResolver = resolve;
});
}
_rowRenderer({ index, key, style }: ListRowProps) {
const { list } = this.context;
const { loadedRowsMap } = this.state;
const row = list.get(index);
let content;
if (loadedRowsMap[index] === STATUS_LOADED) {
content = row.name;
} else {
content = (
<div
className={"styles.placeholder"}
style={{ width: row.size }}
/>
);
}
return (
<div className={"styles.row"} key={key} style={style}>
{content}
</div>
);
}
}
export class ListExample extends PureComponent<any, any> {
context: any;
state: any;
constructor(props: any, context: any) {
super(props, context);
this.state = {
listHeight: 300,
listRowHeight: 50,
overscanRowCount: 10,
rowCount: context.list.size,
scrollToIndex: undefined,
showScrollingPlaceholder: false,
useDynamicRowHeight: false
};
}
render() {
const {
listHeight,
listRowHeight,
overscanRowCount,
rowCount,
scrollToIndex,
showScrollingPlaceholder,
useDynamicRowHeight
} = this.state;
return (
<AutoSizer disableHeight>
{({ width }) => (
<List
ref="List"
className={"styles.List"}
height={listHeight}
overscanRowCount={overscanRowCount}
noRowsRenderer={this._noRowsRenderer}
rowCount={rowCount}
rowHeight={
useDynamicRowHeight
? this._getRowHeight
: listRowHeight
}
rowRenderer={this._rowRenderer}
scrollToIndex={scrollToIndex}
width={width}
/>
)}
</AutoSizer>
);
}
_getDatum(index: number) {
const { list } = this.context;
return list.get(index % list.size);
}
_getRowHeight({ index }: Index) {
return this._getDatum(index).size;
}
_noRowsRenderer() {
return <div className={"styles.noRows"}>No rows</div>;
}
_rowRenderer({ index, isScrolling, key, style }: ListRowProps) {
const { showScrollingPlaceholder, useDynamicRowHeight } = this.state;
if (showScrollingPlaceholder && isScrolling) {
return (
<div
className={"cn(styles.row, styles.isScrollingPlaceholder)"}
key={key}
style={style}
>
Scrolling...
</div>
);
}
const datum = this._getDatum(index);
let additionalContent;
if (useDynamicRowHeight) {
switch (datum.size) {
case 75:
additionalContent = <div>It is medium-sized.</div>;
break;
case 100:
additionalContent = (
<div>
It is large-sized.<br />It has a 3rd row.
</div>
);
break;
}
}
return (
<div className={"styles.row"} key={key} style={style}>
<div
className={"styles.letter"}
style={{
backgroundColor: datum.color
}}
>
{datum.name.charAt(0)}
</div>
<div>
<div className={"styles.name"}>{datum.name}</div>
<div className={"styles.index"}>This is row {index}</div>
{additionalContent}
</div>
{useDynamicRowHeight && (
<span className={"styles.height"}>{datum.size}px</span>
)}
</div>
);
}
}
import {
WindowScroller,
createMasonryCellPositioner as createCellPositioner,
Positioner,
Masonry,
MasonryCellProps
} from "react-virtualized";
export class GridExample2 extends PureComponent<any, any> {
_columnCount: number;
_cache: CellMeasurerCache;
_columnHeights: any;
_width = 0;
_height = 0;
_scrollTop?: number;
_cellPositioner: Positioner;
_masonry: Masonry;
context: any;
state: any;
constructor(props: any, context: any) {
super(props, context);
this._columnCount = 0;
this._cache = new CellMeasurerCache({
defaultHeight: 250,
defaultWidth: 200,
fixedWidth: true
});
this._columnHeights = {};
this.state = {
columnWidth: 200,
height: 300,
gutterSize: 10,
windowScrollerEnabled: false
};
this._cellRenderer = this._cellRenderer.bind(this);
this._onResize = this._onResize.bind(this);
this._renderAutoSizer = this._renderAutoSizer.bind(this);
this._renderMasonry = this._renderMasonry.bind(this);
this._setMasonryRef = this._setMasonryRef.bind(this);
}
render() {
const {
columnWidth,
height,
gutterSize,
windowScrollerEnabled
} = this.state;
const child = windowScrollerEnabled ? (
<WindowScroller>{this._renderAutoSizer}</WindowScroller>
) : (
this._renderAutoSizer({ height })
);
return <div>{child}</div>;
}
_calculateColumnCount() {
const { columnWidth, gutterSize } = this.state;
this._columnCount = Math.floor(
this._width / (columnWidth + gutterSize)
);
}
_cellRenderer({ index, key, parent, style }: MasonryCellProps) {
const { list } = this.context;
const { columnWidth } = this.state;
const datum = list.get(index % list.size);
return (
<CellMeasurer
cache={this._cache}
index={index}
key={key}
parent={parent}
>
<div
className={"styles.Cell"}
style={{
...style,
width: columnWidth
}}
>
<div
style={{
backgroundColor: datum.color,
borderRadius: "0.5rem",
height: datum.size * 3,
marginBottom: "0.5rem",
width: "100%"
}}
/>
{datum.random}
</div>
</CellMeasurer>
);
}
_initCellPositioner() {
if (typeof this._cellPositioner === "undefined") {
const { columnWidth, gutterSize } = this.state;
this._cellPositioner = createCellPositioner({
cellMeasurerCache: this._cache,
columnCount: this._columnCount,
columnWidth,
spacer: gutterSize
});
}
}
_onResize({ height, width }: Size) {
this._width = width;
this._columnHeights = {};
this._calculateColumnCount();
this._resetCellPositioner();
this._masonry.recomputeCellPositions();
}
_renderAutoSizer({
height,
scrollTop
}: {
height: number;
scrollTop?: number;
}) {
this._height = height;
this._scrollTop = scrollTop;
return (
<AutoSizer disableHeight onResize={this._onResize}>
{this._renderMasonry}
</AutoSizer>
);
}
_renderMasonry({ width }: Size) {
this._width = width;
this._calculateColumnCount();
this._initCellPositioner();
const { height, windowScrollerEnabled } = this.state;
return (
<Masonry
autoHeight={windowScrollerEnabled}
cellCount={1000}
cellMeasurerCache={this._cache}
cellPositioner={this._cellPositioner}
cellRenderer={this._cellRenderer}
height={windowScrollerEnabled ? this._height : height}
ref={this._setMasonryRef}
scrollTop={this._scrollTop}
width={width}
/>
);
}
_resetCellPositioner() {
const { columnWidth, gutterSize } = this.state;
this._cellPositioner.reset({
columnCount: this._columnCount,
columnWidth,
spacer: gutterSize
});
}
_setMasonryRef(ref: any) {
this._masonry = ref;
}
}
import { MultiGrid } from "react-virtualized";
const STYLE: React.CSSProperties = {
border: "1px solid #ddd",
overflow: "hidden"
};
const STYLE_BOTTOM_LEFT_GRID: React.CSSProperties = {
borderRight: "2px solid #aaa",
backgroundColor: "#f7f7f7"
};
const STYLE_TOP_LEFT_GRID: React.CSSProperties = {
borderBottom: "2px solid #aaa",
borderRight: "2px solid #aaa",
fontWeight: "bold"
};
const STYLE_TOP_RIGHT_GRID: React.CSSProperties = {
borderBottom: "2px solid #aaa",
fontWeight: "bold"
};
export class MultiGridExample extends PureComponent<{}, any> {
state = {
fixedColumnCount: 2,
fixedRowCount: 1,
scrollToColumn: 0,
scrollToRow: 0
};
render() {
return (
<AutoSizer disableHeight>
{({ width }) => (
<MultiGrid
{...this.state}
cellRenderer={this._cellRenderer}
columnWidth={75}
columnCount={50}
height={300}
rowHeight={40}
rowCount={100}
style={STYLE}
styleBottomLeftGrid={STYLE_BOTTOM_LEFT_GRID}
styleTopLeftGrid={STYLE_TOP_LEFT_GRID}
styleTopRightGrid={STYLE_TOP_RIGHT_GRID}
width={width}
/>
)}
</AutoSizer>
);
}
_cellRenderer({ columnIndex, key, rowIndex, style }: GridCellProps) {
return (
<div className={"styles.Cell"} key={key} style={style}>
{columnIndex}, {rowIndex}
</div>
);
}
}
import { ScrollSync } from "react-virtualized";
const LEFT_COLOR_FROM = hexToRgb("#471061");
const LEFT_COLOR_TO = hexToRgb("#BC3959");
const TOP_COLOR_FROM = hexToRgb("#000000");
const TOP_COLOR_TO = hexToRgb("#333333");
function scrollbarSize() {
return 42;
}
export class GridExample3 extends PureComponent<{}, any> {
state = {
columnWidth: 75,
columnCount: 50,
height: 300,
overscanColumnCount: 0,
overscanRowCount: 5,
rowHeight: 40,
rowCount: 100
};
render() {
const {
columnCount,
columnWidth,
height,
overscanColumnCount,
overscanRowCount,
rowHeight,
rowCount
} = this.state;
return (
<ScrollSync>
{({
clientHeight,
clientWidth,
onScroll,
scrollHeight,
scrollLeft,
scrollTop,
scrollWidth
}) => {
const x = scrollLeft / (scrollWidth - clientWidth);
const y = scrollTop / (scrollHeight - clientHeight);
const leftBackgroundColor = mixColors(
LEFT_COLOR_FROM,
LEFT_COLOR_TO,
y
);
const leftColor = "#ffffff";
const topBackgroundColor = mixColors(
TOP_COLOR_FROM,
TOP_COLOR_TO,
x
);
const topColor = "#ffffff";
const middleBackgroundColor = mixColors(
leftBackgroundColor,
topBackgroundColor,
0.5
);
const middleColor = "#ffffff";
return (
<div className={"styles.GridRow"}>
<div
className={"styles.LeftSideGridContainer"}
style={{
position: "absolute",
left: 0,
top: 0,
color: leftColor,
backgroundColor: `rgb(${
topBackgroundColor.r
},${topBackgroundColor.g},${
topBackgroundColor.b
})`
}}
>
<Grid
cellRenderer={this._renderLeftHeaderCell}
className={"styles.HeaderGrid"}
width={columnWidth}
height={rowHeight}
rowHeight={rowHeight}
columnWidth={columnWidth}
rowCount={1}
columnCount={1}
/>
</div>
<div
className={"styles.LeftSideGridContainer"}
style={{
position: "absolute",
left: 0,
top: rowHeight,
color: leftColor,
backgroundColor: `rgb(${
leftBackgroundColor.r
},${leftBackgroundColor.g},${
leftBackgroundColor.b
})`
}}
>
<Grid
overscanColumnCount={overscanColumnCount}
overscanRowCount={overscanRowCount}
cellRenderer={this._renderLeftSideCell}
columnWidth={columnWidth}
columnCount={1}
className={"styles.LeftSideGrid"}
height={height - scrollbarSize()}
rowHeight={rowHeight}
rowCount={rowCount}
scrollTop={scrollTop}
width={columnWidth}
/>
</div>
<div className={"styles.GridColumn"}>
<AutoSizer disableHeight>
{({ width }) => (
<div>
<div
style={{
backgroundColor: `rgb(${
topBackgroundColor.r
},${topBackgroundColor.g},${
topBackgroundColor.b
})`,
color: topColor,
height: rowHeight,
width:
width - scrollbarSize()
}}
>
<Grid
className={
"styles.HeaderGrid"
}
columnWidth={columnWidth}
columnCount={columnCount}
height={rowHeight}
overscanColumnCount={
overscanColumnCount
}
cellRenderer={
this._renderHeaderCell
}
rowHeight={rowHeight}
rowCount={1}
scrollLeft={scrollLeft}
width={
width - scrollbarSize()
}
/>
</div>
<div
style={{
backgroundColor: `rgb(${
middleBackgroundColor.r
},${
middleBackgroundColor.g
},${
middleBackgroundColor.b
})`,
color: middleColor,
height,
width
}}
>
<Grid
className={
"styles.BodyGrid"
}
columnWidth={columnWidth}
columnCount={columnCount}
height={height}
onScroll={onScroll}
overscanColumnCount={
overscanColumnCount
}
overscanRowCount={
overscanRowCount
}
cellRenderer={
this._renderBodyCell
}
rowHeight={rowHeight}
rowCount={rowCount}
width={width}
/>
</div>
</div>
)}
</AutoSizer>
</div>
</div>
);
}}
</ScrollSync>
);
}
_renderBodyCell(params: GridCellProps) {
if (params.columnIndex < 1) {
return;
}
return this._renderLeftSideCell(params);
}
_renderHeaderCell(params: GridCellProps) {
if (params.columnIndex < 1) {
return;
}
return this._renderLeftHeaderCell(params);
}
_renderLeftHeaderCell({
columnIndex,
key,
rowIndex,
style
}: GridCellProps) {
return (
<div className={"styles.headerCell"} key={key} style={style}>
{`C${columnIndex}`}
</div>
);
}
_renderLeftSideCell({ columnIndex, key, rowIndex, style }: GridCellProps) {
return (
<div className={"classNames"} key={key} style={style}>
{`R${rowIndex}, C${columnIndex}`}
</div>
);
}
}
function hexToRgb(hex: string) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
}
: null;
}
/**
* Ported from sass implementation in C
* https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
*/
function mixColors(color1: any, color2: any, amount: any) {
const weight1 = amount;
const weight2 = 1 - amount;
const r = Math.round(weight1 * color1.r + weight2 * color2.r);
const g = Math.round(weight1 * color1.g + weight2 * color2.g);
const b = Math.round(weight1 * color1.b + weight2 * color2.b);
return { r, g, b };
}
import { Column, Table, SortDirection, SortIndicator } from "react-virtualized";
export class TableExample extends PureComponent<{}, any> {
context: any;
state = {
disableHeader: false,
headerHeight: 30,
height: 270,
hideIndexRow: false,
overscanRowCount: 10,
rowHeight: 40,
rowCount: 1000,
scrollToIndex: undefined,
sortBy: "index",
sortDirection: SortDirection.ASC,
useDynamicRowHeight: false
};
render() {
const {
disableHeader,
headerHeight,
height,
hideIndexRow,
overscanRowCount,
rowHeight,
rowCount,
scrollToIndex,
sortBy,
sortDirection,
useDynamicRowHeight
} = this.state;
const { list } = this.context;
const sortedList = list;
const rowGetter = ({ index }: Index) =>
this._getDatum(sortedList, index);
return (
<div>
<AutoSizer disableHeight>
{({ width }) => (
<Table
ref="Table"
disableHeader={disableHeader}
headerClassName={"styles.headerColumn"}
headerHeight={headerHeight}
height={height}
noRowsRenderer={this._noRowsRenderer}
overscanRowCount={overscanRowCount}
rowClassName={this._rowClassName}
rowHeight={
useDynamicRowHeight
? this._getRowHeight
: rowHeight
}
rowGetter={rowGetter}
rowCount={rowCount}
scrollToIndex={scrollToIndex}
sort={this._sort}
sortBy={sortBy}
sortDirection={sortDirection}
width={width}
>
{!hideIndexRow && (
<Column
label="Index"
cellDataGetter={({
columnData,
dataKey,
rowData
}) => rowData.index}
dataKey="index"
disableSort={!this._isSortEnabled()}
defaultSortDirection={SortDirection.DESC}
width={60}
/>
)}
<Column
dataKey="name"
disableSort={!this._isSortEnabled()}
defaultSortDirection={SortDirection.ASC}
headerRenderer={this._headerRenderer}
width={90}
/>
<Column
width={210}
disableSort
label="The description label is really long so that it will be truncated"
dataKey="random"
className={"styles.exampleColumn"}
cellRenderer={({
cellData,
columnData,
dataKey,
rowData,
rowIndex
}) => cellData}
flexGrow={1}
/>
</Table>
)}
</AutoSizer>
</div>
);
}
_getDatum(list: any, index: number) {
return list.get(index % list.size);
}
_getRowHeight({ index }: Index) {
const { list } = this.context;
return this._getDatum(list, index).size;
}
_headerRenderer({
columnData,
dataKey,
disableSort,
label,
sortBy,
sortDirection
}: TableHeaderProps) {
return (
<div>
Full Name
{sortBy === dataKey && (
<SortIndicator sortDirection={sortDirection} />
)}
</div>
);
}
_isSortEnabled() {
const { list } = this.context;
const { rowCount } = this.state;
return rowCount <= list.size;
}
_noRowsRenderer() {
return <div className={"styles.noRows"}>No rows</div>;
}
_rowClassName({ index }: Index) {
if (index < 0) {
return "styles.headerRow";
} else {
return index % 2 === 0 ? "styles.evenRow" : "styles.oddRow";
}
}
_sort({
sortBy,
sortDirection
}: {
sortBy: string;
sortDirection: SortDirectionType;
}) {
this.setState({ sortBy, sortDirection });
}
}
import { TableCellProps } from "react-virtualized";
export class DynamicHeightTableColumnExample extends PureComponent<any, any> {
_cache = new CellMeasurerCache({
fixedWidth: true,
minHeight: 25
});
render() {
const { width } = this.props;
return (
<Table
deferredMeasurementCache={this._cache}
headerHeight={20}
height={400}
overscanRowCount={2}
rowClassName={"styles.tableRow"}
rowHeight={this._cache.rowHeight}
rowGetter={this._rowGetter}
rowCount={1000}
width={width}
>
<Column
className={"styles.tableColumn"}
dataKey="name"
label="Name"
width={125}
/>
<Column
className={"styles.tableColumn"}
dataKey="color"
label="Color"
width={75}
/>
<Column
width={width - 200}
dataKey="random"
label="Dynamic text"
cellRenderer={this._columnCellRenderer}
/>
</Table>
);
}
_columnCellRenderer(args: TableCellProps) {
const { list } = this.props;
const datum = list.get(args.rowIndex % list.size);
const content = args.rowIndex % 5 === 0 ? "" : datum.randomLong;
return (
<CellMeasurer
cache={this._cache}
columnIndex={0}
key={args.dataKey}
parent={args.parent}
rowIndex={args.rowIndex}
>
<div
className={"styles.tableColumn"}
style={{
whiteSpace: "normal"
}}
>
{content}
</div>
</CellMeasurer>
);
}
_rowGetter({ index }: Index) {
const { list } = this.props;
return list.get(index % list.size);
}
}
export class WindowScrollerExample extends PureComponent<{}, any> {
_windowScroller: WindowScroller;
context: any;
state = {
showHeaderText: true
};
render() {
const { list, isScrollingCustomElement, customElement } = this.context;
const { showHeaderText } = this.state;
return (
<div className={"styles.WindowScrollerWrapper"}>
<WindowScroller
ref={this._setRef}
scrollElement={
isScrollingCustomElement ? customElement : null
}
>
{({ height, isScrolling, scrollTop, onChildScroll }) => (
<AutoSizer disableHeight>
{({ width }) => (
<List
onScroll={onChildScroll}
autoHeight
className={"styles.List"}
height={height}
isScrolling={isScrolling}
overscanRowCount={2}
rowCount={list.size}
rowHeight={30}
rowRenderer={params =>
this._rowRenderer({
...params,
isScrolling
})
}
scrollTop={scrollTop}
width={width}
/>
)}
</AutoSizer>
)}
</WindowScroller>
</div>
);
}
_rowRenderer({ index, isScrolling, isVisible, key, style }: ListRowProps) {
const { list } = this.context;
const row = list.get(index);
return (
<div key={key} className={"className"} style={style}>
{row.name}
</div>
);
}
_setRef(windowScroller: any) {
this._windowScroller = windowScroller;
}
}
import {
GridCellProps,
GridCellRangeProps,
SortParams,
SortDirectionType
} from "react-virtualized";
export class GridCellRangeRendererExample extends PureComponent<{}, any> {
state = {
columnWidth: 75,
columnCount: 50,
height: 300,
rowHeight: 40,
rowCount: 100
};
render() {
const {
columnCount,
columnWidth,
height,
rowHeight,
rowCount
} = this.state;
return (
<Grid
cellRangeRenderer={this._cellRangeRenderer}
cellRenderer={(props: GridCellProps): React.ReactNode => (
<div key={props.key} style={props.style}>
I'm a table cell
</div>
)}
columnCount={columnCount}
columnWidth={columnWidth}
height={height}
rowCount={rowCount}
rowHeight={rowHeight}
width={columnWidth}
/>
);
}
_cellRangeRenderer({
cellCache, // Temporary cell cache used while scrolling
cellRenderer, // Cell renderer prop supplied to Grid
columnSizeAndPositionManager, // @see CellSizeAndPositionManager,
columnStartIndex, // Index of first column (inclusive) to render
columnStopIndex, // Index of last column (inclusive) to render
horizontalOffsetAdjustment, // Horizontal pixel offset (required for scaling)
isScrolling, // The Grid is currently being scrolled
rowSizeAndPositionManager, // @see CellSizeAndPositionManager,
rowStartIndex, // Index of first column (inclusive) to render
rowStopIndex, // Index of last column (inclusive) to render
scrollLeft, // Current horizontal scroll offset of Grid
scrollTop, // Current vertical scroll offset of Grid
styleCache, // Temporary style (size & position) cache used while scrolling
verticalOffsetAdjustment, // Vertical pixel offset (required for scaling)
parent,
visibleColumnIndices,
visibleRowIndices
}: GridCellRangeProps): React.ReactNode[] {
const renderedCells: React.ReactNode[] = [];
const style: React.CSSProperties = {};
for (
let rowIndex = rowStartIndex;
rowIndex <= rowStopIndex;
rowIndex++
) {
// This contains :offset (top) and :size (height) information for the cell
const rowDatum = rowSizeAndPositionManager.getSizeAndPositionOfCell(
rowIndex
);
for (
let columnIndex = columnStartIndex;
columnIndex <= columnStopIndex;
columnIndex++
) {
// This contains :offset (left) and :size (width) information for the cell
const columnDatum = columnSizeAndPositionManager.getSizeAndPositionOfCell(
columnIndex
);
// Be sure to adjust cell position in case the total set of cells is too large to be supported by the browser natively.
// In this case, Grid will shift cells as a user scrolls to increase cell density.
const left = columnDatum.offset + horizontalOffsetAdjustment;
const top = rowDatum.offset + verticalOffsetAdjustment;
// The rest of the information you need to render the cell are contained in the data.
// Be sure to provide unique :key attributes.
const key = `${rowIndex}-${columnIndex}`;
const height = rowDatum.size;
const width = columnDatum.size;
const isVisible =
columnIndex >= visibleColumnIndices.start &&
columnIndex <= visibleColumnIndices.stop &&
rowIndex >= visibleRowIndices.start &&
rowIndex <= visibleRowIndices.stop;
// Now render your cell and additional UI as you see fit.
// Add all rendered children to the :renderedCells Array.
const gridCellProps: GridCellProps = {
columnIndex,
isScrolling,
isVisible,
key,
parent,
rowIndex,
style
};
renderedCells.push(cellRenderer(gridCellProps));
}
}
return renderedCells;
}
}