From 8484faf7747a8731783bb8debc2a733a19de1592 Mon Sep 17 00:00:00 2001 From: Kalle Ott Date: Mon, 27 Mar 2017 21:23:45 +0200 Subject: [PATCH 1/6] update for react-virtualized 9.4 replaced single declaration file with multiple files to represent the module structure of react-virtualized. This makes the future maintanance easier, because changes in the lib can be easier mirrored in the corresponding declaration file. This typings update should be the last with large breaking changes --- types/react-virtualized/ArrowKeyStepper.d.ts | 55 ++ .../ArrowKeyStepper.test.tsx | 71 ++ types/react-virtualized/AutoSizer.d.ts | 49 ++ types/react-virtualized/AutoSizer.test.tsx | 47 ++ types/react-virtualized/CellMeasurer.d.ts | 78 ++ types/react-virtualized/CellMeasurer.test.tsx | 74 ++ types/react-virtualized/Collection.d.ts | 124 ++++ types/react-virtualized/Collection.test.tsx | 160 +++++ types/react-virtualized/ColumnSizer.d.ts | 50 ++ types/react-virtualized/ColumnSizer.test.tsx | 113 +++ types/react-virtualized/Grid.d.ts | 462 ++++++++++++ types/react-virtualized/Grid.test.tsx | 207 ++++++ types/react-virtualized/InfiniteLoader.d.ts | 80 +++ .../react-virtualized/InfiniteLoader.test.tsx | 138 ++++ types/react-virtualized/List.d.ts | 138 ++++ types/react-virtualized/List.test.tsx | 160 +++++ types/react-virtualized/Masonry.d.ts | 146 ++++ types/react-virtualized/Masonry.test.tsx | 200 ++++++ types/react-virtualized/MultiGrid.d.ts | 75 ++ types/react-virtualized/MultiGrid.test.tsx | 105 +++ types/react-virtualized/ScrollSync.d.ts | 51 ++ types/react-virtualized/ScrollSync.test.tsx | 222 ++++++ types/react-virtualized/Table.d.ts | 447 ++++++++++++ types/react-virtualized/Table.test.tsx | 196 +++++ types/react-virtualized/WindowScroller.d.ts | 60 ++ .../react-virtualized/WindowScroller.test.tsx | 88 +++ types/react-virtualized/genericTypes.d.ts | 40 ++ types/react-virtualized/index.d.ts | 671 ++++-------------- .../react-virtualized-tests.tsx | 532 -------------- types/react-virtualized/tsconfig.json | 28 +- 30 files changed, 3795 insertions(+), 1072 deletions(-) create mode 100644 types/react-virtualized/ArrowKeyStepper.d.ts create mode 100644 types/react-virtualized/ArrowKeyStepper.test.tsx create mode 100644 types/react-virtualized/AutoSizer.d.ts create mode 100644 types/react-virtualized/AutoSizer.test.tsx create mode 100644 types/react-virtualized/CellMeasurer.d.ts create mode 100644 types/react-virtualized/CellMeasurer.test.tsx create mode 100644 types/react-virtualized/Collection.d.ts create mode 100644 types/react-virtualized/Collection.test.tsx create mode 100644 types/react-virtualized/ColumnSizer.d.ts create mode 100644 types/react-virtualized/ColumnSizer.test.tsx create mode 100644 types/react-virtualized/Grid.d.ts create mode 100644 types/react-virtualized/Grid.test.tsx create mode 100644 types/react-virtualized/InfiniteLoader.d.ts create mode 100644 types/react-virtualized/InfiniteLoader.test.tsx create mode 100644 types/react-virtualized/List.d.ts create mode 100644 types/react-virtualized/List.test.tsx create mode 100644 types/react-virtualized/Masonry.d.ts create mode 100644 types/react-virtualized/Masonry.test.tsx create mode 100644 types/react-virtualized/MultiGrid.d.ts create mode 100644 types/react-virtualized/MultiGrid.test.tsx create mode 100644 types/react-virtualized/ScrollSync.d.ts create mode 100644 types/react-virtualized/ScrollSync.test.tsx create mode 100644 types/react-virtualized/Table.d.ts create mode 100644 types/react-virtualized/Table.test.tsx create mode 100644 types/react-virtualized/WindowScroller.d.ts create mode 100644 types/react-virtualized/WindowScroller.test.tsx create mode 100644 types/react-virtualized/genericTypes.d.ts delete mode 100644 types/react-virtualized/react-virtualized-tests.tsx diff --git a/types/react-virtualized/ArrowKeyStepper.d.ts b/types/react-virtualized/ArrowKeyStepper.d.ts new file mode 100644 index 0000000000..e42ff353f2 --- /dev/null +++ b/types/react-virtualized/ArrowKeyStepper.d.ts @@ -0,0 +1,55 @@ +import { PropTypes, PureComponent, Validator, Requireable } from 'react' + +export type OnSectionRenderedParams = { + columnStartIndex: number, + columnStopIndex: number, + rowStartIndex: number, + rowStopIndex: number +} + +export type ChildProps = { + onSectionRendered: (params: OnSectionRenderedParams) => void, + scrollToColumn: number, + scrollToRow: number +}; +/** + * This HOC decorates a virtualized component and responds to arrow-key events by scrolling one row or column at a time. + */ +export type ArrowKeyStepperProps = { + children?: (props: ChildProps) => React.ReactNode; + className?: string; + columnCount: number; + rowCount: number; + mode?: 'edges' | 'cells'; +} +export type ScrollIndexes = { + scrollToRow: number, + scrollToColumn: number +} +export class ArrowKeyStepper extends PureComponent { + static defaultProps: { + disabled: false, + mode: 'edges', + scrollToColumn: 0, + scrollToRow: 0 + }; + + static propTypes: { + children: Validator<(props: ChildProps) => React.ReactNode>, + className: Requireable, + columnCount: Validator, + disabled: Validator, + mode: Validator<'cells' | 'edges'>, + rowCount: Validator, + scrollToColumn: Validator, + scrollToRow: Validator + }; + + constructor(props: ArrowKeyStepperProps, context: any); + + componentWillReceiveProps(nextProps: ArrowKeyStepperProps): void; + + setScrollIndexes(params: ScrollIndexes): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/ArrowKeyStepper.test.tsx b/types/react-virtualized/ArrowKeyStepper.test.tsx new file mode 100644 index 0000000000..8204aafdd6 --- /dev/null +++ b/types/react-virtualized/ArrowKeyStepper.test.tsx @@ -0,0 +1,71 @@ +/** @flow */ +import * as React from 'react'; +import { PureComponent } from 'react' +import { ArrowKeyStepper, AutoSizer, Grid } from 'react-virtualized' + +export default class ArrowKeyStepperExample extends PureComponent { + constructor(props) { + super(props) + + this._getColumnWidth = this._getColumnWidth.bind(this) + this._getRowHeight = this._getRowHeight.bind(this) + this._cellRenderer = this._cellRenderer.bind(this) + } + + render() { + const { mode } = this.state + + return ( + + + {({ onSectionRendered, scrollToColumn, scrollToRow }) => ( +
+ + + {({ width }) => ( + this._cellRenderer({ columnIndex, key, rowIndex, scrollToColumn, scrollToRow, style })} + rowHeight={this._getRowHeight} + rowCount={100} + scrollToColumn={scrollToColumn} + scrollToRow={scrollToRow} + width={width} + /> + )} + +
+ )} +
+ ) + } + + _getColumnWidth({ index }) { + return (1 + (index % 3)) * 60 + } + + _getRowHeight({ index }) { + return (1 + (index % 3)) * 30 + } + + _cellRenderer({ columnIndex, key, rowIndex, scrollToColumn, scrollToRow, style }) { + + return ( +
+ {`r:${rowIndex}, c:${columnIndex}`} +
+ ) + } +} diff --git a/types/react-virtualized/AutoSizer.d.ts b/types/react-virtualized/AutoSizer.d.ts new file mode 100644 index 0000000000..6d82a44482 --- /dev/null +++ b/types/react-virtualized/AutoSizer.d.ts @@ -0,0 +1,49 @@ +import { PropTypes, PureComponent, Validator, Requireable } from 'react' + +export type Dimensions = { + height: number, + width: number +} + +export type AutoSizerProps = { + disableHeight?: boolean; + disableWidth?: boolean; + onResize?: (info: { height: number, width: number }) => any; + children?: (props: Dimensions) => React.ReactNode +}; +/** + * Decorator component that automatically adjusts the width and height of a single child. + * Child component should not be declared as a child but should rather be specified by a `ChildComponent` property. + * All other properties will be passed through to the child component. + */ +export class AutoSizer extends PureComponent { + static propTypes: { + /** + * Function responsible for rendering children. + * This function should implement the following signature: + * ({ height, width }) => PropTypes.element + */ + children: Validator<(props: Dimensions) => React.ReactNode>, + + /** Disable dynamic :height property */ + disableHeight: Requireable, + + /** Disable dynamic :width property */ + disableWidth: Requireable, + + /** Callback to be invoked on-resize: ({ height, width }) */ + onResize: Validator<(props: Dimensions) => any> + }; + + static defaultProps: { + onResize: () => { } + }; + + constructor(props: AutoSizerProps); + + componentDidMount(): void; + + componentWillUnmount(): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/AutoSizer.test.tsx b/types/react-virtualized/AutoSizer.test.tsx new file mode 100644 index 0000000000..670d77b52b --- /dev/null +++ b/types/react-virtualized/AutoSizer.test.tsx @@ -0,0 +1,47 @@ +/** @flow */ +import * as React from 'react'; +import { PureComponent } from 'react' +import { AutoSizer, List } from 'react-virtualized' + +export default class AutoSizerExample extends PureComponent { + constructor(props) { + super(props) + + this._rowRenderer = this._rowRenderer.bind(this) + } + + render() { + const { list } = this.context + const { hideDescription } = this.state + + return ( + + {({ width, height }) => ( + + )} + + ) + } + + _rowRenderer({ index, key, style }) { + const { list } = this.context + const row = list.get(index) + + return ( +
+ {row.name} +
+ ) + } +} diff --git a/types/react-virtualized/CellMeasurer.d.ts b/types/react-virtualized/CellMeasurer.d.ts new file mode 100644 index 0000000000..5e1e0db3fb --- /dev/null +++ b/types/react-virtualized/CellMeasurer.d.ts @@ -0,0 +1,78 @@ +import { PureComponent } from 'react' + +export type KeyMapper = ( + rowIndex: number, + columnIndex: number +) => any; + +export type CellMeasurerCacheParams = { + defaultHeight?: number, + defaultWidth?: number, + fixedHeight?: boolean, + fixedWidth?: boolean, + minHeight?: number, + minWidth?: number, + keyMapper?: KeyMapper +} +export class CellMeasurerCache { + constructor(params: CellMeasurerCacheParams); + clear( + rowIndex: number, + columnIndex: number + ): void; + clearAll(): void; + columnWidth: (params: { index: number }) => number | undefined; + hasFixedHeight(): boolean; + hasFixedWidth(): boolean; + getHeight( + rowIndex: number, + columnIndex: number + ): number | undefined; + getWidth( + rowIndex: number, + columnIndex: number + ): number | undefined; + has( + rowIndex: number, + columnIndex: number + ): boolean; + rowHeight: (params: { index: number }) => number | undefined; + set( + rowIndex: number, + columnIndex: number, + width: number, + height: number + ): void; +} + +export type CellMeasurerChildProps = { + getColumnWidth: () => number, + getRowHeight: () => number, + resetMeasurements: () => any, + resetMeasurementsForColumn: (index: number) => any, + resetMeasurementsForRow: (index: number) => any, +} + +export type CellMeasurerProps = { + cache?: CellMeasurerCache; + children?: (props: CellMeasurerChildProps) => React.ReactNode; + columnIndex?: number; + index?: number; + parent?: React.ReactType; + rowIndex?: number; + style?: React.CSSProperties; +} +/** + * Wraps a cell and measures its rendered content. + * Measurements are stored in a per-cell cache. + * Cached-content is not be re-measured. + */ +export class CellMeasurer extends PureComponent { + constructor(props: CellMeasurerProps, context: any); + + componentDidMount(): void; + + componentDidUpdate(prevProps: CellMeasurerProps, prevState: any): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/CellMeasurer.test.tsx b/types/react-virtualized/CellMeasurer.test.tsx new file mode 100644 index 0000000000..5b510704c0 --- /dev/null +++ b/types/react-virtualized/CellMeasurer.test.tsx @@ -0,0 +1,74 @@ +/** @flow */ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { CellMeasurer, CellMeasurerCache, List } from 'react-virtualized' + +export default class DynamicHeightList extends PureComponent { + + _cache: CellMeasurerCache + + constructor(props, context) { + super(props, context) + + this._cache = new CellMeasurerCache({ + fixedWidth: true, + minHeight: 50 + }) + + this._rowRenderer = this._rowRenderer.bind(this) + } + + render() { + const { width } = this.props + + return ( + + ) + } + + _rowRenderer({ index, isScrolling, key, parent, style }) { + 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 ( + + {({ measure }) => ( +
+ +
+ )} +
+ ) + } +} diff --git a/types/react-virtualized/Collection.d.ts b/types/react-virtualized/Collection.d.ts new file mode 100644 index 0000000000..7e11946eb1 --- /dev/null +++ b/types/react-virtualized/Collection.d.ts @@ -0,0 +1,124 @@ +/** @flow */ +import { PureComponent, Validator, Requireable } from 'react' +import { + Index, + ScrollPosition, + SizeInfo, + SizeAndPositionInfo +} from './genericTypes'; + +export type CollectionCellSizeAndPosition = { height: number, width: number, x: number, y: number }; +export type CollectionCellSizeAndPositionGetter = (params: Index) => CollectionCellSizeAndPosition; + +export type CollectionCellGroupRendererParams = { + cellSizeAndPositionGetter: CollectionCellSizeAndPositionGetter, + indices: number[], + cellRenderer: CollectionCellRenderer +} +export type CollectionCellGroupRenderer = (params: CollectionCellGroupRendererParams) => React.ReactNode[]; +export type CollectionCellRendererParams = { + index: number, + key: string, + style?: React.CSSProperties +} +export type CollectionCellRenderer = (params: CollectionCellRendererParams) => React.ReactNode; +export type CollectionProps = { + 'aria-label'?: string; + cellCount: number; + cellGroupRenderer?: CollectionCellGroupRenderer, + cellRenderer: CollectionCellRenderer, + cellSizeAndPositionGetter: CollectionCellSizeAndPositionGetter, + sectionSize?: number; + className?: string; + height: number; + width:number; + horizontalOverscanSize?: number; + noContentRenderer?: () => JSX.Element; + scrollToCell?: number; + verticalOverscanSize?:number; +}; + +/** + * Renders scattered or non-linear data. + * Unlike Grid, which renders checkerboard data, Collection can render arbitrarily positioned- even overlapping- data. + */ +export class Collection extends PureComponent { + static propTypes: { + 'aria-label': Requireable, + + /** + * Number of cells in Collection. + */ + cellCount: Validator, + + /** + * Responsible for rendering a group of cells given their indices. + * Should implement the following interface: ({ + * cellSizeAndPositionGetter:Function, + * indices: Array, + * cellRenderer: Function + * }): Array + */ + cellGroupRenderer: Validator, + + /** + * Responsible for rendering a cell given an row and column index. + * Should implement the following interface: ({ index: number, key: string, style: object }): PropTypes.element + */ + cellRenderer: Validator, + + /** + * Callback responsible for returning size and offset/position information for a given cell (index). + * ({ index: number }): { height: number, width: number, x: number, y: number } + */ + cellSizeAndPositionGetter: Validator, + + /** + * Optionally override the size of the sections a Collection's cells are split into. + */ + sectionSize: Requireable + }; + + static defaultProps: { + 'aria-label': 'grid', + cellGroupRenderer: CollectionCellGroupRenderer + }; + + constructor(props: CollectionProps, context: any); + + forceUpdate(): void; + + /** See Collection#recomputeCellSizesAndPositions */ + recomputeCellSizesAndPositions(): void; + + /** React lifecycle methods */ + + render(): JSX.Element; + + /** CellLayoutManager interface */ + + calculateSizeAndPositionData(): void; + + /** + * Returns the most recently rendered set of cell indices. + */ + getLastRenderedIndices(): number[]; + + /** + * Calculates the minimum amount of change from the current scroll position to ensure the specified cell is (fully) visible. + */ + getScrollPositionForCell(params: { + align: 'auto' | 'start' | 'end' | 'center', + cellIndex: number, + height: number, + scrollLeft: number, + scrollTop: number, + width: number + }): ScrollPosition; + + getTotalSize(): SizeInfo; + + cellRenderers(params: { + isScrolling: boolean, + } & SizeInfo): React.ReactNode[]; +} diff --git a/types/react-virtualized/Collection.test.tsx b/types/react-virtualized/Collection.test.tsx new file mode 100644 index 0000000000..8a7860b3c7 --- /dev/null +++ b/types/react-virtualized/Collection.test.tsx @@ -0,0 +1,160 @@ +/** @flow */ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { AutoSizer, 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 default class CollectionExample extends PureComponent { + + _columnYMap: any; + + constructor(props, context) { + 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 = [] + + this._cellRenderer = this._cellRenderer.bind(this) + this._cellSizeAndPositionGetter = this._cellSizeAndPositionGetter.bind(this) + this._noContentRenderer = this._noContentRenderer.bind(this) + this._onCellCountChange = this._onCellCountChange.bind(this) + this._onHeightChange = this._onHeightChange.bind(this) + this._onHorizontalOverscanSizeChange = this._onHorizontalOverscanSizeChange.bind(this) + this._onScrollToCellChange = this._onScrollToCellChange.bind(this) + this._onVerticalOverscanSizeChange = this._onVerticalOverscanSizeChange.bind(this) + } + + render() { + const { cellCount, height, horizontalOverscanSize, scrollToCell, showScrollingPlaceholder, verticalOverscanSize } = this.state + + return ( + + {({ width }) => ( + + )} + + ) + } + + _cellRenderer({ index, isScrolling, key, style }) { + const { list } = this.context + const { showScrollingPlaceholder } = this.state + + const datum = list.get(index % list.size) + + // Customize style + style.backgroundColor = datum.color + + return ( +
+ {showScrollingPlaceholder && isScrolling ? '...' : index} +
+ ) + } + + _cellSizeAndPositionGetter({ 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) { + return Math.round(Math.sqrt(cellCount)) + } + + _onHorizontalOverscanSizeChange(event) { + const horizontalOverscanSize = parseInt(event.target.value, 10) || 0 + + this.setState({ horizontalOverscanSize }) + } + + _noContentRenderer() { + return ( +
+ No cells +
+ ) + } + + _onCellCountChange(event) { + const cellCount = parseInt(event.target.value, 10) || 0 + + this._columnYMap = [] + + this.setState({ + cellCount, + columnCount: this._getColumnCount(cellCount) + }) + } + + _onHeightChange(event) { + const height = parseInt(event.target.value, 10) || 0 + + this.setState({ height }) + } + + _onScrollToCellChange(event) { + const { cellCount } = this.state + + let scrollToCell = Math.min(cellCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToCell)) { + scrollToCell = undefined + } + + this.setState({ scrollToCell }) + } + + _onVerticalOverscanSizeChange(event) { + const verticalOverscanSize = parseInt(event.target.value, 10) || 0 + + this.setState({ verticalOverscanSize }) + } +} diff --git a/types/react-virtualized/ColumnSizer.d.ts b/types/react-virtualized/ColumnSizer.d.ts new file mode 100644 index 0000000000..6efcf8c044 --- /dev/null +++ b/types/react-virtualized/ColumnSizer.d.ts @@ -0,0 +1,50 @@ +import { PureComponent, Validator, Requireable } from 'react' + +export type SizedColumnProps = { + adjustedWidth: number, + getColumnWidth: () => number, + registerChild: any +} + +export type ColumnSizerProps = { + children?: (props: SizedColumnProps) => React.ReactNode; + columnMaxWidth?: number; + columnMinWidth?: number; + columnCount?: number; + width: number; +} +/** + * High-order component that auto-calculates column-widths for `Grid` cells. + */ +export class ColumnSizer extends PureComponent { + static propTypes: { + /** + * Function responsible for rendering a virtualized Grid. + * This function should implement the following signature: + * ({ adjustedWidth, getColumnWidth, registerChild }) => PropTypes.element + * + * The specified :getColumnWidth function should be passed to the Grid's :columnWidth property. + * The :registerChild should be passed to the Grid's :ref property. + * The :adjustedWidth property is optional; it reflects the lesser of the overall width or the width of all columns. + */ + children: Validator<(props: SizedColumnProps) => React.ReactNode>, + + /** Optional maximum allowed column width */ + columnMaxWidth: Requireable, + + /** Optional minimum allowed column width */ + columnMinWidth: Requireable, + + /** Number of columns in Grid or Table child */ + columnCount: Validator, + + /** Width of Grid or Table child */ + width: Validator + }; + + constructor(props: ColumnSizerProps, context: any); + + componentDidUpdate(prevProps: ColumnSizerProps, prevState: any): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/ColumnSizer.test.tsx b/types/react-virtualized/ColumnSizer.test.tsx new file mode 100644 index 0000000000..97de9fff45 --- /dev/null +++ b/types/react-virtualized/ColumnSizer.test.tsx @@ -0,0 +1,113 @@ +import * as React from 'react' +import { PureComponent } from 'react' +import { AutoSizer, ColumnSizer, Grid } from 'react-virtualized' + +export default class ColumnSizerExample extends PureComponent { + constructor(props) { + super(props) + + this._noColumnMaxWidthChange = this._noColumnMaxWidthChange.bind(this) + this._noColumnMinWidthChange = this._noColumnMinWidthChange.bind(this) + this._onColumnCountChange = this._onColumnCountChange.bind(this) + this._noContentRenderer = this._noContentRenderer.bind(this) + this._cellRenderer = this._cellRenderer.bind(this) + } + + render() { + const { + columnMaxWidth, + columnMinWidth, + columnCount + } = this.state + + return ( +
+ + {({ width }) => ( + + {({ adjustedWidth, getColumnWidth, registerChild }) => ( +
+ +
+ )} +
+ )} +
+
+ ) + } + + _noColumnMaxWidthChange(event) { + let columnMaxWidth = parseInt(event.target.value, 10) + + if (isNaN(columnMaxWidth)) { + columnMaxWidth = undefined + } else { + columnMaxWidth = Math.min(1000, columnMaxWidth) + } + + this.setState({ columnMaxWidth }) + } + + _noColumnMinWidthChange(event) { + let columnMinWidth = parseInt(event.target.value, 10) + + if (isNaN(columnMinWidth)) { + columnMinWidth = undefined + } else { + columnMinWidth = Math.max(1, columnMinWidth) + } + + this.setState({ columnMinWidth }) + } + + _onColumnCountChange(event) { + this.setState({ columnCount: parseInt(event.target.value, 10) || 0 }) + } + + _noContentRenderer() { + return ( +
+ No cells +
+ ) + } + + _cellRenderer({ columnIndex, key, rowIndex, style }) { + const className = columnIndex === 0 + ? 'styles.firstCell' + : 'styles.cell' + + return ( +
+ {`R:${rowIndex}, C:${columnIndex}`} +
+ ) + } +} diff --git a/types/react-virtualized/Grid.d.ts b/types/react-virtualized/Grid.d.ts new file mode 100644 index 0000000000..ea7130857c --- /dev/null +++ b/types/react-virtualized/Grid.d.ts @@ -0,0 +1,462 @@ +/** @flow */ +import { Validator, Requireable, PureComponent } from 'react' +import { List } from './List'; +import { Table } from './Table'; +import { CellMeasurerCache } from './CellMeasurer'; +import { Index, Map, Alignment } from './genericTypes'; + +export type GridCellProps = { + columnIndex: number; + isScrolling: boolean; + isVisible: boolean; + key: string; + parent: Grid | List | Table; + rowIndex: number; + style: React.CSSProperties; +}; +export type GridCellRenderer = (props: GridCellProps) => React.ReactNode; + +export type ConfigureParams = { + cellCount: number, + estimatedCellSize: number +}; +export type ContainerSizeAndOffset = { + containerSize: number, + offset: number +}; +export type SizeAndPositionData = { + offset: number, + size: number +}; +export type GetVisibleCellRangeParams = { + containerSize: number, + offset: number +}; +export type VisibleCellRange = { + start: number; + stop: number; +}; +export type ScrollParams = { + clientHeight: number, + clientWidth: number, + scrollHeight: number, + scrollLeft: number, + scrollTop: number, + scrollWidth: number +}; +export type SectionRenderedParams = { + columnStartIndex: number, + columnStopIndex: number, + rowStartIndex: number, + rowStopIndex: number +}; +export type OverscanIndicesGetterParams = { + cellCount: number, + overscanCellsCount: number, + scrollDirection: number, + startIndex: number, + stopIndex: number +}; +export type OverscanIndices = { + overscanStartIndex: number, + overscanStopIndex: number +}; + +export type CellSizeAndPositionManager = { + areOffsetsAdjusted(): boolean; + configure({ + cellCount, + estimatedCellSize + }: ConfigureParams): void; + getCellCount(): number; + getEstimatedCellSize(): number; + getLastMeasuredIndex(): number; + getOffsetAdjustment({ + containerSize, + offset // safe + }: ContainerSizeAndOffset): number; + /** + * This method returns the size and position for the cell at the specified index. + * It just-in-time calculates (or used cached values) for cells leading up to the index. + */ + getSizeAndPositionOfCell(index: number): SizeAndPositionData; + getSizeAndPositionOfLastMeasuredCell(): SizeAndPositionData; + /** + * Total size of all cells being measured. + * This value will be completedly estimated initially. + * As cells as measured the estimate will be updated. + */ + getTotalSize(): number; + /** + * Determines a new offset that ensures a certain cell is visible, given the current offset. + * If the cell is already visible then the current offset will be returned. + * If the current offset is too great or small, it will be adjusted just enough to ensure the specified index is visible. + * + * @param align Desired alignment within container; one of "auto" (default), "start", or "end" + * @param containerSize Size (width or height) of the container viewport + * @param currentOffset Container's current (x or y) offset + * @param totalSize Total size (width or height) of all cells + * @return Offset to use to ensure the specified cell is visible + */ + getUpdatedOffsetForIndex(params: { + align: string, + containerSize: number, + currentOffset: number, + targetIndex: number + }): number; + getVisibleCellRange(params: GetVisibleCellRangeParams): VisibleCellRange; + /** + * Clear all cached values for cells after the specified index. + * This method should be called for any cell that has changed its size. + * It will not immediately perform any calculations; they'll be performed the next time getSizeAndPositionOfCell() is called. + */ + resetCell(index: number): void +} + +export type GridCellRangeProps = { + cellCache: Map, + cellRenderer: GridCellRenderer, + columnSizeAndPositionManager: CellSizeAndPositionManager, + columnStartIndex: number, + columnStopIndex: number, + isScrolling: boolean, + rowSizeAndPositionManager: CellSizeAndPositionManager, + rowStartIndex: number, + rowStopIndex: number, + scrollLeft: number, + scrollTop: number +} +export type GridCellRangeRenderer = (params: GridCellRangeProps) => React.ReactNode[]; +// TODO add proper typing +export type GridProps = { + 'aria-label'?: string; + autoContainerWidth?: boolean; + autoHeight?: boolean; + cellRenderer: GridCellRenderer; + cellRangeRenderer?: GridCellRangeRenderer; + className?: string; + columnCount: number; + columnWidth: number | ((params: Index) => number); + containerStyle?: React.CSSProperties; + deferredMeasurementCache?: CellMeasurerCache; + estimatedColumnSize?: number; + estimatedRowSize?: number; + getScrollbarSize?: () => number; + height: number; + id?: string; + noContentRenderer?: () => React.ReactNode; + onScroll?: (params: ScrollParams) => any; + onSectionRendered?: (params: SectionRenderedParams) => any; + overscanColumnCount?: number; + overscanIndicesGetter?: (params: OverscanIndicesGetterParams) => OverscanIndices; + overscanRowCount?: number; + rowHeight: number | ((params: Index) => number); + rowCount: number; + scrollingResetTimeInterval?: number; + scrollLeft?: number; + scrollToAlignment?: Alignment; + scrollToColumn?: number; + scrollTop?: number; + scrollToRow?: number; + style?: React.CSSProperties; + tabIndex?: number; + width: number; +}; + +export type ScrollDirection = 'horizontal' | 'vertical'; + +export type GridState = { + isScrolling: boolean, + scrollDirectionHorizontal: ScrollDirection, + scrollDirectionVertical: ScrollDirection, + scrollLeft: number, + scrollTop: number +}; + +/** + * Specifies the number of miliseconds during which to disable pointer events while a scroll is in progress. + * This improves performance and makes scrolling smoother. + */ +export const DEFAULT_SCROLLING_RESET_TIME_INTERVAL = 150 + +/** + * Renders tabular data with virtualization along the vertical and horizontal axes. + * Row heights and column widths must be known ahead of time and specified as properties. + */ +export class Grid extends PureComponent { + static propTypes: { + 'aria-label': Requireable, + + /** + * Set the width of the inner scrollable container to 'auto'. + * This is useful for single-column Grids to ensure that the column doesn't extend below a vertical scrollbar. + */ + autoContainerWidth: Requireable, + + /** + * Removes fixed height from the scrollingContainer so that the total height + * of rows can stretch the window. Intended for use with WindowScroller + */ + autoHeight: Requireable, + + /** + * Responsible for rendering a cell given an row and column index. + * Should implement the following interface: ({ columnIndex: number, rowIndex: number }): PropTypes.node + */ + cellRenderer: Validator< (props: GridCellProps) => React.ReactNode>, + + /** + * Responsible for rendering a group of cells given their index ranges. + * Should implement the following interface: ({ + * cellCache: Map, + * cellRenderer: Function, + * columnSizeAndPositionManager: CellSizeAndPositionManager, + * columnStartIndex: number, + * columnStopIndex: number, + * isScrolling: boolean, + * rowSizeAndPositionManager: CellSizeAndPositionManager, + * rowStartIndex: number, + * rowStopIndex: number, + * scrollLeft: number, + * scrollTop: number + * }): Array + */ + cellRangeRenderer: Validator<(params: GridCellRangeProps) => React.ReactNode[]>, + + /** + * Optional custom CSS class name to attach to root Grid element. + */ + className: Requireable, + + /** + * Number of columns in grid. + */ + columnCount: Validator, + + /** + * Either a fixed column width (number) or a function that returns the width of a column given its index. + * Should implement the following interface: (index: number): number + */ + columnWidth: Validator number)>, + + /** Optional inline style applied to inner cell-container */ + containerStyle: Requireable, + + /** + * If CellMeasurer is used to measure this Grid's children, this should be a pointer to its CellMeasurerCache. + * A shared CellMeasurerCache reference enables Grid and CellMeasurer to share measurement data. + */ + deferredMeasurementCache: Requireable, + + /** + * Used to estimate the total width of a Grid before all of its columns have actually been measured. + * The estimated total width is adjusted as columns are rendered. + */ + estimatedColumnSize: Validator, + + /** + * Used to estimate the total height of a Grid before all of its rows have actually been measured. + * The estimated total height is adjusted as rows are rendered. + */ + estimatedRowSize: Validator, + + /** + * Exposed for testing purposes only. + */ + getScrollbarSize: Validator<() => number>, + + /** + * Height of Grid; this property determines the number of visible (vs virtualized) rows. + */ + height: Validator, + + /** + * Optional custom id to attach to root Grid element. + */ + id: Requireable, + + /** + * Optional renderer to be used in place of rows when either :rowCount or :columnCount is 0. + */ + noContentRenderer: Requireable<() => JSX.Element>, + + /** + * Callback invoked whenever the scroll offset changes within the inner scrollable region. + * This callback can be used to sync scrolling between lists, tables, or grids. + * ({ clientHeight, clientWidth, scrollHeight, scrollLeft, scrollTop, scrollWidth }): void + */ + onScroll: Validator<(params: ScrollParams) => void>, + + /** + * Callback invoked with information about the section of the Grid that was just rendered. + * ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }): void + */ + onSectionRendered: Validator<(params: SectionRenderedParams) => void>, + + /** + * Number of columns to render before/after the visible section of the grid. + * These columns can help for smoother scrolling on touch devices or browsers that send scroll events infrequently. + */ + overscanColumnCount: Validator, + + /** + * Calculates the number of cells to overscan before and after a specified range. + * This function ensures that overscanning doesn't exceed the available cells. + * Should implement the following interface: ({ + * cellCount: number, + * overscanCellsCount: number, + * scrollDirection: number, + * startIndex: number, + * stopIndex: number + * }): {overscanStartIndex: number, overscanStopIndex: number} + */ + overscanIndicesGetter: Validator<(params: OverscanIndicesGetterParams) => OverscanIndices>, + + /** + * Number of rows to render above/below the visible section of the grid. + * These rows can help for smoother scrolling on touch devices or browsers that send scroll events infrequently. + */ + overscanRowCount: Validator, + + /** + * ARIA role for the grid element. + */ + role: Requireable, + + /** + * Either a fixed row height (number) or a function that returns the height of a row given its index. + * Should implement the following interface: ({ index: number }): number + */ + rowHeight: Validator number)>, + + /** + * Number of rows in grid. + */ + rowCount: Validator, + + /** Wait this amount of time after the last scroll event before resetting Grid `pointer-events`. */ + scrollingResetTimeInterval: Requireable, + + /** Horizontal offset. */ + scrollLeft: Requireable, + + /** + * Controls scroll-to-cell behavior of the Grid. + * The default ("auto") scrolls the least amount possible to ensure that the specified cell is fully visible. + * Use "start" to align cells to the top/left of the Grid and "end" to align bottom/right. + */ + scrollToAlignment: Validator, + + /** + * Column index to ensure visible (by forcefully scrolling if necessary) + */ + scrollToColumn: Validator, + + /** Vertical offset. */ + scrollTop: Requireable, + + /** + * Row index to ensure visible (by forcefully scrolling if necessary) + */ + scrollToRow: Validator, + + /** Optional inline style */ + style: Requireable, + + /** Tab index for focus */ + tabIndex: Requireable, + + /** + * Width of Grid; this property determines the number of visible (vs virtualized) columns. + */ + width: Validator + }; + + static defaultProps: { + 'aria-label': 'grid', + cellRangeRenderer: GridCellRangeRenderer, + estimatedColumnSize: 100, + estimatedRowSize: 30, + getScrollbarSize: () => number, + noContentRenderer: () => null, + onScroll: () => null, + onSectionRendered: () => null, + overscanColumnCount: 0, + overscanIndicesGetter: OverscanIndicesGetterParams, + overscanRowCount: 10, + role: 'grid', + scrollingResetTimeInterval: typeof DEFAULT_SCROLLING_RESET_TIME_INTERVAL, + scrollToAlignment: 'auto', + scrollToColumn: -1, + scrollToRow: -1, + style: {}, + tabIndex: 0 + }; + + constructor(props: GridProps, context: any); + + /** + * Invalidate Grid size and recompute visible cells. + * This is a deferred wrapper for recomputeGridSize(). + * It sets a flag to be evaluated on cDM/cDU to avoid unnecessary renders. + * This method is intended for advanced use-cases like CellMeasurer. + */ + // @TODO (bvaughn) Add automated test coverage for this. + invalidateCellSizeAfterRender(params: { + columnIndex: number, + rowIndex: number + }): void + + /** + * Pre-measure all columns and rows in a Grid. + * Typically cells are only measured as needed and estimated sizes are used for cells that have not yet been measured. + * This method ensures that the next call to getTotalSize() returns an exact size (as opposed to just an estimated one). + */ + measureAllCells(): void; + + /** + * Forced recompute of row heights and column widths. + * This function should be called if dynamic column or row sizes have changed but nothing else has. + * Since Grid only receives :columnCount and :rowCount it has no way of detecting when the underlying data changes. + */ + recomputeGridSize(params?: { + columnIndex?: number, + rowIndex?: number + }): void; + + /** + * Ensure column and row are visible. + */ + scrollToCell(params: { + columnIndex: number, + rowIndex: number + }): void; + + componentDidMount(): void; + + /** + * @private + * This method updates scrollLeft/scrollTop in state for the following conditions: + * 1) New scroll-to-cell props have been set + */ + componentDidUpdate(prevProps: GridProps, prevState: GridState): void; + + componentWillMount(): void; + + componentWillUnmount(): void; + + /** + * @private + * This method updates scrollLeft/scrollTop in state for the following conditions: + * 1) Empty content (0 rows or columns) + * 2) New scroll props overriding the current state + * 3) Cells-count or cells-size has changed, making previous scroll offsets invalid + */ + componentWillReceiveProps(nextProps: GridProps): void; + + componentWillUpdate(nextProps: GridProps, nextState: GridState): void; + + render(): JSX.Element; +} + +export const defaultCellRangeRenderer: GridCellRangeRenderer; \ No newline at end of file diff --git a/types/react-virtualized/Grid.test.tsx b/types/react-virtualized/Grid.test.tsx new file mode 100644 index 0000000000..634fcdc137 --- /dev/null +++ b/types/react-virtualized/Grid.test.tsx @@ -0,0 +1,207 @@ +/** @flow */ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { AutoSizer, Grid } from 'react-virtualized' + +export default class GridExample extends PureComponent { + + + constructor(props, context) { + super(props, context) + + this.state = { + columnCount: 1000, + height: 300, + overscanColumnCount: 0, + overscanRowCount: 10, + rowHeight: 40, + rowCount: 1000, + scrollToColumn: undefined, + scrollToRow: undefined, + useDynamicRowHeight: false + } + + this._cellRenderer = this._cellRenderer.bind(this) + this._getColumnWidth = this._getColumnWidth.bind(this) + this._getRowClassName = this._getRowClassName.bind(this) + this._getRowHeight = this._getRowHeight.bind(this) + this._noContentRenderer = this._noContentRenderer.bind(this) + this._onColumnCountChange = this._onColumnCountChange.bind(this) + this._onRowCountChange = this._onRowCountChange.bind(this) + this._onScrollToColumnChange = this._onScrollToColumnChange.bind(this) + this._onScrollToRowChange = this._onScrollToRowChange.bind(this) + this._renderBodyCell = this._renderBodyCell.bind(this) + this._renderLeftSideCell = this._renderLeftSideCell.bind(this) + } + + render() { + const { + columnCount, + height, + overscanColumnCount, + overscanRowCount, + rowHeight, + rowCount, + scrollToColumn, + scrollToRow, + useDynamicRowHeight + } = this.state + + return ( + + + {({ width }) => ( + + )} + + ) + } + + _cellRenderer({ columnIndex, key, rowIndex, style }) { + if (columnIndex === 0) { + return this._renderLeftSideCell({ key, rowIndex, style }) + } else { + return this._renderBodyCell({ columnIndex, key, rowIndex, style }) + } + } + + _getColumnWidth({ index }) { + switch (index) { + case 0: + return 50 + case 1: + return 100 + case 2: + return 300 + default: + return 80 + } + } + + _getDatum(index) { + const { list } = this.context + + return list.get(index % list.size) + } + + _getRowClassName(row) { + return row % 2 === 0 ? 'styles.evenRow' : 'styles.oddRow' + } + + _getRowHeight({ index }) { + return this._getDatum(index).size + } + + _noContentRenderer() { + return ( +
+ No cells +
+ ) + } + + _renderBodyCell({ columnIndex, key, rowIndex, style }) { + 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 ( +
+ {content} +
+ ) + } + + _renderLeftSideCell({ key, rowIndex, style }) { + 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 ( +
+ {datum.name.charAt(0)} +
+ ) + } + + _updateUseDynamicRowHeights(value) { + this.setState({ + useDynamicRowHeight: value + }) + } + + _onColumnCountChange(event) { + const columnCount = parseInt(event.target.value, 10) || 0 + + this.setState({ columnCount }) + } + + _onRowCountChange(event) { + const rowCount = parseInt(event.target.value, 10) || 0 + + this.setState({ rowCount }) + } + + _onScrollToColumnChange(event) { + const { columnCount } = this.state + let scrollToColumn = Math.min(columnCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToColumn)) { + scrollToColumn = undefined + } + + this.setState({ scrollToColumn }) + } + + _onScrollToRowChange(event) { + const { rowCount } = this.state + let scrollToRow = Math.min(rowCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToRow)) { + scrollToRow = undefined + } + + this.setState({ scrollToRow }) + } +} diff --git a/types/react-virtualized/InfiniteLoader.d.ts b/types/react-virtualized/InfiniteLoader.d.ts new file mode 100644 index 0000000000..4493921e72 --- /dev/null +++ b/types/react-virtualized/InfiniteLoader.d.ts @@ -0,0 +1,80 @@ +import { PureComponent, Validator, Requireable } from 'react' +import { Index, IndexRange } from './genericTypes'; + +export type InfiniteLoaderChildProps = { + onRowsRendered: (params: { startIndex: number, stopIndex: number }) => void, + registerChild: (registeredChild: any) => void +} + +export type InfiniteLoaderProps = { + children?: (props: InfiniteLoaderChildProps) => React.ReactNode; + isRowLoaded: (params: Index) => boolean; + loadMoreRows: (params: IndexRange) => Promise; + minimumBatchSize?: number; + rowCount?: number; + threshold?: number; +}; + +/** + * Higher-order component that manages lazy-loading for "infinite" data. + * This component decorates a virtual component and just-in-time prefetches rows as a user scrolls. + * It is intended as a convenience component; fork it if you'd like finer-grained control over data-loading. + */ +export class InfiniteLoader extends PureComponent { + static propTypes: { + /** + * Function responsible for rendering a virtualized component. + * This function should implement the following signature: + * ({ onRowsRendered, registerChild }) => PropTypes.element + * + * The specified :onRowsRendered function should be passed through to the child's :onRowsRendered property. + * The :registerChild callback should be set as the virtualized component's :ref. + */ + children: Validator<(props: InfiniteLoaderChildProps) => React.ReactNode>, + + /** + * Function responsible for tracking the loaded state of each row. + * It should implement the following signature: ({ index: number }): boolean + */ + isRowLoaded: Validator<(params: Index) => boolean>, + + /** + * Callback to be invoked when more rows must be loaded. + * It should implement the following signature: ({ startIndex, stopIndex }): Promise + * The returned Promise should be resolved once row data has finished loading. + * It will be used to determine when to refresh the list with the newly-loaded data. + * This callback may be called multiple times in reaction to a single scroll event. + */ + loadMoreRows: Validator<(params: IndexRange) => Promise>, + + /** + * Minimum number of rows to be loaded at a time. + * This property can be used to batch requests to reduce HTTP requests. + */ + minimumBatchSize: Validator, + + /** + * Number of rows in list; can be arbitrary high number if actual number is unknown. + */ + rowCount: Validator, + + /** + * Threshold at which to pre-fetch data. + * A threshold X means that data will start loading when a user scrolls within X rows. + * This value defaults to 15. + */ + threshold: Validator + }; + + static defaultProps: { + minimumBatchSize: 10, + rowCount: 0, + threshold: 15 + }; + + constructor(props: InfiniteLoaderProps, context: any); + + resetLoadMoreRowsCache(): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/InfiniteLoader.test.tsx b/types/react-virtualized/InfiniteLoader.test.tsx new file mode 100644 index 0000000000..0509f46216 --- /dev/null +++ b/types/react-virtualized/InfiniteLoader.test.tsx @@ -0,0 +1,138 @@ +/** @flow */ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { AutoSizer, InfiniteLoader, List } from 'react-virtualized' + +const STATUS_LOADING = 1 +const STATUS_LOADED = 2 + +export default class InfiniteLoaderExample extends PureComponent { + _timeoutIdMap: any; + + constructor(props) { + super(props) + + this._timeoutIdMap = {} + + this._clearData = this._clearData.bind(this) + this._isRowLoaded = this._isRowLoaded.bind(this) + this._loadMoreRows = this._loadMoreRows.bind(this) + this._rowRenderer = this._rowRenderer.bind(this) + } + + componentWillUnmount() { + Object.keys(this._timeoutIdMap).forEach(timeoutId => { + clearTimeout(timeoutId as any) + }) + } + + render() { + const { list } = this.context + const { loadedRowCount, loadingRowCount } = this.state + + return ( + + {({ onRowsRendered, registerChild }) => ( + + {({ width }) => ( + + )} + + )} + + ) + } + + _clearData() { + this.setState({ + loadedRowCount: 0, + loadedRowsMap: {}, + loadingRowCount: 0 + }) + } + + _isRowLoaded({ index }) { + const { loadedRowsMap } = this.state + return !!loadedRowsMap[index] // STATUS_LOADING or STATUS_LOADED + } + + _loadMoreRows({ startIndex, stopIndex }) { + const { loadedRowsMap, loadingRowCount } = this.state + const increment = stopIndex - startIndex + 1 + + for (var i = startIndex; i <= stopIndex; i++) { + loadedRowsMap[i] = STATUS_LOADING + } + + this.setState({ + loadingRowCount: loadingRowCount + increment + }) + + const timeoutId = setTimeout(() => { + const { loadedRowCount, loadingRowCount } = this.state + + delete this._timeoutIdMap[timeoutId] + + for (var 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._timeoutIdMap[timeoutId] = true + + let promiseResolver + + return new Promise(resolve => { + promiseResolver = resolve + }) + } + + _rowRenderer({ index, key, style }) { + 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 = ( +
+ ) + } + + return ( +
+ {content} +
+ ) + } +} diff --git a/types/react-virtualized/List.d.ts b/types/react-virtualized/List.d.ts new file mode 100644 index 0000000000..d4d5196a34 --- /dev/null +++ b/types/react-virtualized/List.d.ts @@ -0,0 +1,138 @@ +/** @flow */ +import { PureComponent, Validator, Requireable } from 'react' +import { Grid, GridCellProps } from './Grid' +import { Index, IndexRange, Alignment } from './genericTypes' +import { CellMeasurerCache } from './CellMeasurer' + +export type ListRowProps = GridCellProps & { index: number, style: React.CSSProperties }; + +export type ListRowRenderer = (props: ListRowProps) => React.ReactNode; +export type ListProps = { + deferredMeasurementCache?: CellMeasurerCache; + className?: string; + autoHeight?: boolean; + estimatedRowSize?: number; + height: number; + noRowsRenderer?: () => JSX.Element; + onRowsRendered?: (info: { overscanStartIndex: number, overscanStopIndex: number, startIndex: number, stopIndex: number }) => void; + onScroll?: (info: { clientHeight: number, scrollHeight: number, scrollTop: number }) => void; + overscanRowCount?: number; + rowHeight: number | ((info: Index) => number); + rowRenderer: ListRowRenderer; + rowCount: number; + scrollToAlignment?: string; + scrollToIndex?: number; + scrollTop?: number; + style?: React.CSSProperties; + tabIndex?: number; + width: number; +} +/** + * It is inefficient to create and manage a large list of DOM elements within a scrolling container + * if only a few of those elements are visible. The primary purpose of this component is to improve + * performance by only rendering the DOM nodes that a user is able to see based on their current + * scroll position. + * + * This component renders a virtualized list of elements with either fixed or dynamic heights. + */ +export class List extends PureComponent { + static propTypes: { + 'aria-label': Requireable, + + /** + * Removes fixed height from the scrollingContainer so that the total height + * of rows can stretch the window. Intended for use with WindowScroller + */ + autoHeight: Requireable, + + /** Optional CSS class name */ + className: Requireable, + + /** + * Used to estimate the total height of a List before all of its rows have actually been measured. + * The estimated total height is adjusted as rows are rendered. + */ + estimatedRowSize: Validator, + + /** Height constraint for list (determines how many actual rows are rendered) */ + height: Validator, + + /** Optional renderer to be used in place of rows when rowCount is 0 */ + noRowsRenderer: Validator<() => JSX.Element>, + + /** + * Callback invoked with information about the slice of rows that were just rendered. + * ({ startIndex, stopIndex }): void + */ + onRowsRendered: Validator<(params: IndexRange) => void>, + + /** + * Number of rows to render above/below the visible bounds of the list. + * These rows can help for smoother scrolling on touch devices. + */ + overscanRowCount: Validator, + + /** + * Callback invoked whenever the scroll offset changes within the inner scrollable region. + * This callback can be used to sync scrolling between lists, tables, or grids. + * ({ clientHeight, scrollHeight, scrollTop }): void + */ + onScroll: Validator<(params: { clientHeight: number, scrollHeight: number, scrollTop: number }) => void>, + + /** + * Either a fixed row height (number) or a function that returns the height of a row given its index. + * ({ index: number }): number + */ + rowHeight: Validator number)>, + + /** Responsible for rendering a row given an index; ({ index: number }): node */ + rowRenderer: Validator, + + /** Number of rows in list. */ + rowCount: Validator, + + /** See Grid#scrollToAlignment */ + scrollToAlignment: Validator, + + /** Row index to ensure visible (by forcefully scrolling if necessary) */ + scrollToIndex: Validator, + + /** Vertical offset. */ + scrollTop: Requireable, + + /** Optional inline style */ + style: Validator, + + /** Tab index for focus */ + tabIndex: Requireable, + + /** Width of list */ + width: Validator + }; + + static defaultProps: { + estimatedRowSize: 30, + noRowsRenderer: () => null, + onRowsRendered: () => null, + onScroll: () => null, + overscanRowCount: 10, + scrollToAlignment: 'auto', + scrollToIndex: -1, + style: {} + }; + + constructor(props: ListProps, context: any); + + forceUpdateGrid(): void; + + /** See Grid#measureAllCells */ + measureAllRows(): void; + + /** See Grid#recomputeGridSize */ + recomputeRowHeights(index?: number): void; + + /** See Grid#scrollToCell */ + scrollToRow(index?: number): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/List.test.tsx b/types/react-virtualized/List.test.tsx new file mode 100644 index 0000000000..86763a95f8 --- /dev/null +++ b/types/react-virtualized/List.test.tsx @@ -0,0 +1,160 @@ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { AutoSizer, List } from 'react-virtualized' + +export default class ListExample extends PureComponent { + + constructor(props, context) { + super(props, context) + + this.state = { + listHeight: 300, + listRowHeight: 50, + overscanRowCount: 10, + rowCount: context.list.size, + scrollToIndex: undefined, + showScrollingPlaceholder: false, + useDynamicRowHeight: false + } + + this._getRowHeight = this._getRowHeight.bind(this) + this._noRowsRenderer = this._noRowsRenderer.bind(this) + this._onRowCountChange = this._onRowCountChange.bind(this) + this._onScrollToRowChange = this._onScrollToRowChange.bind(this) + this._rowRenderer = this._rowRenderer.bind(this) + } + + render() { + const { + listHeight, + listRowHeight, + overscanRowCount, + rowCount, + scrollToIndex, + showScrollingPlaceholder, + useDynamicRowHeight + } = this.state + + return ( + + {({ width }) => ( + + )} + + ) + } + + _getDatum(index) { + const { list } = this.context + + return list.get(index % list.size) + } + + _getRowHeight({ index }) { + return this._getDatum(index).size + } + + _noRowsRenderer() { + return ( +
+ No rows +
+ ) + } + + _onRowCountChange(event) { + const rowCount = parseInt(event.target.value, 10) || 0 + + this.setState({ rowCount }) + } + + _onScrollToRowChange(event) { + const { rowCount } = this.state + let scrollToIndex = Math.min(rowCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToIndex)) { + scrollToIndex = undefined + } + + this.setState({ scrollToIndex }) + } + + _rowRenderer({ index, isScrolling, key, style }) { + const { + showScrollingPlaceholder, + useDynamicRowHeight + } = this.state + + if ( + showScrollingPlaceholder && + isScrolling + ) { + return ( +
+ Scrolling... +
+ ) + } + + const datum = this._getDatum(index) + + let additionalContent + + if (useDynamicRowHeight) { + switch (datum.size) { + case 75: + additionalContent =
It is medium-sized.
+ break + case 100: + additionalContent =
It is large-sized.
It has a 3rd row.
+ break + } + } + + return ( +
+
+ {datum.name.charAt(0)} +
+
+
+ {datum.name} +
+
+ This is row {index} +
+ {additionalContent} +
+ {useDynamicRowHeight && + + {datum.size}px + + } +
+ ) + } +} diff --git a/types/react-virtualized/Masonry.d.ts b/types/react-virtualized/Masonry.d.ts new file mode 100644 index 0000000000..c4187bf611 --- /dev/null +++ b/types/react-virtualized/Masonry.d.ts @@ -0,0 +1,146 @@ +import { PureComponent, Validator, Requireable } from 'react' +import { } from './genericTypes'; +import { CellMeasurerCache, KeyMapper } from './CellMeasurer'; +import { GridCellRenderer } from './Grid'; +/** + * Specifies the number of miliseconds during which to disable pointer events while a scroll is in progress. + * This improves performance and makes scrolling smoother. + */ +export const DEFAULT_SCROLLING_RESET_TIME_INTERVAL = 150 + +export type OnCellsRenderedCallback = (params: { + startIndex: number, + stopIndex: number +}) => void; + +export type OnScrollCallback = (params: { + clientHeight: number, + scrollHeight: number, + scrollTop: number +}) => void; + +export type MasonryCellProps = { + index: number, + isScrolling: boolean, + key: React.Key, + parent: React.ReactType, + style?: React.CSSProperties +} + +export type CellRenderer = (props: MasonryCellProps) => React.ReactNode + +export type MasonryProps = { + autoHeight: boolean, + cellCount: number, + cellMeasurerCache: CellMeasurerCache, + cellPositioner: Positioner, + cellRenderer: CellRenderer, + className?: string, + height: number, + id?: string, + keyMapper?: KeyMapper, + onCellsRendered?: OnCellsRenderedCallback, + onScroll?: OnScrollCallback, + overscanByPixels?: number, + role?: string, + scrollingResetTimeInterval?: number, + scrollTop?: number, + style?: React.CSSProperties, + tabIndex?: number, + width: number +} + +export type MasonryState = { + isScrolling: boolean, + scrollTop: number +} + +/** + * This component efficiently displays arbitrarily positioned cells using windowing techniques. + * Cell position is determined by an injected `cellPositioner` property. + * Windowing is vertical; this component does not support horizontal scrolling. + * + * Rendering occurs in two phases: + * 1) First pass uses estimated cell sizes (provided by the cache) to determine how many cells to measure in a batch. + * Batch size is chosen using a fast, naive layout algorithm that stacks images in order until the viewport has been filled. + * After measurement is complete (componentDidMount or componentDidUpdate) this component evaluates positioned cells + * in order to determine if another measurement pass is required (eg if actual cell sizes were less than estimated sizes). + * All measurements are permanently cached (keyed by `keyMapper`) for performance purposes. + * 2) Second pass uses the external `cellPositioner` to layout cells. + * At this time the positioner has access to cached size measurements for all cells. + * The positions it returns are cached by Masonry for fast access later. + * Phase one is repeated if the user scrolls beyond the current layout's bounds. + * If the layout is invalidated due to eg a resize, cached positions can be cleared using `recomputeCellPositions()`. + * + * Animation constraints: + * Simple animations are supported (eg translate/slide into place on initial reveal). + * More complex animations are not (eg flying from one position to another on resize). + * + * Layout constraints: + * This component supports multi-column layout. + * The height of each item may vary. + * The width of each item must not exceed the width of the column it is "in". + * The left position of all items within a column must align. + * (Items may not span multiple columns.) + */ +export class Masonry extends PureComponent { + + static defaultProps: { + autoHeight: false, + keyMapper: identity, + onCellsRendered: noop, + onScroll: noop, + overscanByPixels: 20, + role: 'grid', + scrollingResetTimeInterval: typeof DEFAULT_SCROLLING_RESET_TIME_INTERVAL, + style: emptyObject, + tabIndex: 0 + } + + constructor(props: MasonryProps, context: any); + + clearCellPositions(): void; + + // HACK This method signature was intended for Grid + invalidateCellSizeAfterRender(params: { rowIndex: number }): void + + recomputeCellPositions(): void; + + componentDidMount(): void; + + componentDidUpdate(prevProps: MasonryProps, prevState: MasonryState): void; + + componentWillUnmount(): void; + + componentWillReceiveProps(nextProps: MasonryProps): void; + + render(): JSX.Element; +} + +type emptyObject = {} + +type identity = (value: T) => T; + +type noop = () => void; + +export type Position = { + left: number, + top: number +}; + +export type createCellPositionerParams = { + cellMeasurerCache: CellMeasurerCache, + columnCount: number, + columnWidth: number, + spacer?: number +}; + +export type resetParams = { + columnCount: number, + columnWidth: number, + spacer?: number +}; + +export type Positioner = ((index: number) => Position) & {reset: (params: resetParams) => void}; + +export const createCellPositioner: (params: createCellPositionerParams) => Positioner; \ No newline at end of file diff --git a/types/react-virtualized/Masonry.test.tsx b/types/react-virtualized/Masonry.test.tsx new file mode 100644 index 0000000000..902e5498c5 --- /dev/null +++ b/types/react-virtualized/Masonry.test.tsx @@ -0,0 +1,200 @@ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { + CellMeasurer, + CellMeasurerCache, + AutoSizer, + WindowScroller, + createMasonryCellPositioner as createCellPositioner, + Positioner, + Masonry, + MasonryCellProps +} from 'react-virtualized' + +export default class GridExample extends PureComponent { + _columnCount: number; + _cache: CellMeasurerCache; + _columnHeights: any; + _width: number; + _height: number; + _scrollTop: number; + _cellPositioner?: Positioner; + _masonry: Masonry; + + constructor(props, context) { + 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 + + let child + + if (windowScrollerEnabled) { + child = ( + + {this._renderAutoSizer} + + ) + } else { + child = this._renderAutoSizer({ height }) + } + + return ( +
+ {child} +
+ ) + } + + _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 ( + +
+
+ {datum.random} +
+ + ) + } + + _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 }) { + 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 ( + + {this._renderMasonry} + + ) + } + + _renderMasonry({ width }) { + this._width = width + + this._calculateColumnCount() + this._initCellPositioner() + + const { height, windowScrollerEnabled } = this.state + + return ( + + ) + } + + _resetCellPositioner() { + const { + columnWidth, + gutterSize + } = this.state + + this._cellPositioner.reset({ + columnCount: this._columnCount, + columnWidth, + spacer: gutterSize + }) + } + + _setMasonryRef(ref) { + this._masonry = ref + } +} diff --git a/types/react-virtualized/MultiGrid.d.ts b/types/react-virtualized/MultiGrid.d.ts new file mode 100644 index 0000000000..1bb8b7dfac --- /dev/null +++ b/types/react-virtualized/MultiGrid.d.ts @@ -0,0 +1,75 @@ +import { PureComponent, Validator, Requireable } from 'react' +import { GridProps } from './Grid' + +export type MultiGridProps = { + fixedColumnCount: number; + fixedRowCount: number; + style: React.CSSProperties; + styleBottomLeftGrid: React.CSSProperties; + styleBottomRightGrid: React.CSSProperties; + styleTopLeftGrid: React.CSSProperties; + styleTopRightGrid: React.CSSProperties; +} & GridProps; + +export type MultiGridState = { + scrollLeft: number, + scrollTop: number +} + +/** + * Renders 1, 2, or 4 Grids depending on configuration. + * A main (body) Grid will always be rendered. + * Optionally, 1-2 Grids for sticky header rows will also be rendered. + * If no sticky columns, only 1 sticky header Grid will be rendered. + * If sticky columns, 2 sticky header Grids will be rendered. + */ +export class MultiGrid extends PureComponent { + static propTypes: { + fixedColumnCount: Validator, + fixedRowCount: Validator, + style: Validator, + styleBottomLeftGrid: Validator, + styleBottomRightGrid: Validator, + styleTopLeftGrid: Validator, + styleTopRightGrid: Validator + }; + + static defaultProps: { + fixedColumnCount: 0, + fixedRowCount: 0, + style: {}, + styleBottomLeftGrid: {}, + styleBottomRightGrid: {}, + styleTopLeftGrid: {}, + styleTopRightGrid: {} + }; + + constructor(props: MultiGridProps, context: any); + + forceUpdateGrids(): void; + + /** See Grid#invalidateCellSizeAfterRender */ + invalidateCellSizeAfterRender(params?: { + columnIndex?: number, + rowIndex?: number + }): void; + + /** See Grid#measureAllCells */ + measureAllCells(): void; + + /** See Grid#recomputeGridSize */ + recomputeGridSize(params?: { + columnIndex?: number, + rowIndex?: number + }): void; + + componentDidMount(): void; + + componentDidUpdate(prevProps: MultiGridProps, prevState: MultiGridState): void; + + componentWillMount(): void; + + componentWillReceiveProps(nextProps: MultiGridProps, nextState: MultiGridState): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/MultiGrid.test.tsx b/types/react-virtualized/MultiGrid.test.tsx new file mode 100644 index 0000000000..f2f3af9397 --- /dev/null +++ b/types/react-virtualized/MultiGrid.test.tsx @@ -0,0 +1,105 @@ +/** @flow */ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { AutoSizer, 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 default class MultiGridExample extends PureComponent { + state + _onFixedColumnCountChange + _onFixedRowCountChange + _onScrollToColumnChange + _onScrollToRowChange + + constructor(props, context) { + super(props, context) + + this.state = { + fixedColumnCount: 2, + fixedRowCount: 1, + scrollToColumn: 0, + scrollToRow: 0 + } + + this._cellRenderer = this._cellRenderer.bind(this) + this._onFixedColumnCountChange = this._createEventHandler('fixedColumnCount') + this._onFixedRowCountChange = this._createEventHandler('fixedRowCount') + this._onScrollToColumnChange = this._createEventHandler('scrollToColumn') + this._onScrollToRowChange = this._createEventHandler('scrollToRow') + } + + render() { + return ( + + {({ width }) => ( + + )} + + ) + } + + _cellRenderer({ columnIndex, key, rowIndex, style }) { + return ( +
+ {columnIndex}, {rowIndex} +
+ ) + } + + _createEventHandler(property) { + return (event) => { + const value = parseInt(event.target.value, 10) || 0 + + this.setState({ + [property]: value + }) + } + } + + _createLabeledInput(property, eventHandler) { + const value = this.state[property] + + return ( + `` + ) + } +} diff --git a/types/react-virtualized/ScrollSync.d.ts b/types/react-virtualized/ScrollSync.d.ts new file mode 100644 index 0000000000..4f1e924a69 --- /dev/null +++ b/types/react-virtualized/ScrollSync.d.ts @@ -0,0 +1,51 @@ +import { PureComponent, Validator, Requireable } from 'react' + +export type OnScrollParams = { + clientHeight: number, + clientWidth: number, + scrollHeight: number, + scrollLeft: number, + scrollTop: number, + scrollWidth: number +} + +export type ScrollSyncChildProps = { + clientHeight: number, + clientWidth: number, + onScroll: (params: OnScrollParams) => void, + scrollHeight: number, + scrollLeft: number, + scrollTop: number, + scrollWidth: number +} + +export type ScrollSyncProps = { + children?: (props: ScrollSyncChildProps) => React.ReactNode +}; + +export type ScrollSyncState = { + clientHeight: number, + clientWidth: number, + scrollHeight: number, + scrollLeft: number, + scrollTop: number, + scrollWidth: number +}; + +/** + * HOC that simplifies the process of synchronizing scrolling between two or more virtualized components. + */ +export class ScrollSync extends PureComponent { + static propTypes: { + /** + * Function responsible for rendering 2 or more virtualized components. + * This function should implement the following signature: + * ({ onScroll, scrollLeft, scrollTop }) => PropTypes.element + */ + children: Validator<(props: ScrollSyncChildProps) => React.ReactNode> + }; + + constructor(props: ScrollSyncProps, context: any); + + render(): JSX.Element; +} \ No newline at end of file diff --git a/types/react-virtualized/ScrollSync.test.tsx b/types/react-virtualized/ScrollSync.test.tsx new file mode 100644 index 0000000000..9919b72ab3 --- /dev/null +++ b/types/react-virtualized/ScrollSync.test.tsx @@ -0,0 +1,222 @@ +import * as React from 'react' +import { PureComponent } from 'react' +import { AutoSizer, Grid, 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 default class GridExample extends PureComponent { + state + constructor(props, context) { + super(props, context) + + this.state = { + columnWidth: 75, + columnCount: 50, + height: 300, + overscanColumnCount: 0, + overscanRowCount: 5, + rowHeight: 40, + rowCount: 100 + } + + this._renderBodyCell = this._renderBodyCell.bind(this) + this._renderHeaderCell = this._renderHeaderCell.bind(this) + this._renderLeftSideCell = this._renderLeftSideCell.bind(this) + } + + render() { + const { + columnCount, + columnWidth, + height, + overscanColumnCount, + overscanRowCount, + rowHeight, + rowCount + } = this.state + + return ( + + + {({ 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 ( +
+
+ +
+
+ +
+
+ + {({ width }) => ( +
+
+ +
+
+ +
+
+ )} +
+
+
+ ) + }} +
+ ) + } + + _renderBodyCell({ columnIndex, key, rowIndex, style }) { + if (columnIndex < 1) { + return + } + + return this._renderLeftSideCell({ columnIndex, key, rowIndex, style }) + } + + _renderHeaderCell({ columnIndex, key, rowIndex, style }) { + if (columnIndex < 1) { + return + } + + return this._renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) + } + + _renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) { + return ( +
+ {`C${columnIndex}`} +
+ ) + } + + _renderLeftSideCell({ columnIndex, key, rowIndex, style }) { + return ( +
+ {`R${rowIndex}, C${columnIndex}`} +
+ ) + } +} + +function hexToRgb(hex) { + 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, color2, amount) { + 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 } +} diff --git a/types/react-virtualized/Table.d.ts b/types/react-virtualized/Table.d.ts new file mode 100644 index 0000000000..af5cf9b0b5 --- /dev/null +++ b/types/react-virtualized/Table.d.ts @@ -0,0 +1,447 @@ +import { Validator, Requireable, PureComponent, Component } from 'react'; +import { CellMeasurerCache } from './CellMeasurer'; +import { Index, Alignment, ScrollEventData, IndexRange, OverscanIndexRange } from './genericTypes'; +import { Grid } from './Grid'; + +export type TableCellDataGetterParams = { + columnData?: any, + dataKey: string, + rowData: any +}; +export type TableCellProps = { + cellData?: any, + columnData?: any, + dataKey: string, + rowData: any, + rowIndex: number +}; +export type TableHeaderProps = { + columnData?: any, + dataKey: string, + disableSort?: boolean, + label?: string, + sortBy?: string, + sortDirection?: SortDirectionType +}; +export type TableHeaderRowProps = { + className: string, + columns: React.ReactNode[], + style: React.CSSProperties, + scrollbarWidth: number, + height: number, + width: number +}; +export type TableRowProps = { + className: string, + columns: Array, + index: number, + isScrolling: boolean, + onRowClick?: (params: RowMouseEventHandlerParams) => void, + onRowDoubleClick?: (params: RowMouseEventHandlerParams) => void, + onRowMouseOver?: (params: RowMouseEventHandlerParams) => void, + onRowMouseOut?: (params: RowMouseEventHandlerParams) => void, + rowData: any, + style: any +}; + +export type TableCellDataGetter = (params: TableCellDataGetterParams) => any; +export type TableCellRenderer = (props: TableCellProps) => React.ReactNode; +export type TableHeaderRenderer = (props: TableHeaderProps) => React.ReactNode; +export type TableHeaderRowRenderer = (props: TableHeaderRowProps) => React.ReactNode; +export type TableRowRenderer = (props: TableRowProps) => React.ReactNode; + +// https://github.com/bvaughn/react-virtualized/blob/master/docs/Column.md +export type ColumnProps = { + cellDataGetter?: TableCellDataGetter; + cellRenderer?: TableCellRenderer; + className?: string; + columnData?: any; + dataKey: any; + disableSort?: boolean; + flexGrow?: number; + flexShrink?: number; + headerClassName?: string; + headerRenderer?: TableHeaderRenderer; + label?: string; + maxWidth?: number; + minWidth?: number; + style?: React.CSSProperties; + width: number; +} +export class Column extends Component { + static propTypes: { + /** Optional aria-label value to set on the column header */ + 'aria-label': Requireable, + + /** + * Callback responsible for returning a cell's data, given its :dataKey + * ({ columnData: any, dataKey: string, rowData: any }): any + */ + cellDataGetter: Requireable, + + /** + * Callback responsible for rendering a cell's contents. + * ({ cellData: any, columnData: any, dataKey: string, rowData: any, rowIndex: number }): node + */ + cellRenderer: Requireable, + + /** Optional CSS class to apply to cell */ + className: Requireable, + + /** Optional additional data passed to this column's :cellDataGetter */ + columnData: Requireable, + + /** Uniquely identifies the row-data attribute correspnding to this cell */ + dataKey: Validator, + + /** If sort is enabled for the table at large, disable it for this column */ + disableSort: Requireable, + + /** Flex grow style; defaults to 0 */ + flexGrow: Requireable, + + /** Flex shrink style; defaults to 1 */ + flexShrink: Requireable, + + /** Optional CSS class to apply to this column's header */ + headerClassName: Requireable, + + /** + * Optional callback responsible for rendering a column header contents. + * ({ columnData: object, dataKey: string, disableSort: boolean, label: string, sortBy: string, sortDirection: string }): PropTypes.node + */ + headerRenderer: Validator, + + /** Header label for this column */ + label: Requireable, + + /** Maximum width of column; this property will only be used if :flexGrow is > 0. */ + maxWidth: Requireable, + + /** Minimum width of column. */ + minWidth: Requireable, + + /** Optional inline style to apply to cell */ + style: Requireable, + + /** Flex basis (width) for this column; This value can grow or shrink based on :flexGrow and :flexShrink properties. */ + width: Validator + }; + + static defaultProps: { + cellDataGetter: TableCellDataGetter, + cellRenderer: TableCellRenderer, + flexGrow: 0, + flexShrink: 1, + headerRenderer: TableHeaderRenderer, + style: {} + }; +} + +export type RowMouseEventHandlerParams = { + rowData: { + columnData: object, + id: string, + index: number + }, + index: number, + event: React.SyntheticEvent> +} + +export type HeaderMouseEventHandlerParams = { + dataKey: string, + columnData: any, + event: React.SyntheticEvent> +} + +// ref: https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md +export type TableProps = { + deferredMeasurementCache?: CellMeasurerCache; + autoHeight?: boolean; + children?: React.ReactChildren; + className?: string; + disableHeader?: boolean; + estimatedRowSize?: number; + gridClassName?: string; + gridStyle?: any; + headerClassName?: string; + headerHeight: number; + headerStyle?: any; + height?: number; + id?: string; + noRowsRenderer?: () => void; + onHeaderClick?: (params: HeaderMouseEventHandlerParams) => void; + onRowClick?: (info: RowMouseEventHandlerParams) => void; + onRowDoubleClick?: (info: RowMouseEventHandlerParams) => void; + onRowMouseOut?: (info: RowMouseEventHandlerParams) => void; + onRowMouseOver?: (info: RowMouseEventHandlerParams) => void; + onRowsRendered?: (info: IndexRange & OverscanIndexRange) => void; + overscanRowCount?: number; + onScroll?: (info: ScrollEventData) => void; + rowClassName?: string | ((info: Index) => string); + rowCount: number; + rowGetter?: (info: Index) => any; + rowHeight: number | ((info: Index) => number); + rowRenderer?: TableRowRenderer; + headerRowRenderer?: TableHeaderRowRenderer; + rowStyle?: React.CSSProperties | ((info: Index) => React.CSSProperties); + scrollToAlignment?: string; + scrollToIndex?: number; + scrollTop?: number; + sort?: (info: { sortBy: string, sortDirection: SortDirectionType }) => void; + sortBy?: string; + sortDirection?: SortDirectionType; + style?: React.CSSProperties; + tabIndex?: number; + width?: number; +} + +export const defaultTableCellDataGetter: TableCellDataGetter; +export const defaultTableCellRenderer: TableCellRenderer; +export const defaultTableHeaderRenderer: () => React.ReactElement[]; +export const defaultTableHeaderRowRenderer: TableHeaderRowRenderer; +export const defaultTableRowRenderer: TableRowRenderer; + +type SortDirectionStatic = { + /** + * Sort items in ascending order. + * This means arranging from the lowest value to the highest (e.g. a-z, 0-9). + */ + ASC: 'ASC', + + /** + * Sort items in descending order. + * This means arranging from the highest value to the lowest (e.g. z-a, 9-0). + */ + DESC: 'DESC' +} + +export const SortDirection: SortDirectionStatic + +export type SortDirectionType = 'ASC' | 'DESC' + +export const SortIndicator: React.StatelessComponent<{ sortDirection: SortDirectionType }> + +/** + * Table component with fixed headers and virtualized rows for improved performance with large data sets. + * This component expects explicit width, height, and padding parameters. + */ +export class Table extends PureComponent { + static propTypes: { + 'aria-label': Requireable, + + /** + * Removes fixed height from the scrollingContainer so that the total height + * of rows can stretch the window. Intended for use with WindowScroller + */ + autoHeight: Requireable, + + /** One or more Columns describing the data displayed in this row */ + children: Validator, + + /** Optional CSS class name */ + className: Requireable, + + /** Disable rendering the header at all */ + disableHeader: Requireable, + + /** + * Used to estimate the total height of a Table before all of its rows have actually been measured. + * The estimated total height is adjusted as rows are rendered. + */ + estimatedRowSize: Validator, + + /** Optional custom CSS class name to attach to inner Grid element. */ + gridClassName: Requireable, + + /** Optional inline style to attach to inner Grid element. */ + gridStyle: Requireable, + + /** Optional CSS class to apply to all column headers */ + headerClassName: Requireable, + + /** Fixed height of header row */ + headerHeight: Validator, + + /** + * Responsible for rendering a table row given an array of columns: + * Should implement the following interface: ({ + * className: string, + * columns: any[], + * style: any + * }): PropTypes.node + */ + headerRowRenderer: Requireable, + + /** Optional custom inline style to attach to table header columns. */ + headerStyle: Requireable, + + /** Fixed/available height for out DOM element */ + height: Validator, + + /** Optional id */ + id: Requireable, + + /** Optional renderer to be used in place of table body rows when rowCount is 0 */ + noRowsRenderer: Requireable<() => JSX.Element>, + + /** + * Optional callback when a column's header is clicked. + * ({ columnData: any, dataKey: string }): void + */ + onHeaderClick: Requireable<(params: HeaderMouseEventHandlerParams) => void>, + + /** + * Callback invoked when a user clicks on a table row. + * ({ index: number }): void + */ + onRowClick: Requireable<(params: RowMouseEventHandlerParams) => void>, + + /** + * Callback invoked when a user double-clicks on a table row. + * ({ index: number }): void + */ + onRowDoubleClick: Requireable<(params: RowMouseEventHandlerParams) => void>, + + /** + * Callback invoked when the mouse leaves a table row. + * ({ index: number }): void + */ + onRowMouseOut: Requireable<(params: RowMouseEventHandlerParams) => void>, + + /** + * Callback invoked when a user moves the mouse over a table row. + * ({ index: number }): void + */ + onRowMouseOver: Requireable<(params: RowMouseEventHandlerParams) => void>, + + /** + * Callback invoked with information about the slice of rows that were just rendered. + * ({ startIndex, stopIndex }): void + */ + onRowsRendered: Requireable<(params: RowMouseEventHandlerParams) => void>, + + /** + * Callback invoked whenever the scroll offset changes within the inner scrollable region. + * This callback can be used to sync scrolling between lists, tables, or grids. + * ({ clientHeight, scrollHeight, scrollTop }): void + */ + onScroll: Requireable<(params: ScrollEventData) => void>, + + /** + * Number of rows to render above/below the visible bounds of the list. + * These rows can help for smoother scrolling on touch devices. + */ + overscanRowCount: Validator, + + /** + * Optional CSS class to apply to all table rows (including the header row). + * This property can be a CSS class name (string) or a function that returns a class name. + * If a function is provided its signature should be: ({ index: number }): string + */ + rowClassName: Requireable string)>, + + /** + * Callback responsible for returning a data row given an index. + * ({ index: number }): any + */ + rowGetter: Validator<(params: Index) => any>, + + /** + * Either a fixed row height (number) or a function that returns the height of a row given its index. + * ({ index: number }): number + */ + rowHeight: Validator number)>, + + /** Number of rows in table. */ + rowCount: Validator, + + /** + * Responsible for rendering a table row given an array of columns: + * Should implement the following interface: ({ + * className: string, + * columns: Array, + * index: number, + * isScrolling: boolean, + * onRowClick: ?Function, + * onRowDoubleClick: ?Function, + * onRowMouseOver: ?Function, + * onRowMouseOut: ?Function, + * rowData: any, + * style: any + * }): PropTypes.node + */ + rowRenderer: Requireable<(props: TableRowProps) => React.ReactNode>, + + /** Optional custom inline style to attach to table rows. */ + rowStyle: Validator React.CSSProperties)>, + + /** See Grid#scrollToAlignment */ + scrollToAlignment: Validator, + + /** Row index to ensure visible (by forcefully scrolling if necessary) */ + scrollToIndex: Validator, + + /** Vertical offset. */ + scrollTop: Requireable, + + /** + * Sort function to be called if a sortable header is clicked. + * ({ sortBy: string, sortDirection: SortDirection }): void + */ + sort: Requireable<(params: { sortBy: string, sortDirection: SortDirectionType }) => void>, + + /** Table data is currently sorted by this :dataKey (if it is sorted at all) */ + sortBy: Requireable, + + /** Table data is currently sorted in this direction (if it is sorted at all) */ + sortDirection: Validator, + + /** Optional inline style */ + style: Requireable, + + /** Tab index for focus */ + tabIndex: Requireable, + + /** Width of list */ + width: Validator + }; + + static defaultProps: { + disableHeader: false, + estimatedRowSize: 30, + headerHeight: 0, + headerStyle: {}, + noRowsRenderer: () => null, + onRowsRendered: () => null, + onScroll: () => null, + overscanRowCount: 10, + rowRenderer: TableRowRenderer, + headerRowRenderer: TableHeaderRenderer, + rowStyle: {}, + scrollToAlignment: 'auto', + scrollToIndex: -1, + style: {} + }; + + Grid: Grid; + + constructor(props: TableProps); + + forceUpdateGrid(): void; + + /** See Grid#measureAllCells */ + measureAllRows(): void; + + /** See Grid#recomputeGridSize */ + recomputeRowHeights(index?: number): void; + + /** See Grid#scrollToCell */ + scrollToRow(index?: number): void + + componentDidMount(): void; + + componentDidUpdate(): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/Table.test.tsx b/types/react-virtualized/Table.test.tsx new file mode 100644 index 0000000000..8714634d1d --- /dev/null +++ b/types/react-virtualized/Table.test.tsx @@ -0,0 +1,196 @@ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { AutoSizer, Column, Table, SortDirection, SortIndicator } from 'react-virtualized' + +export default class TableExample extends PureComponent { + state; + context; + constructor(props, context) { + super(props, context) + + this.state = { + disableHeader: false, + headerHeight: 30, + height: 270, + hideIndexRow: false, + overscanRowCount: 10, + rowHeight: 40, + rowCount: 1000, + scrollToIndex: undefined, + sortBy: 'index', + sortDirection: SortDirection.ASC, + useDynamicRowHeight: false + } + + this._getRowHeight = this._getRowHeight.bind(this) + this._headerRenderer = this._headerRenderer.bind(this) + this._noRowsRenderer = this._noRowsRenderer.bind(this) + this._onRowCountChange = this._onRowCountChange.bind(this) + this._onScrollToRowChange = this._onScrollToRowChange.bind(this) + this._rowClassName = this._rowClassName.bind(this) + this._sort = this._sort.bind(this) + } + + render() { + const { + disableHeader, + headerHeight, + height, + hideIndexRow, + overscanRowCount, + rowHeight, + rowCount, + scrollToIndex, + sortBy, + sortDirection, + useDynamicRowHeight + } = this.state + + const { list } = this.context + const sortedList = this._isSortEnabled() + ? list + .sortBy(item => item[sortBy]) + .update(list => + sortDirection === SortDirection.DESC + ? list.reverse() + : list + ) + : list + + const rowGetter = ({ index }) => this._getDatum(sortedList, index) + + return ( +
+ + {({ width }) => ( + + {!hideIndexRow && + rowData.index + } + dataKey='index' + disableSort={!this._isSortEnabled()} + width={60} + /> + } + + cellData + } + flexGrow={1} + /> +
+ )} +
+
+ ) + } + + _getDatum(list, index) { + return list.get(index % list.size) + } + + _getRowHeight({ index }) { + const { list } = this.context + + return this._getDatum(list, index).size + } + + _headerRenderer({ + columnData, + dataKey, + disableSort, + label, + sortBy, + sortDirection + }) { + return ( +
+ Full Name + {sortBy === dataKey && + + } +
+ ) + } + + _isSortEnabled() { + const { list } = this.context + const { rowCount } = this.state + + return rowCount <= list.size + } + + _noRowsRenderer() { + return ( +
+ No rows +
+ ) + } + + _onRowCountChange(event) { + const rowCount = parseInt(event.target.value, 10) || 0 + + this.setState({ rowCount }) + } + + _onScrollToRowChange(event) { + const { rowCount } = this.state + let scrollToIndex = Math.min(rowCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToIndex)) { + scrollToIndex = undefined + } + + this.setState({ scrollToIndex }) + } + + _rowClassName({ index }) { + if (index < 0) { + return 'styles.headerRow' + } else { + return index % 2 === 0 ? 'styles.evenRow' : 'styles.oddRow' + } + } + + _sort({ sortBy, sortDirection }) { + this.setState({ sortBy, sortDirection }) + } + + _updateUseDynamicRowHeight(value) { + this.setState({ + useDynamicRowHeight: value + }) + } +} diff --git a/types/react-virtualized/WindowScroller.d.ts b/types/react-virtualized/WindowScroller.d.ts new file mode 100644 index 0000000000..093debdd78 --- /dev/null +++ b/types/react-virtualized/WindowScroller.d.ts @@ -0,0 +1,60 @@ +/** @flow */ +import { Validator, Requireable, PureComponent } from 'react' + +export type WindowScrollerChildProps = { + height: number, + isScrolling: boolean, + scrollTop: number +}; + +export type WindowScrollerProps = { + children?: (props: WindowScrollerChildProps) => React.ReactNode; + onResize?: (prams: { height: number }) => void; + onScroll?: (params: { scrollTop: number }) => void; + scrollElement?: HTMLElement; +} +export type WindowScrollerState = { + height: number, + isScrolling: boolean, + scrollTop: number +} + +export class WindowScroller extends PureComponent { + static propTypes: { + /** + * Function responsible for rendering children. + * This function should implement the following signature: + * ({ height, isScrolling, scrollTop }) => PropTypes.element + */ + children: Validator<(props: WindowScrollerChildProps) => React.ReactNode>, + + /** Callback to be invoked on-resize: ({ height }) */ + onResize: Validator<(params: { height: number }) => void>, + + /** Callback to be invoked on-scroll: ({ scrollTop }) */ + onScroll: Validator<(params: { scrollTop: number }) => void>, + + /** Element to attach scroll event listeners. Defaults to window. */ + scrollElement: HTMLElement + }; + + static defaultProps: { + onResize: () => {}, + onScroll: () => {} + }; + + constructor(props: WindowScrollerProps); + + // Can’t use defaultProps for scrollElement without breaking server-side rendering + readonly scrollElement: HTMLElement | Window; + + updatePosition(scrollElement?: HTMLElement): void; + + componentDidMount(): void; + + componentWillReceiveProps(nextProps: WindowScrollerProps): void; + + componentWillUnmount(): void; + + render(): JSX.Element; +} diff --git a/types/react-virtualized/WindowScroller.test.tsx b/types/react-virtualized/WindowScroller.test.tsx new file mode 100644 index 0000000000..c72a1b197a --- /dev/null +++ b/types/react-virtualized/WindowScroller.test.tsx @@ -0,0 +1,88 @@ +import * as React from 'react' +import { PropTypes, PureComponent } from 'react' +import { WindowScroller, List, AutoSizer } from 'react-virtualized' + +export default class WindowScrollerExample extends PureComponent { + state; + context; + _windowScroller: WindowScroller; + + constructor(props) { + super(props) + + this.state = { + showHeaderText: true + } + + this._hideHeader = this._hideHeader.bind(this) + this._rowRenderer = this._rowRenderer.bind(this) + this._onCheckboxChange = this._onCheckboxChange.bind(this) + this._setRef = this._setRef.bind(this) + } + + render() { + const { list, isScrollingCustomElement, customElement } = this.context + const { showHeaderText } = this.state + + return ( + +
+ + {({ height, isScrolling, scrollTop }) => ( + + {({ width }) => ( + this._rowRenderer({ index, isScrolling, isVisible, key, style })} + scrollTop={scrollTop} + width={width} + /> + )} + + )} + +
+ ) + } + + _hideHeader() { + const { showHeaderText } = this.state + + this.setState({ + showHeaderText: !showHeaderText + }, () => { + this._windowScroller.updatePosition() + }) + } + + _rowRenderer({ index, isScrolling, isVisible, key, style }) { + const { list } = this.context + const row = list.get(index) + + return ( +
+ {row.name} +
+ ) + } + + _setRef(windowScroller) { + this._windowScroller = windowScroller + } + + _onCheckboxChange(event) { + this.context.setScrollingCustomElement(event.target.checked) + } +} diff --git a/types/react-virtualized/genericTypes.d.ts b/types/react-virtualized/genericTypes.d.ts new file mode 100644 index 0000000000..7f4b6ff4b4 --- /dev/null +++ b/types/react-virtualized/genericTypes.d.ts @@ -0,0 +1,40 @@ +export type Index = { + index: number +}; + +export type PositionInfo = { + x: number, + y: number +}; + +export type ScrollPosition = { + scrollLeft: number, + scrollTop: number +}; + +export type SizeInfo = { + height: number, + width: number +}; + +export type SizeAndPositionInfo = SizeInfo & PositionInfo; + +export type Map = { [key: string]: T }; + +export type Alignment = 'auto' | 'end' | 'start' | 'center'; + +export type IndexRange = { + startIndex: number, + stopIndex: number +} + +export type OverscanIndexRange = { + overscanStartIndex: number, + overscanStopIndex: number, +} + +export type ScrollEventData = { + clientHeight: number, + scrollHeight: number, + scrollTop: number +} \ No newline at end of file diff --git a/types/react-virtualized/index.d.ts b/types/react-virtualized/index.d.ts index f89183c90f..31a6ee29c8 100644 --- a/types/react-virtualized/index.d.ts +++ b/types/react-virtualized/index.d.ts @@ -1,545 +1,138 @@ -// Type definitions for react-virtualized 9.2.1 +// Type definitions for react-virtualized 9.4 // Project: https://github.com/bvaughn/react-virtualized // Definitions by: Kalle Ott // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.1 -import * as React from "react"; +export { + ArrowKeyStepper, + ArrowKeyStepperProps, + ChildProps as ArrowKeyStepperChildProps +} from './ArrowKeyStepper' +export { + AutoSizer, + AutoSizerProps, + Dimensions +} from './AutoSizer' +export { + CellMeasurer, + CellMeasurerCache, + CellMeasurerCacheParams, + CellMeasurerProps, + KeyMapper +} from './CellMeasurer' +export { + Collection, + CollectionCellGroupRenderer, + CollectionCellGroupRendererParams, + CollectionCellRenderer, + CollectionCellRendererParams, + CollectionCellSizeAndPosition, + CollectionCellSizeAndPositionGetter, + CollectionProps +} from './Collection' +export { + ColumnSizer, + ColumnSizerProps, + SizedColumnProps +} from './ColumnSizer' +export { + defaultCellRangeRenderer, + Grid, + CellSizeAndPositionManager, + ConfigureParams, + ContainerSizeAndOffset, + GetVisibleCellRangeParams, + GridCellProps, + GridCellRangeProps, + GridCellRangeRenderer, + GridCellRenderer, + GridProps, + GridState, + OverscanIndices, + OverscanIndicesGetterParams, + ScrollDirection, + ScrollParams, + SectionRenderedParams, + SizeAndPositionData, + VisibleCellRange +} from './Grid' +export { + InfiniteLoader, + InfiniteLoaderChildProps, + InfiniteLoaderProps +} from './InfiniteLoader' +export { + List, + ListProps, + ListRowProps, + ListRowRenderer +} from './List' +export { + createCellPositioner as createMasonryCellPositioner, + Masonry, + CellRenderer, + MasonryCellProps, + MasonryProps, + MasonryState, + OnCellsRenderedCallback, + OnScrollCallback, + Position, + Positioner +} from './Masonry' +export { + MultiGrid, + MultiGridProps, + MultiGridState +} from './MultiGrid' +export { + ScrollSync, + OnScrollParams, + ScrollSyncChildProps, + ScrollSyncProps, + ScrollSyncState +} from './ScrollSync' +export { + defaultTableCellDataGetter, + defaultTableCellRenderer, + defaultTableHeaderRenderer, + defaultTableHeaderRowRenderer, + defaultTableRowRenderer, + Table, + Column, + SortDirection, + SortIndicator, + ColumnProps, + HeaderMouseEventHandlerParams, + RowMouseEventHandlerParams, + SortDirectionType, + TableCellDataGetter, + TableCellDataGetterParams, + TableCellProps, + TableCellRenderer, + TableHeaderProps, + TableHeaderRenderer, + TableHeaderRowProps, + TableHeaderRowRenderer, + TableProps, + TableRowProps, + TableRowRenderer +} from './Table' +export { + WindowScroller, + WindowScrollerChildProps, + WindowScrollerProps, + WindowScrollerState +} from './WindowScroller' -export interface ArrowKeyStepperProps { - children?: React.StatelessComponent<{ - onSectionRendered: Function, - scrollToColumn: number, - scrollToRow: number - }>; - className?: string; - columnCount: number; - rowCount: number; -} -export class ArrowKeyStepper extends React.PureComponent { } - -export interface AutoSizerProps { - disableHeight?: boolean; - disableWidth?: boolean; - onResize?: (info: { height: number, width: number }) => any; -} -export class AutoSizer extends React.PureComponent { } - -export interface CellMeasurerProps { - cache?: CellMeasurerCache; - children?: React.StatelessComponent<{ - getColumnWidth: () => number, - getRowHeight: () => number, - resetMeasurements: () => any, - resetMeasurementsForColumn: (index: number) => any, - resetMeasurementsForRow: (index: number) => any, - }>; - columnIndex: number; - parent?: React.ReactType; - rowIndex: number; - style?: React.CSSProperties; -} -export class CellMeasurer extends React.PureComponent { } - -export type KeyMapper = ( - rowIndex: number, - columnIndex: number -) => any; -export type Map = { [key: string]: T }; -export type Cache = Map; -export type IndexParam = { - index: number -}; - -export type CellMeasurerCacheParams = { - defaultHeight?: number, - defaultWidth?: number, - fixedHeight?: boolean, - fixedWidth?: boolean, - minHeight?: number, - minWidth?: number, - keyMapper?: KeyMapper -} -export class CellMeasurerCache { - constructor(params: CellMeasurerCacheParams); - clear( - rowIndex: number, - columnIndex: number - ): void; - clearAll(): void; - columnWidth: (params: IndexParam) => number | undefined; - hasFixedHeight(): boolean; - hasFixedWidth(): boolean; - getHeight( - rowIndex: number, - columnIndex: number - ): number | undefined; - getWidth( - rowIndex: number, - columnIndex: number - ): number | undefined; - has( - rowIndex: number, - columnIndex: number - ): boolean; - rowHeight: (params: IndexParam) => number | undefined; - set( - rowIndex: number, - columnIndex: number, - width: number, - height: number - ): void; -} - -export type CollectionCellSizeAndPosition = { height: number, width: number, x: number, y: number }; -export type CollectionCellSizeAndPositionGetter = (params: IndexParam) => CollectionCellSizeAndPosition; - -export type CollectionCellGroupRendererParams = { - cellSizeAndPositionGetter: CollectionCellSizeAndPositionGetter, - indices: number[], - cellRenderer: CollectionCellRenderer -} -export type CollectionCellGroupRenderer = (params: CollectionCellGroupRendererParams) => React.ReactNode[]; -export type CollectionCellRendererParams = { - index: number, - key: string, - style?: React.CSSProperties -} -export type CollectionCellRenderer = (params: CollectionCellRendererParams) => React.ReactNode; -export type CollectionProps = { - 'aria-label'?: string; - cellCount: number; - cellGroupRenderer?: CollectionCellGroupRenderer, - cellRenderer: CollectionCellRenderer, - cellSizeAndPositionGetter: CollectionCellSizeAndPositionGetter, - sectionSize?: number; -}; -export class Collection extends React.PureComponent { } - -export interface ColumnSizerProps { - children?: React.StatelessComponent<{ adjustedWidth: number, getColumnWidth: () => number, registerChild: any }>; - columnMaxWidth?: number; - columnMinWidth?: number; - columnCount?: number; - width: number; -} -export class ColumnSizer extends React.PureComponent { } - -export type CellDataGetterParams = { - columnData?: any, - dataKey: string, - rowData: any -}; -export type CellRendererParams = { - cellData?: any, - columnData?: any, - dataKey: string, - rowData: any, - rowIndex: number -}; -export type HeaderRendererParams = { - columnData?: any, - dataKey: string, - disableSort?: boolean, - label?: string, - sortBy?: string, - sortDirection?: SortDirectionType -}; -export type HeaderRowRendererParams = { - className: string, - columns: React.ReactNode[], - style: React.CSSProperties, - scrollbarWidth: number, - height: number, - width: number -}; -export type RowRendererParams = { - className: string, - columns: Array, - index: number, - isScrolling: boolean, - onRowClick?: Function, - onRowDoubleClick?: Function, - onRowMouseOver?: Function, - onRowMouseOut?: Function, - rowData: any, - style: any -}; - -export type TableCellDataGetter = (params: CellDataGetterParams) => any; -export type TableCellRenderer = (params: CellRendererParams) => React.ReactNode; -export type TableHeaderRenderer = (params: HeaderRendererParams) => React.ReactNode; -export type TableHeaderRowRenderer = (params: HeaderRowRendererParams) => React.ReactNode; -export type TableRowRenderer = (params: RowRendererParams) => React.ReactNode; - -// https://github.com/bvaughn/react-virtualized/blob/master/docs/Column.md -export interface ColumnProps { - cellDataGetter?: TableCellDataGetter; - cellRenderer?: TableCellRenderer; - className?: string; - columnData?: any; - dataKey: any; - disableSort?: boolean; - flexGrow?: number; - flexShrink?: number; - headerClassName?: string; - headerRenderer?: TableHeaderRenderer; - label?: string; - maxWidth?: number; - minWidth?: number; - style?: React.CSSProperties; - width: number; -} -export class Column extends React.Component { } - -export type RowClickHandlerParams = { - rowData: { - columnData: Object, - id: string, - index: number - } -} - -// ref: https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md -export interface TableProps { - deferredMeasurementCache?: CellMeasurerCache; - autoHeight?: boolean; - children?: React.ReactChildren; - className?: string; - disableHeader?: boolean; - estimatedRowSize?: number; - gridClassName?: string; - gridStyle?: any; - headerClassName?: string; - headerHeight: number; - headerStyle?: any; - height?: number; - id?: string; - noRowsRender?: () => void; - onHeaderClick?: (dataKey: string, columnData: any) => void; - onRowClick?: (info: RowClickHandlerParams) => void; - onRowDoubleClick?: (info: RowClickHandlerParams) => void; - onRowMouseOut?: (info: RowClickHandlerParams) => void; - onRowMouseOver?: (info: RowClickHandlerParams) => void; - onRowsRendered?: (info: RowClickHandlerParams) => void; - overscanRowCount?: number; - onScroll?: (info: { clientHeight: number, scrollHeight: number, scrollTop: number }) => void; - rowClassName?: string | ((info: IndexParam) => string); - rowCount: number; - rowGetter?: (info: IndexParam) => any; - rowHeight: number | ((info: IndexParam) => number); - rowRenderer?: TableRowRenderer; - headerRowRenderer?: TableHeaderRowRenderer; - rowStyle?: React.CSSProperties | ((info: IndexParam) => React.CSSProperties); - scrollToAlignment?: string; - scrollToIndex?: number; - scrollTop?: number; - sort?: (info: { sortBy: string, sortDirection: SortDirectionType }) => void; - sortBy?: string; - sortDirection?: SortDirectionType; - style?: React.CSSProperties; - tabIndex?: number; - width?: number; -} -export class Table extends React.PureComponent { - forceUpdateGrid(): void; - /** See Grid#measureAllCells */ - measureAllRows(): void; - /** See Grid#recomputeGridSize */ - recomputeRowHeights(index?: number): void; - /** See Grid#scrollToCell */ - scrollToRow(index?: number): void; - Grid: Grid; -} - -export const defaultTableCellDataGetter: TableCellDataGetter; -export const defaultTableCellRenderer: TableCellRenderer; -export const defaultTableHeaderRenderer: () => React.ReactElement[]; -export const defaultTableHeaderRowRenderer: TableHeaderRowRenderer; -export const defaultTableRowRenderer: TableRowRenderer; - -interface ISortDirection { - /** - * Sort items in ascending order. - * This means arranging from the lowest value to the highest (e.g. a-z, 0-9). - */ - ASC: 'ASC', - - /** - * Sort items in descending order. - * This means arranging from the highest value to the lowest (e.g. z-a, 9-0). - */ - DESC: 'DESC' -} - -export const SortDirection: ISortDirection - -export type SortDirectionType = 'ASC' | 'DESC' - -export const SortIndicator: React.StatelessComponent<{ sortDirection: SortDirectionType }> - - -export type DefaultCellRangeRendererParams = { - cellCache: Object, - cellRenderer: Function, - columnSizeAndPositionManager: Object, - columnStartIndex: number, - columnStopIndex: number, - horizontalOffsetAdjustment: number, - isScrolling: boolean, - rowSizeAndPositionManager: Object, - rowStartIndex: number, - rowStopIndex: number, - scrollLeft: number, - scrollTop: number, - styleCache: Object, - verticalOffsetAdjustment: number, - visibleColumnIndices: Object, - visibleRowIndices: Object -}; -export function defaultCellRangeRenderer(params: DefaultCellRangeRendererParams): React.ReactElement; - - -export type GridCellRendererParams = { - columnIndex: number; - isScrolling: boolean; - isVisible: boolean; - key: string; - parent: Grid | List | Table; - rowIndex: number; - style: React.CSSProperties; -}; -export type GridCellRenderer = (params: GridCellRendererParams) => React.ReactNode; - -export type ConfigureParams = { - cellCount: number, - estimatedCellSize: number -}; -export type ContainerSizeAndOffset = { - containerSize: number, - offset: number -}; -export type SizeAndPositionData = { - offset: number, - size: number -}; -export type GetVisibleCellRangeParams = { - containerSize: number, - offset: number -}; -export type VisibleCellRange = { - start: number; - stop: number; -} - -export type CellSizeAndPositionManager = { - areOffsetsAdjusted(): boolean; - configure({ - cellCount, - estimatedCellSize - }: ConfigureParams): void; - getCellCount(): number; - getEstimatedCellSize(): number; - getLastMeasuredIndex(): number; - getOffsetAdjustment({ - containerSize, - offset // safe - }: ContainerSizeAndOffset): number; - /** - * This method returns the size and position for the cell at the specified index. - * It just-in-time calculates (or used cached values) for cells leading up to the index. - */ - getSizeAndPositionOfCell(index: number): SizeAndPositionData; - getSizeAndPositionOfLastMeasuredCell(): SizeAndPositionData; - /** - * Total size of all cells being measured. - * This value will be completedly estimated initially. - * As cells as measured the estimate will be updated. - */ - getTotalSize(): number; - /** - * Determines a new offset that ensures a certain cell is visible, given the current offset. - * If the cell is already visible then the current offset will be returned. - * If the current offset is too great or small, it will be adjusted just enough to ensure the specified index is visible. - * - * @param align Desired alignment within container; one of "auto" (default), "start", or "end" - * @param containerSize Size (width or height) of the container viewport - * @param currentOffset Container's current (x or y) offset - * @param totalSize Total size (width or height) of all cells - * @return Offset to use to ensure the specified cell is visible - */ - getUpdatedOffsetForIndex(params: { - align: string, - containerSize: number, - currentOffset: number, - targetIndex: number - }): number; - getVisibleCellRange(params: GetVisibleCellRangeParams): VisibleCellRange; - /** - * Clear all cached values for cells after the specified index. - * This method should be called for any cell that has changed its size. - * It will not immediately perform any calculations; they'll be performed the next time getSizeAndPositionOfCell() is called. - */ - resetCell(index: number): void -} - -export type GridCellRangeRendererParams = { - cellCache: Map, - cellRenderer: GridCellRenderer, - columnSizeAndPositionManager: CellSizeAndPositionManager, - columnStartIndex: number, - columnStopIndex: number, - isScrolling: boolean, - rowSizeAndPositionManager: CellSizeAndPositionManager, - rowStartIndex: number, - rowStopIndex: number, - scrollLeft: number, - scrollTop: number -} -export type GridCellRangeRenderer = (params: GridCellRangeRendererParams) => React.ReactNode[]; -// TODO add proper typing -export type GridProps = { - 'aria-label'?: string; - autoContainerWidth?: boolean; - autoHeight?: boolean; - cellRenderer: GridCellRenderer; - cellRangeRenderer?: GridCellRangeRenderer; - className?: string; - columnCount: number; - columnWidth: number | ((params: IndexParam) => number); - containerStyle?: React.CSSProperties; - deferredMeasurementCache?: CellMeasurerCache; - estimatedColumnSize?: number; - estimatedRowSize?: number; - getScrollbarSize?: () => number; - height: number; - id?: string; - noContentRenderer?: () => React.ReactNode; - onScroll?: (params: { clientHeight: number, clientWidth: number, scrollHeight: number, scrollLeft: number, scrollTop: number, scrollWidth: number }) => any; - onSectionRendered?: (params: { columnStartIndex: number, columnStopIndex: number, rowStartIndex: number, rowStopIndex: number }) => any; - overscanColumnCount?: number; - overscanIndicesGetter?: (params: { - cellCount: number, - overscanCellsCount: number, - scrollDirection: number, - startIndex: number, - stopIndex: number - }) => { overscanStartIndex: number, overscanStopIndex: number }; - overscanRowCount?: number; - rowHeight: number | ((params: IndexParam) => number); - rowCount: number; - scrollingResetTimeInterval?: number; - scrollLeft?: number; - scrollToAlignment?: 'auto' | 'end' | 'start' | 'center'; - scrollToColumn?: number; - scrollTop?: number; - scrollToRow?: number; - style?: React.CSSProperties; - tabIndex?: number; - width: number; -}; -export class Grid extends React.PureComponent { - /** - * Invalidate Grid size and recompute visible cells. - * This is a deferred wrapper for recomputeGridSize(). - * It sets a flag to be evaluated on cDM/cDU to avoid unnecessary renders. - * This method is intended for advanced use-cases like CellMeasurer. - */ - invalidateCellSizeAfterRender(params: { - columnIndex: number, - rowIndex: number - }): void; - /** - * Pre-measure all columns and rows in a Grid. - * Typically cells are only measured as needed and estimated sizes are used for cells that have not yet been measured. - * This method ensures that the next call to getTotalSize() returns an exact size (as opposed to just an estimated one). - */ - measureAllCells(): void; - /** - * Forced recompute of row heights and column widths. - * This function should be called if dynamic column or row sizes have changed but nothing else has. - * Since Grid only receives :columnCount and :rowCount it has no way of detecting when the underlying data changes. - */ - recomputeGridSize(params?: { - columnIndex?: number, - rowIndex?: number - }): void; - /** - * Ensure column and row are visible. - */ - scrollToCell(params: { - columnIndex: number, - rowIndex: number - }): void; -} - -export type InfiniteLoaderProps = { - children?: React.StatelessComponent<{ - onRowsRendered: (params: { startIndex: number, stopIndex: number }) => void, - registerChild: (registeredChild: any) => void - }>; - isRowLoaded: (params: IndexParam) => boolean; - loadMoreRows: (params: { startIndex: number, stopIndex: number }) => Promise; - minimumBatchSize?: number; - rowCount?: number; - threshold?: number; -}; -export class InfiniteLoader extends React.PureComponent { } -export type ListRowRenderer = (params: GridCellRendererParams & { index: number, style: React.CSSProperties }) => React.ReactNode; -export interface ListProps { - className?: string; - autoHeight?: boolean; - estimatedRowSize?: number; - height: number; - noRowsRenderer?: Function; - onRowsRendered?: (info: { overscanStartIndex: number, overscanStopIndex: number, startIndex: number, stopIndex: number }) => void; - onScroll?: (info: { clientHeight: number, scrollHeight: number, scrollTop: number }) => void; - overscanRowCount?: number; - rowHeight: number | ((info: IndexParam) => number); - rowRenderer: ListRowRenderer; - rowCount: number; - scrollToAlignment?: string; - scrollToIndex?: number; - scrollTop?: number; - style?: React.CSSProperties; - tabIndex?: number; - width: number; -} -export class List extends React.PureComponent { } - -export interface MultiGridProps { - fixedColumnCount: number; - fixedRowCount: number; - style: React.CSSProperties; - styleBottomLeftGrid: React.CSSProperties; - styleBottomRightGrid: React.CSSProperties; - styleTopLeftGrid: React.CSSProperties; - styleTopRightGrid: React.CSSProperties; -} -export class MultiGrid extends React.PureComponent { } - -export type ScrollSyncProps = { - children?: React.StatelessComponent<{ - clientHeight: number, - clientWidth: number, - onScroll: (params: { clientHeight: number, clientWidth: number, scrollHeight: number, scrollLeft: number, scrollTop: number, scrollWidth: number }) => void, - scrollHeight: number, - scrollLeft: number, - scrollTop: number, - scrollWidth: number - }>; -}; -export class ScrollSync extends React.PureComponent { } -export type WindowScrollerRenderCallBackParams = { - height: number, - isScrolling: boolean, - scrollTop: number -}; - -export type WindowScrollerProps = { - children?: React.StatelessComponent; - onResize?: (prams: { height: number }) => void; - onScroll?: (params: { scrollTop: number }) => void; - scrollElement?: HTMLElement; -} -export class WindowScroller extends React.PureComponent { } +export { + Alignment, + Index, + IndexRange, + Map, + PositionInfo, + ScrollEventData, + ScrollPosition, + SizeAndPositionInfo, + SizeInfo +} from './genericTypes' \ No newline at end of file diff --git a/types/react-virtualized/react-virtualized-tests.tsx b/types/react-virtualized/react-virtualized-tests.tsx deleted file mode 100644 index aa1dc087a9..0000000000 --- a/types/react-virtualized/react-virtualized-tests.tsx +++ /dev/null @@ -1,532 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -import { - Collection, - SortDirection, - Grid, - ArrowKeyStepper, - AutoSizer, - CellMeasurer, - ColumnSizer, - InfiniteLoader, - ScrollSync, - WindowScroller, - WindowScrollerRenderCallBackParams, - List, - Column, - Table, -} from "react-virtualized"; - -/* - * Collection - */ - -function CollectionTest() { - const list = [ - { name: "Brian Vaughn", x: 13, y: 34, width: 123, size: 234, height: 123 } - ]; - - // Render your grid - ReactDOM.render( - list[index].name} - cellSizeAndPositionGetter={({ index }) => { - const datum = list[index]; - return { - height: datum.height, - width: datum.width, - x: datum.x, - y: datum.y - }; - }} - />, - document.getElementById("example") - ); -} - -function GridTest() { - // Grid data as an array of arrays - const list = [ - ['Brian Vaughn', 'Software Engineer', 'San Jose', 'CA', 95125 /* ... */] - // And so on... - ]; - - // Render your grid - ReactDOM.render( - list[rowIndex][columnIndex]} - />, - document.getElementById('example') - ); -} - -function ListTest() { - // List data - const list = [ - { name: 'Brian Vaughn', occupation: 'Software Engineer', location: 'San Jose, CA, 95125' /* ... */ } - // And so on... - ]; - - // Render your List - ReactDOM.render( - list[index]} - />, - document.getElementById('example') - ); -} - -function TableTest() { - const list = [ - { name: 'Brian Vaughn', description: 'Software engineer' } - // And so on... - ]; - ReactDOM.render( - list[index]} - > - - -
, - document.getElementById('example') - ); -} - -function ArrowKeyStepperTest() { - const columnCount = 12; - const rowCount = 3; - - ReactDOM.render( - - {({ onSectionRendered, scrollToColumn, scrollToRow }) => ( - null} - columnCount={columnCount} - onSectionRendered={onSectionRendered} - rowCount={rowCount} - scrollToColumn={scrollToColumn} - scrollToRow={scrollToRow} - /> - )} - , - document.getElementById('example') - ); -} - -function AutoSizerTest() { - // List data as an array of strings - const list = [ - 'Brian Vaughn' - // And so on... - ]; - const _rowRenderer = ({ index, key, style }) => { - - const row = list[index]; - - return ( -
- {row} -
- ) - } - - // Render your list - ReactDOM.render( - - {({ width, height }) => ( - { - const row = list[index]; - - return ( -
- {row} -
- ) - }} - width={width} - /> - )} -
, - document.getElementById('example') - ); -} - -function CellMeasurerTest() { - const columnCount = 12; - const rowCount = 3; - const cellRenderer = ({ columnIndex, rowIndex }) => `${rowIndex}, ${columnIndex}`; - const fixedRowHeight = 42; - const height = 12; - const width = 12; - - ReactDOM.render( - - {({ getColumnWidth }) => ( - - )} - , - document.getElementById('example') - ); -} - -function ColumnSizerTest() { - ReactDOM.render( - - {({ adjustedWidth, getColumnWidth, registerChild }) => ( - "test"} - rowHeight={50} - rowCount={12} - width={adjustedWidth} - /> - )} - , - document.getElementById('example') - ); -} - -function InfiniteLoaderTest() { - const list: string[] = []; - - function isRowLoaded({ index }) { - return !!list[index]; - } - - function loadMoreRows({ startIndex, stopIndex }: { startIndex: number, stopIndex: number }) { - return new Promise(resolve => resolve(list.push('test'))); - } - - function rowRenderer({ index, key, style }) { - const content = list[index]; - - return ( -
- {content} -
- ) - } - - - // Render your list - ReactDOM.render( - - {({ onRowsRendered, registerChild }) => ( - - {({ width }) => ( - - )} - - )} - , - document.getElementById('example') - ); -} - -function ScrollSyncTest() { - function hexToRgb(hex) { - 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 - } - - const LEFT_COLOR_FROM = hexToRgb('#471061') - const LEFT_COLOR_TO = hexToRgb('#BC3959') - const TOP_COLOR_FROM = hexToRgb('#000000') - const TOP_COLOR_TO = hexToRgb('#333333') - const columnWidth = 20; - const rowHeight = 10; - const overscanColumnCount = 10; - const overscanRowCount = 10; - const height = 10; - const rowCount = 100; - const columnCount = 100; - - - function mixColors(color1, color2, amount) { - 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 } - }; - - function renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) { - return ( -
- {`C${columnIndex}`} -
- ) - }; - function renderLeftSideCell({ columnIndex, key, rowIndex, style }) { - const rowClass = rowIndex % 2 === 0 - ? columnIndex % 2 === 0 ? 'styles.evenRow' : 'styles.oddRow' - : columnIndex % 2 !== 0 ? 'styles.evenRow' : 'styles.oddRow' - const classNames = [rowClass, 'styles.cell'].join(' ') - - return ( -
- {`R${rowIndex}, C${columnIndex}`} -
- ) - }; - - function renderHeaderCell({ columnIndex, key, rowIndex, style }) { - if (columnIndex < 1) { - return - } - - return renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) - }; - - function renderBodyCell({ columnIndex, key, rowIndex, style }) { - if (columnIndex < 1) { - return - } - - return renderLeftSideCell({ columnIndex, key, rowIndex, style }) - } - - return ( - - {({ 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 ( -
-
- -
-
- -
-
- - {({ width }) => ( -
-
- -
-
- -
-
- )} -
-
-
- ) - }} -
- ); -} - -function WindowScrollerTest() { - const onScroll = function ({scrollTop}: { scrollTop: number }) { }; - const onResize = function ({height}: { height: number }) { }; - const list = [ - { name: 'Brian Vaughn', description: 'Software engineer' } - // And so on... - ]; - ReactDOM.render( - - {({ height, isScrolling, scrollTop }) => ( - - {({ width }) => ( - list[index].name} - scrollTop={scrollTop} - width={width} - /> - )} - - )} - , - document.getElementById('example') - ); - // test that onScroll & onResize are optional - ReactDOM.render( - , - document.getElementById('example') - ); -} diff --git a/types/react-virtualized/tsconfig.json b/types/react-virtualized/tsconfig.json index ac62cf83d8..21a0e43a0d 100644 --- a/types/react-virtualized/tsconfig.json +++ b/types/react-virtualized/tsconfig.json @@ -19,6 +19,32 @@ }, "files": [ "index.d.ts", - "react-virtualized-tests.tsx" + "ArrowKeyStepper.d.ts", + "ArrowKeyStepper.test.tsx", + "AutoSizer.d.ts", + "AutoSizer.test.tsx", + "CellMeasurer.d.ts", + "CellMeasurer.test.tsx", + "Collection.d.ts", + "Collection.test.tsx", + "ColumnSizer.d.ts", + "ColumnSizer.test.tsx", + "genericTypes.d.ts", + "Grid.d.ts", + "Grid.test.tsx", + "InfiniteLoader.d.ts", + "InfiniteLoader.test.tsx", + "List.d.ts", + "List.test.tsx", + "Masonry.d.ts", + "Masonry.test.tsx", + "MultiGrid.d.ts", + "MultiGrid.test.tsx", + "ScrollSync.d.ts", + "ScrollSync.test.tsx", + "Table.d.ts", + "Table.test.tsx", + "WindowScroller.d.ts", + "WindowScroller.test.tsx" ] } \ No newline at end of file From 62ad9abc10b38daae1940f0345b094882f4d5f6f Mon Sep 17 00:00:00 2001 From: Kalle Ott Date: Mon, 27 Mar 2017 21:32:02 +0200 Subject: [PATCH 2/6] fixed linting error --- types/react-virtualized/Collection.d.ts | 6 +++--- types/react-virtualized/tslint.json | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 types/react-virtualized/tslint.json diff --git a/types/react-virtualized/Collection.d.ts b/types/react-virtualized/Collection.d.ts index 7e11946eb1..52a69de286 100644 --- a/types/react-virtualized/Collection.d.ts +++ b/types/react-virtualized/Collection.d.ts @@ -31,11 +31,11 @@ export type CollectionProps = { sectionSize?: number; className?: string; height: number; - width:number; + width: number; horizontalOverscanSize?: number; noContentRenderer?: () => JSX.Element; - scrollToCell?: number; - verticalOverscanSize?:number; + scrollToCell?: number; + verticalOverscanSize?: number; }; /** diff --git a/types/react-virtualized/tslint.json b/types/react-virtualized/tslint.json new file mode 100644 index 0000000000..2221e40e4a --- /dev/null +++ b/types/react-virtualized/tslint.json @@ -0,0 +1 @@ +{ "extends": "../tslint.json" } \ No newline at end of file From 97fd2fc247ed9996d7faf87f0ca3cd3e67eef208 Mon Sep 17 00:00:00 2001 From: Kalle Ott Date: Mon, 27 Mar 2017 21:54:40 +0200 Subject: [PATCH 3/6] replaced mulstiple testfiles with on to obey definitely typed naming --- .../ArrowKeyStepper.test.tsx | 71 - types/react-virtualized/AutoSizer.test.tsx | 47 - types/react-virtualized/CellMeasurer.test.tsx | 74 - types/react-virtualized/Collection.test.tsx | 160 -- types/react-virtualized/ColumnSizer.test.tsx | 113 -- types/react-virtualized/Grid.test.tsx | 207 -- .../react-virtualized/InfiniteLoader.test.tsx | 138 -- types/react-virtualized/List.test.tsx | 160 -- types/react-virtualized/Masonry.test.tsx | 200 -- types/react-virtualized/MultiGrid.test.tsx | 105 - types/react-virtualized/ScrollSync.test.tsx | 222 --- types/react-virtualized/Table.test.tsx | 196 -- .../react-virtualized/WindowScroller.test.tsx | 88 - .../react-virtualized-tests.tsx | 1753 +++++++++++++++++ types/react-virtualized/tsconfig.json | 14 +- 15 files changed, 1754 insertions(+), 1794 deletions(-) delete mode 100644 types/react-virtualized/ArrowKeyStepper.test.tsx delete mode 100644 types/react-virtualized/AutoSizer.test.tsx delete mode 100644 types/react-virtualized/CellMeasurer.test.tsx delete mode 100644 types/react-virtualized/Collection.test.tsx delete mode 100644 types/react-virtualized/ColumnSizer.test.tsx delete mode 100644 types/react-virtualized/Grid.test.tsx delete mode 100644 types/react-virtualized/InfiniteLoader.test.tsx delete mode 100644 types/react-virtualized/List.test.tsx delete mode 100644 types/react-virtualized/Masonry.test.tsx delete mode 100644 types/react-virtualized/MultiGrid.test.tsx delete mode 100644 types/react-virtualized/ScrollSync.test.tsx delete mode 100644 types/react-virtualized/Table.test.tsx delete mode 100644 types/react-virtualized/WindowScroller.test.tsx create mode 100644 types/react-virtualized/react-virtualized-tests.tsx diff --git a/types/react-virtualized/ArrowKeyStepper.test.tsx b/types/react-virtualized/ArrowKeyStepper.test.tsx deleted file mode 100644 index 8204aafdd6..0000000000 --- a/types/react-virtualized/ArrowKeyStepper.test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/** @flow */ -import * as React from 'react'; -import { PureComponent } from 'react' -import { ArrowKeyStepper, AutoSizer, Grid } from 'react-virtualized' - -export default class ArrowKeyStepperExample extends PureComponent { - constructor(props) { - super(props) - - this._getColumnWidth = this._getColumnWidth.bind(this) - this._getRowHeight = this._getRowHeight.bind(this) - this._cellRenderer = this._cellRenderer.bind(this) - } - - render() { - const { mode } = this.state - - return ( - - - {({ onSectionRendered, scrollToColumn, scrollToRow }) => ( -
- - - {({ width }) => ( - this._cellRenderer({ columnIndex, key, rowIndex, scrollToColumn, scrollToRow, style })} - rowHeight={this._getRowHeight} - rowCount={100} - scrollToColumn={scrollToColumn} - scrollToRow={scrollToRow} - width={width} - /> - )} - -
- )} -
- ) - } - - _getColumnWidth({ index }) { - return (1 + (index % 3)) * 60 - } - - _getRowHeight({ index }) { - return (1 + (index % 3)) * 30 - } - - _cellRenderer({ columnIndex, key, rowIndex, scrollToColumn, scrollToRow, style }) { - - return ( -
- {`r:${rowIndex}, c:${columnIndex}`} -
- ) - } -} diff --git a/types/react-virtualized/AutoSizer.test.tsx b/types/react-virtualized/AutoSizer.test.tsx deleted file mode 100644 index 670d77b52b..0000000000 --- a/types/react-virtualized/AutoSizer.test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/** @flow */ -import * as React from 'react'; -import { PureComponent } from 'react' -import { AutoSizer, List } from 'react-virtualized' - -export default class AutoSizerExample extends PureComponent { - constructor(props) { - super(props) - - this._rowRenderer = this._rowRenderer.bind(this) - } - - render() { - const { list } = this.context - const { hideDescription } = this.state - - return ( - - {({ width, height }) => ( - - )} - - ) - } - - _rowRenderer({ index, key, style }) { - const { list } = this.context - const row = list.get(index) - - return ( -
- {row.name} -
- ) - } -} diff --git a/types/react-virtualized/CellMeasurer.test.tsx b/types/react-virtualized/CellMeasurer.test.tsx deleted file mode 100644 index 5b510704c0..0000000000 --- a/types/react-virtualized/CellMeasurer.test.tsx +++ /dev/null @@ -1,74 +0,0 @@ -/** @flow */ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { CellMeasurer, CellMeasurerCache, List } from 'react-virtualized' - -export default class DynamicHeightList extends PureComponent { - - _cache: CellMeasurerCache - - constructor(props, context) { - super(props, context) - - this._cache = new CellMeasurerCache({ - fixedWidth: true, - minHeight: 50 - }) - - this._rowRenderer = this._rowRenderer.bind(this) - } - - render() { - const { width } = this.props - - return ( - - ) - } - - _rowRenderer({ index, isScrolling, key, parent, style }) { - 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 ( - - {({ measure }) => ( -
- -
- )} -
- ) - } -} diff --git a/types/react-virtualized/Collection.test.tsx b/types/react-virtualized/Collection.test.tsx deleted file mode 100644 index 8a7860b3c7..0000000000 --- a/types/react-virtualized/Collection.test.tsx +++ /dev/null @@ -1,160 +0,0 @@ -/** @flow */ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { AutoSizer, 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 default class CollectionExample extends PureComponent { - - _columnYMap: any; - - constructor(props, context) { - 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 = [] - - this._cellRenderer = this._cellRenderer.bind(this) - this._cellSizeAndPositionGetter = this._cellSizeAndPositionGetter.bind(this) - this._noContentRenderer = this._noContentRenderer.bind(this) - this._onCellCountChange = this._onCellCountChange.bind(this) - this._onHeightChange = this._onHeightChange.bind(this) - this._onHorizontalOverscanSizeChange = this._onHorizontalOverscanSizeChange.bind(this) - this._onScrollToCellChange = this._onScrollToCellChange.bind(this) - this._onVerticalOverscanSizeChange = this._onVerticalOverscanSizeChange.bind(this) - } - - render() { - const { cellCount, height, horizontalOverscanSize, scrollToCell, showScrollingPlaceholder, verticalOverscanSize } = this.state - - return ( - - {({ width }) => ( - - )} - - ) - } - - _cellRenderer({ index, isScrolling, key, style }) { - const { list } = this.context - const { showScrollingPlaceholder } = this.state - - const datum = list.get(index % list.size) - - // Customize style - style.backgroundColor = datum.color - - return ( -
- {showScrollingPlaceholder && isScrolling ? '...' : index} -
- ) - } - - _cellSizeAndPositionGetter({ 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) { - return Math.round(Math.sqrt(cellCount)) - } - - _onHorizontalOverscanSizeChange(event) { - const horizontalOverscanSize = parseInt(event.target.value, 10) || 0 - - this.setState({ horizontalOverscanSize }) - } - - _noContentRenderer() { - return ( -
- No cells -
- ) - } - - _onCellCountChange(event) { - const cellCount = parseInt(event.target.value, 10) || 0 - - this._columnYMap = [] - - this.setState({ - cellCount, - columnCount: this._getColumnCount(cellCount) - }) - } - - _onHeightChange(event) { - const height = parseInt(event.target.value, 10) || 0 - - this.setState({ height }) - } - - _onScrollToCellChange(event) { - const { cellCount } = this.state - - let scrollToCell = Math.min(cellCount - 1, parseInt(event.target.value, 10)) - - if (isNaN(scrollToCell)) { - scrollToCell = undefined - } - - this.setState({ scrollToCell }) - } - - _onVerticalOverscanSizeChange(event) { - const verticalOverscanSize = parseInt(event.target.value, 10) || 0 - - this.setState({ verticalOverscanSize }) - } -} diff --git a/types/react-virtualized/ColumnSizer.test.tsx b/types/react-virtualized/ColumnSizer.test.tsx deleted file mode 100644 index 97de9fff45..0000000000 --- a/types/react-virtualized/ColumnSizer.test.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import * as React from 'react' -import { PureComponent } from 'react' -import { AutoSizer, ColumnSizer, Grid } from 'react-virtualized' - -export default class ColumnSizerExample extends PureComponent { - constructor(props) { - super(props) - - this._noColumnMaxWidthChange = this._noColumnMaxWidthChange.bind(this) - this._noColumnMinWidthChange = this._noColumnMinWidthChange.bind(this) - this._onColumnCountChange = this._onColumnCountChange.bind(this) - this._noContentRenderer = this._noContentRenderer.bind(this) - this._cellRenderer = this._cellRenderer.bind(this) - } - - render() { - const { - columnMaxWidth, - columnMinWidth, - columnCount - } = this.state - - return ( -
- - {({ width }) => ( - - {({ adjustedWidth, getColumnWidth, registerChild }) => ( -
- -
- )} -
- )} -
-
- ) - } - - _noColumnMaxWidthChange(event) { - let columnMaxWidth = parseInt(event.target.value, 10) - - if (isNaN(columnMaxWidth)) { - columnMaxWidth = undefined - } else { - columnMaxWidth = Math.min(1000, columnMaxWidth) - } - - this.setState({ columnMaxWidth }) - } - - _noColumnMinWidthChange(event) { - let columnMinWidth = parseInt(event.target.value, 10) - - if (isNaN(columnMinWidth)) { - columnMinWidth = undefined - } else { - columnMinWidth = Math.max(1, columnMinWidth) - } - - this.setState({ columnMinWidth }) - } - - _onColumnCountChange(event) { - this.setState({ columnCount: parseInt(event.target.value, 10) || 0 }) - } - - _noContentRenderer() { - return ( -
- No cells -
- ) - } - - _cellRenderer({ columnIndex, key, rowIndex, style }) { - const className = columnIndex === 0 - ? 'styles.firstCell' - : 'styles.cell' - - return ( -
- {`R:${rowIndex}, C:${columnIndex}`} -
- ) - } -} diff --git a/types/react-virtualized/Grid.test.tsx b/types/react-virtualized/Grid.test.tsx deleted file mode 100644 index 634fcdc137..0000000000 --- a/types/react-virtualized/Grid.test.tsx +++ /dev/null @@ -1,207 +0,0 @@ -/** @flow */ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { AutoSizer, Grid } from 'react-virtualized' - -export default class GridExample extends PureComponent { - - - constructor(props, context) { - super(props, context) - - this.state = { - columnCount: 1000, - height: 300, - overscanColumnCount: 0, - overscanRowCount: 10, - rowHeight: 40, - rowCount: 1000, - scrollToColumn: undefined, - scrollToRow: undefined, - useDynamicRowHeight: false - } - - this._cellRenderer = this._cellRenderer.bind(this) - this._getColumnWidth = this._getColumnWidth.bind(this) - this._getRowClassName = this._getRowClassName.bind(this) - this._getRowHeight = this._getRowHeight.bind(this) - this._noContentRenderer = this._noContentRenderer.bind(this) - this._onColumnCountChange = this._onColumnCountChange.bind(this) - this._onRowCountChange = this._onRowCountChange.bind(this) - this._onScrollToColumnChange = this._onScrollToColumnChange.bind(this) - this._onScrollToRowChange = this._onScrollToRowChange.bind(this) - this._renderBodyCell = this._renderBodyCell.bind(this) - this._renderLeftSideCell = this._renderLeftSideCell.bind(this) - } - - render() { - const { - columnCount, - height, - overscanColumnCount, - overscanRowCount, - rowHeight, - rowCount, - scrollToColumn, - scrollToRow, - useDynamicRowHeight - } = this.state - - return ( - - - {({ width }) => ( - - )} - - ) - } - - _cellRenderer({ columnIndex, key, rowIndex, style }) { - if (columnIndex === 0) { - return this._renderLeftSideCell({ key, rowIndex, style }) - } else { - return this._renderBodyCell({ columnIndex, key, rowIndex, style }) - } - } - - _getColumnWidth({ index }) { - switch (index) { - case 0: - return 50 - case 1: - return 100 - case 2: - return 300 - default: - return 80 - } - } - - _getDatum(index) { - const { list } = this.context - - return list.get(index % list.size) - } - - _getRowClassName(row) { - return row % 2 === 0 ? 'styles.evenRow' : 'styles.oddRow' - } - - _getRowHeight({ index }) { - return this._getDatum(index).size - } - - _noContentRenderer() { - return ( -
- No cells -
- ) - } - - _renderBodyCell({ columnIndex, key, rowIndex, style }) { - 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 ( -
- {content} -
- ) - } - - _renderLeftSideCell({ key, rowIndex, style }) { - 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 ( -
- {datum.name.charAt(0)} -
- ) - } - - _updateUseDynamicRowHeights(value) { - this.setState({ - useDynamicRowHeight: value - }) - } - - _onColumnCountChange(event) { - const columnCount = parseInt(event.target.value, 10) || 0 - - this.setState({ columnCount }) - } - - _onRowCountChange(event) { - const rowCount = parseInt(event.target.value, 10) || 0 - - this.setState({ rowCount }) - } - - _onScrollToColumnChange(event) { - const { columnCount } = this.state - let scrollToColumn = Math.min(columnCount - 1, parseInt(event.target.value, 10)) - - if (isNaN(scrollToColumn)) { - scrollToColumn = undefined - } - - this.setState({ scrollToColumn }) - } - - _onScrollToRowChange(event) { - const { rowCount } = this.state - let scrollToRow = Math.min(rowCount - 1, parseInt(event.target.value, 10)) - - if (isNaN(scrollToRow)) { - scrollToRow = undefined - } - - this.setState({ scrollToRow }) - } -} diff --git a/types/react-virtualized/InfiniteLoader.test.tsx b/types/react-virtualized/InfiniteLoader.test.tsx deleted file mode 100644 index 0509f46216..0000000000 --- a/types/react-virtualized/InfiniteLoader.test.tsx +++ /dev/null @@ -1,138 +0,0 @@ -/** @flow */ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { AutoSizer, InfiniteLoader, List } from 'react-virtualized' - -const STATUS_LOADING = 1 -const STATUS_LOADED = 2 - -export default class InfiniteLoaderExample extends PureComponent { - _timeoutIdMap: any; - - constructor(props) { - super(props) - - this._timeoutIdMap = {} - - this._clearData = this._clearData.bind(this) - this._isRowLoaded = this._isRowLoaded.bind(this) - this._loadMoreRows = this._loadMoreRows.bind(this) - this._rowRenderer = this._rowRenderer.bind(this) - } - - componentWillUnmount() { - Object.keys(this._timeoutIdMap).forEach(timeoutId => { - clearTimeout(timeoutId as any) - }) - } - - render() { - const { list } = this.context - const { loadedRowCount, loadingRowCount } = this.state - - return ( - - {({ onRowsRendered, registerChild }) => ( - - {({ width }) => ( - - )} - - )} - - ) - } - - _clearData() { - this.setState({ - loadedRowCount: 0, - loadedRowsMap: {}, - loadingRowCount: 0 - }) - } - - _isRowLoaded({ index }) { - const { loadedRowsMap } = this.state - return !!loadedRowsMap[index] // STATUS_LOADING or STATUS_LOADED - } - - _loadMoreRows({ startIndex, stopIndex }) { - const { loadedRowsMap, loadingRowCount } = this.state - const increment = stopIndex - startIndex + 1 - - for (var i = startIndex; i <= stopIndex; i++) { - loadedRowsMap[i] = STATUS_LOADING - } - - this.setState({ - loadingRowCount: loadingRowCount + increment - }) - - const timeoutId = setTimeout(() => { - const { loadedRowCount, loadingRowCount } = this.state - - delete this._timeoutIdMap[timeoutId] - - for (var 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._timeoutIdMap[timeoutId] = true - - let promiseResolver - - return new Promise(resolve => { - promiseResolver = resolve - }) - } - - _rowRenderer({ index, key, style }) { - 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 = ( -
- ) - } - - return ( -
- {content} -
- ) - } -} diff --git a/types/react-virtualized/List.test.tsx b/types/react-virtualized/List.test.tsx deleted file mode 100644 index 86763a95f8..0000000000 --- a/types/react-virtualized/List.test.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { AutoSizer, List } from 'react-virtualized' - -export default class ListExample extends PureComponent { - - constructor(props, context) { - super(props, context) - - this.state = { - listHeight: 300, - listRowHeight: 50, - overscanRowCount: 10, - rowCount: context.list.size, - scrollToIndex: undefined, - showScrollingPlaceholder: false, - useDynamicRowHeight: false - } - - this._getRowHeight = this._getRowHeight.bind(this) - this._noRowsRenderer = this._noRowsRenderer.bind(this) - this._onRowCountChange = this._onRowCountChange.bind(this) - this._onScrollToRowChange = this._onScrollToRowChange.bind(this) - this._rowRenderer = this._rowRenderer.bind(this) - } - - render() { - const { - listHeight, - listRowHeight, - overscanRowCount, - rowCount, - scrollToIndex, - showScrollingPlaceholder, - useDynamicRowHeight - } = this.state - - return ( - - {({ width }) => ( - - )} - - ) - } - - _getDatum(index) { - const { list } = this.context - - return list.get(index % list.size) - } - - _getRowHeight({ index }) { - return this._getDatum(index).size - } - - _noRowsRenderer() { - return ( -
- No rows -
- ) - } - - _onRowCountChange(event) { - const rowCount = parseInt(event.target.value, 10) || 0 - - this.setState({ rowCount }) - } - - _onScrollToRowChange(event) { - const { rowCount } = this.state - let scrollToIndex = Math.min(rowCount - 1, parseInt(event.target.value, 10)) - - if (isNaN(scrollToIndex)) { - scrollToIndex = undefined - } - - this.setState({ scrollToIndex }) - } - - _rowRenderer({ index, isScrolling, key, style }) { - const { - showScrollingPlaceholder, - useDynamicRowHeight - } = this.state - - if ( - showScrollingPlaceholder && - isScrolling - ) { - return ( -
- Scrolling... -
- ) - } - - const datum = this._getDatum(index) - - let additionalContent - - if (useDynamicRowHeight) { - switch (datum.size) { - case 75: - additionalContent =
It is medium-sized.
- break - case 100: - additionalContent =
It is large-sized.
It has a 3rd row.
- break - } - } - - return ( -
-
- {datum.name.charAt(0)} -
-
-
- {datum.name} -
-
- This is row {index} -
- {additionalContent} -
- {useDynamicRowHeight && - - {datum.size}px - - } -
- ) - } -} diff --git a/types/react-virtualized/Masonry.test.tsx b/types/react-virtualized/Masonry.test.tsx deleted file mode 100644 index 902e5498c5..0000000000 --- a/types/react-virtualized/Masonry.test.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { - CellMeasurer, - CellMeasurerCache, - AutoSizer, - WindowScroller, - createMasonryCellPositioner as createCellPositioner, - Positioner, - Masonry, - MasonryCellProps -} from 'react-virtualized' - -export default class GridExample extends PureComponent { - _columnCount: number; - _cache: CellMeasurerCache; - _columnHeights: any; - _width: number; - _height: number; - _scrollTop: number; - _cellPositioner?: Positioner; - _masonry: Masonry; - - constructor(props, context) { - 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 - - let child - - if (windowScrollerEnabled) { - child = ( - - {this._renderAutoSizer} - - ) - } else { - child = this._renderAutoSizer({ height }) - } - - return ( -
- {child} -
- ) - } - - _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 ( - -
-
- {datum.random} -
- - ) - } - - _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 }) { - 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 ( - - {this._renderMasonry} - - ) - } - - _renderMasonry({ width }) { - this._width = width - - this._calculateColumnCount() - this._initCellPositioner() - - const { height, windowScrollerEnabled } = this.state - - return ( - - ) - } - - _resetCellPositioner() { - const { - columnWidth, - gutterSize - } = this.state - - this._cellPositioner.reset({ - columnCount: this._columnCount, - columnWidth, - spacer: gutterSize - }) - } - - _setMasonryRef(ref) { - this._masonry = ref - } -} diff --git a/types/react-virtualized/MultiGrid.test.tsx b/types/react-virtualized/MultiGrid.test.tsx deleted file mode 100644 index f2f3af9397..0000000000 --- a/types/react-virtualized/MultiGrid.test.tsx +++ /dev/null @@ -1,105 +0,0 @@ -/** @flow */ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { AutoSizer, 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 default class MultiGridExample extends PureComponent { - state - _onFixedColumnCountChange - _onFixedRowCountChange - _onScrollToColumnChange - _onScrollToRowChange - - constructor(props, context) { - super(props, context) - - this.state = { - fixedColumnCount: 2, - fixedRowCount: 1, - scrollToColumn: 0, - scrollToRow: 0 - } - - this._cellRenderer = this._cellRenderer.bind(this) - this._onFixedColumnCountChange = this._createEventHandler('fixedColumnCount') - this._onFixedRowCountChange = this._createEventHandler('fixedRowCount') - this._onScrollToColumnChange = this._createEventHandler('scrollToColumn') - this._onScrollToRowChange = this._createEventHandler('scrollToRow') - } - - render() { - return ( - - {({ width }) => ( - - )} - - ) - } - - _cellRenderer({ columnIndex, key, rowIndex, style }) { - return ( -
- {columnIndex}, {rowIndex} -
- ) - } - - _createEventHandler(property) { - return (event) => { - const value = parseInt(event.target.value, 10) || 0 - - this.setState({ - [property]: value - }) - } - } - - _createLabeledInput(property, eventHandler) { - const value = this.state[property] - - return ( - `` - ) - } -} diff --git a/types/react-virtualized/ScrollSync.test.tsx b/types/react-virtualized/ScrollSync.test.tsx deleted file mode 100644 index 9919b72ab3..0000000000 --- a/types/react-virtualized/ScrollSync.test.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import * as React from 'react' -import { PureComponent } from 'react' -import { AutoSizer, Grid, 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 default class GridExample extends PureComponent { - state - constructor(props, context) { - super(props, context) - - this.state = { - columnWidth: 75, - columnCount: 50, - height: 300, - overscanColumnCount: 0, - overscanRowCount: 5, - rowHeight: 40, - rowCount: 100 - } - - this._renderBodyCell = this._renderBodyCell.bind(this) - this._renderHeaderCell = this._renderHeaderCell.bind(this) - this._renderLeftSideCell = this._renderLeftSideCell.bind(this) - } - - render() { - const { - columnCount, - columnWidth, - height, - overscanColumnCount, - overscanRowCount, - rowHeight, - rowCount - } = this.state - - return ( - - - {({ 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 ( -
-
- -
-
- -
-
- - {({ width }) => ( -
-
- -
-
- -
-
- )} -
-
-
- ) - }} -
- ) - } - - _renderBodyCell({ columnIndex, key, rowIndex, style }) { - if (columnIndex < 1) { - return - } - - return this._renderLeftSideCell({ columnIndex, key, rowIndex, style }) - } - - _renderHeaderCell({ columnIndex, key, rowIndex, style }) { - if (columnIndex < 1) { - return - } - - return this._renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) - } - - _renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) { - return ( -
- {`C${columnIndex}`} -
- ) - } - - _renderLeftSideCell({ columnIndex, key, rowIndex, style }) { - return ( -
- {`R${rowIndex}, C${columnIndex}`} -
- ) - } -} - -function hexToRgb(hex) { - 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, color2, amount) { - 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 } -} diff --git a/types/react-virtualized/Table.test.tsx b/types/react-virtualized/Table.test.tsx deleted file mode 100644 index 8714634d1d..0000000000 --- a/types/react-virtualized/Table.test.tsx +++ /dev/null @@ -1,196 +0,0 @@ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { AutoSizer, Column, Table, SortDirection, SortIndicator } from 'react-virtualized' - -export default class TableExample extends PureComponent { - state; - context; - constructor(props, context) { - super(props, context) - - this.state = { - disableHeader: false, - headerHeight: 30, - height: 270, - hideIndexRow: false, - overscanRowCount: 10, - rowHeight: 40, - rowCount: 1000, - scrollToIndex: undefined, - sortBy: 'index', - sortDirection: SortDirection.ASC, - useDynamicRowHeight: false - } - - this._getRowHeight = this._getRowHeight.bind(this) - this._headerRenderer = this._headerRenderer.bind(this) - this._noRowsRenderer = this._noRowsRenderer.bind(this) - this._onRowCountChange = this._onRowCountChange.bind(this) - this._onScrollToRowChange = this._onScrollToRowChange.bind(this) - this._rowClassName = this._rowClassName.bind(this) - this._sort = this._sort.bind(this) - } - - render() { - const { - disableHeader, - headerHeight, - height, - hideIndexRow, - overscanRowCount, - rowHeight, - rowCount, - scrollToIndex, - sortBy, - sortDirection, - useDynamicRowHeight - } = this.state - - const { list } = this.context - const sortedList = this._isSortEnabled() - ? list - .sortBy(item => item[sortBy]) - .update(list => - sortDirection === SortDirection.DESC - ? list.reverse() - : list - ) - : list - - const rowGetter = ({ index }) => this._getDatum(sortedList, index) - - return ( -
- - {({ width }) => ( - - {!hideIndexRow && - rowData.index - } - dataKey='index' - disableSort={!this._isSortEnabled()} - width={60} - /> - } - - cellData - } - flexGrow={1} - /> -
- )} -
-
- ) - } - - _getDatum(list, index) { - return list.get(index % list.size) - } - - _getRowHeight({ index }) { - const { list } = this.context - - return this._getDatum(list, index).size - } - - _headerRenderer({ - columnData, - dataKey, - disableSort, - label, - sortBy, - sortDirection - }) { - return ( -
- Full Name - {sortBy === dataKey && - - } -
- ) - } - - _isSortEnabled() { - const { list } = this.context - const { rowCount } = this.state - - return rowCount <= list.size - } - - _noRowsRenderer() { - return ( -
- No rows -
- ) - } - - _onRowCountChange(event) { - const rowCount = parseInt(event.target.value, 10) || 0 - - this.setState({ rowCount }) - } - - _onScrollToRowChange(event) { - const { rowCount } = this.state - let scrollToIndex = Math.min(rowCount - 1, parseInt(event.target.value, 10)) - - if (isNaN(scrollToIndex)) { - scrollToIndex = undefined - } - - this.setState({ scrollToIndex }) - } - - _rowClassName({ index }) { - if (index < 0) { - return 'styles.headerRow' - } else { - return index % 2 === 0 ? 'styles.evenRow' : 'styles.oddRow' - } - } - - _sort({ sortBy, sortDirection }) { - this.setState({ sortBy, sortDirection }) - } - - _updateUseDynamicRowHeight(value) { - this.setState({ - useDynamicRowHeight: value - }) - } -} diff --git a/types/react-virtualized/WindowScroller.test.tsx b/types/react-virtualized/WindowScroller.test.tsx deleted file mode 100644 index c72a1b197a..0000000000 --- a/types/react-virtualized/WindowScroller.test.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import * as React from 'react' -import { PropTypes, PureComponent } from 'react' -import { WindowScroller, List, AutoSizer } from 'react-virtualized' - -export default class WindowScrollerExample extends PureComponent { - state; - context; - _windowScroller: WindowScroller; - - constructor(props) { - super(props) - - this.state = { - showHeaderText: true - } - - this._hideHeader = this._hideHeader.bind(this) - this._rowRenderer = this._rowRenderer.bind(this) - this._onCheckboxChange = this._onCheckboxChange.bind(this) - this._setRef = this._setRef.bind(this) - } - - render() { - const { list, isScrollingCustomElement, customElement } = this.context - const { showHeaderText } = this.state - - return ( - -
- - {({ height, isScrolling, scrollTop }) => ( - - {({ width }) => ( - this._rowRenderer({ index, isScrolling, isVisible, key, style })} - scrollTop={scrollTop} - width={width} - /> - )} - - )} - -
- ) - } - - _hideHeader() { - const { showHeaderText } = this.state - - this.setState({ - showHeaderText: !showHeaderText - }, () => { - this._windowScroller.updatePosition() - }) - } - - _rowRenderer({ index, isScrolling, isVisible, key, style }) { - const { list } = this.context - const row = list.get(index) - - return ( -
- {row.name} -
- ) - } - - _setRef(windowScroller) { - this._windowScroller = windowScroller - } - - _onCheckboxChange(event) { - this.context.setScrollingCustomElement(event.target.checked) - } -} diff --git a/types/react-virtualized/react-virtualized-tests.tsx b/types/react-virtualized/react-virtualized-tests.tsx new file mode 100644 index 0000000000..71386b2780 --- /dev/null +++ b/types/react-virtualized/react-virtualized-tests.tsx @@ -0,0 +1,1753 @@ +import * as React from 'react'; +import { PureComponent } from 'react' +import { ArrowKeyStepper, AutoSizer, Grid } from 'react-virtualized' + +export class ArrowKeyStepperExample extends PureComponent { + constructor(props) { + super(props) + + this._getColumnWidth = this._getColumnWidth.bind(this) + this._getRowHeight = this._getRowHeight.bind(this) + this._cellRenderer = this._cellRenderer.bind(this) + } + + render() { + const { mode } = this.state + + return ( + + + {({ onSectionRendered, scrollToColumn, scrollToRow }) => ( +
+ + + {({ width }) => ( + this._cellRenderer({ columnIndex, key, rowIndex, scrollToColumn, scrollToRow, style })} + rowHeight={this._getRowHeight} + rowCount={100} + scrollToColumn={scrollToColumn} + scrollToRow={scrollToRow} + width={width} + /> + )} + +
+ )} +
+ ) + } + + _getColumnWidth({ index }) { + return (1 + (index % 3)) * 60 + } + + _getRowHeight({ index }) { + return (1 + (index % 3)) * 30 + } + + _cellRenderer({ columnIndex, key, rowIndex, scrollToColumn, scrollToRow, style }) { + + return ( +
+ {`r:${rowIndex}, c:${columnIndex}`} +
+ ) + } +} + +import { List } from 'react-virtualized' + +export class AutoSizerExample extends PureComponent { + constructor(props) { + super(props) + + this._rowRenderer = this._rowRenderer.bind(this) + } + + render() { + const { list } = this.context + const { hideDescription } = this.state + + return ( + + {({ width, height }) => ( + + )} + + ) + } + + _rowRenderer({ index, key, style }) { + const { list } = this.context + const row = list.get(index) + + return ( +
+ {row.name} +
+ ) + } +} +import { } from 'react' +import { CellMeasurer, CellMeasurerCache } from 'react-virtualized' + +export class DynamicHeightList extends PureComponent { + + _cache: CellMeasurerCache + + constructor(props, context) { + super(props, context) + + this._cache = new CellMeasurerCache({ + fixedWidth: true, + minHeight: 50 + }) + + this._rowRenderer = this._rowRenderer.bind(this) + } + + render() { + const { width } = this.props + + return ( + + ) + } + + _rowRenderer({ index, isScrolling, key, parent, style }) { + 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 ( + + {({ measure }) => ( +
+ +
+ )} +
+ ) + } +} + +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 { + + _columnYMap: any; + + constructor(props, context) { + 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 = [] + + this._cellRenderer = this._cellRenderer.bind(this) + this._cellSizeAndPositionGetter = this._cellSizeAndPositionGetter.bind(this) + this._noContentRenderer = this._noContentRenderer.bind(this) + this._onCellCountChange = this._onCellCountChange.bind(this) + this._onHeightChange = this._onHeightChange.bind(this) + this._onHorizontalOverscanSizeChange = this._onHorizontalOverscanSizeChange.bind(this) + this._onScrollToCellChange = this._onScrollToCellChange.bind(this) + this._onVerticalOverscanSizeChange = this._onVerticalOverscanSizeChange.bind(this) + } + + render() { + const { cellCount, height, horizontalOverscanSize, scrollToCell, showScrollingPlaceholder, verticalOverscanSize } = this.state + + return ( + + {({ width }) => ( + + )} + + ) + } + + _cellRenderer({ index, isScrolling, key, style }) { + const { list } = this.context + const { showScrollingPlaceholder } = this.state + + const datum = list.get(index % list.size) + + // Customize style + style.backgroundColor = datum.color + + return ( +
+ {showScrollingPlaceholder && isScrolling ? '...' : index} +
+ ) + } + + _cellSizeAndPositionGetter({ 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) { + return Math.round(Math.sqrt(cellCount)) + } + + _onHorizontalOverscanSizeChange(event) { + const horizontalOverscanSize = parseInt(event.target.value, 10) || 0 + + this.setState({ horizontalOverscanSize }) + } + + _noContentRenderer() { + return ( +
+ No cells +
+ ) + } + + _onCellCountChange(event) { + const cellCount = parseInt(event.target.value, 10) || 0 + + this._columnYMap = [] + + this.setState({ + cellCount, + columnCount: this._getColumnCount(cellCount) + }) + } + + _onHeightChange(event) { + const height = parseInt(event.target.value, 10) || 0 + + this.setState({ height }) + } + + _onScrollToCellChange(event) { + const { cellCount } = this.state + + let scrollToCell = Math.min(cellCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToCell)) { + scrollToCell = undefined + } + + this.setState({ scrollToCell }) + } + + _onVerticalOverscanSizeChange(event) { + const verticalOverscanSize = parseInt(event.target.value, 10) || 0 + + this.setState({ verticalOverscanSize }) + } +} + +import { ColumnSizer } from 'react-virtualized' + +export class ColumnSizerExample extends PureComponent { + constructor(props) { + super(props) + + this._noColumnMaxWidthChange = this._noColumnMaxWidthChange.bind(this) + this._noColumnMinWidthChange = this._noColumnMinWidthChange.bind(this) + this._onColumnCountChange = this._onColumnCountChange.bind(this) + this._noContentRenderer = this._noContentRenderer.bind(this) + this._cellRenderer = this._cellRenderer.bind(this) + } + + render() { + const { + columnMaxWidth, + columnMinWidth, + columnCount + } = this.state + + return ( +
+ + {({ width }) => ( + + {({ adjustedWidth, getColumnWidth, registerChild }) => ( +
+ +
+ )} +
+ )} +
+
+ ) + } + + _noColumnMaxWidthChange(event) { + let columnMaxWidth = parseInt(event.target.value, 10) + + if (isNaN(columnMaxWidth)) { + columnMaxWidth = undefined + } else { + columnMaxWidth = Math.min(1000, columnMaxWidth) + } + + this.setState({ columnMaxWidth }) + } + + _noColumnMinWidthChange(event) { + let columnMinWidth = parseInt(event.target.value, 10) + + if (isNaN(columnMinWidth)) { + columnMinWidth = undefined + } else { + columnMinWidth = Math.max(1, columnMinWidth) + } + + this.setState({ columnMinWidth }) + } + + _onColumnCountChange(event) { + this.setState({ columnCount: parseInt(event.target.value, 10) || 0 }) + } + + _noContentRenderer() { + return ( +
+ No cells +
+ ) + } + + _cellRenderer({ columnIndex, key, rowIndex, style }) { + const className = columnIndex === 0 + ? 'styles.firstCell' + : 'styles.cell' + + return ( +
+ {`R:${rowIndex}, C:${columnIndex}`} +
+ ) + } +} + +export class GridExample extends PureComponent { + + + constructor(props, context) { + super(props, context) + + this.state = { + columnCount: 1000, + height: 300, + overscanColumnCount: 0, + overscanRowCount: 10, + rowHeight: 40, + rowCount: 1000, + scrollToColumn: undefined, + scrollToRow: undefined, + useDynamicRowHeight: false + } + + this._cellRenderer = this._cellRenderer.bind(this) + this._getColumnWidth = this._getColumnWidth.bind(this) + this._getRowClassName = this._getRowClassName.bind(this) + this._getRowHeight = this._getRowHeight.bind(this) + this._noContentRenderer = this._noContentRenderer.bind(this) + this._onColumnCountChange = this._onColumnCountChange.bind(this) + this._onRowCountChange = this._onRowCountChange.bind(this) + this._onScrollToColumnChange = this._onScrollToColumnChange.bind(this) + this._onScrollToRowChange = this._onScrollToRowChange.bind(this) + this._renderBodyCell = this._renderBodyCell.bind(this) + this._renderLeftSideCell = this._renderLeftSideCell.bind(this) + } + + render() { + const { + columnCount, + height, + overscanColumnCount, + overscanRowCount, + rowHeight, + rowCount, + scrollToColumn, + scrollToRow, + useDynamicRowHeight + } = this.state + + return ( + + + {({ width }) => ( + + )} + + ) + } + + _cellRenderer({ columnIndex, key, rowIndex, style }) { + if (columnIndex === 0) { + return this._renderLeftSideCell({ key, rowIndex, style }) + } else { + return this._renderBodyCell({ columnIndex, key, rowIndex, style }) + } + } + + _getColumnWidth({ index }) { + switch (index) { + case 0: + return 50 + case 1: + return 100 + case 2: + return 300 + default: + return 80 + } + } + + _getDatum(index) { + const { list } = this.context + + return list.get(index % list.size) + } + + _getRowClassName(row) { + return row % 2 === 0 ? 'styles.evenRow' : 'styles.oddRow' + } + + _getRowHeight({ index }) { + return this._getDatum(index).size + } + + _noContentRenderer() { + return ( +
+ No cells +
+ ) + } + + _renderBodyCell({ columnIndex, key, rowIndex, style }) { + 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 ( +
+ {content} +
+ ) + } + + _renderLeftSideCell({ key, rowIndex, style }) { + 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 ( +
+ {datum.name.charAt(0)} +
+ ) + } + + _updateUseDynamicRowHeights(value) { + this.setState({ + useDynamicRowHeight: value + }) + } + + _onColumnCountChange(event) { + const columnCount = parseInt(event.target.value, 10) || 0 + + this.setState({ columnCount }) + } + + _onRowCountChange(event) { + const rowCount = parseInt(event.target.value, 10) || 0 + + this.setState({ rowCount }) + } + + _onScrollToColumnChange(event) { + const { columnCount } = this.state + let scrollToColumn = Math.min(columnCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToColumn)) { + scrollToColumn = undefined + } + + this.setState({ scrollToColumn }) + } + + _onScrollToRowChange(event) { + const { rowCount } = this.state + let scrollToRow = Math.min(rowCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToRow)) { + scrollToRow = undefined + } + + this.setState({ scrollToRow }) + } +} + +import { InfiniteLoader } from 'react-virtualized' + +const STATUS_LOADING = 1 +const STATUS_LOADED = 2 + +export class InfiniteLoaderExample extends PureComponent { + _timeoutIdMap: any; + + constructor(props) { + super(props) + + this._timeoutIdMap = {} + + this._clearData = this._clearData.bind(this) + this._isRowLoaded = this._isRowLoaded.bind(this) + this._loadMoreRows = this._loadMoreRows.bind(this) + this._rowRenderer = this._rowRenderer.bind(this) + } + + componentWillUnmount() { + Object.keys(this._timeoutIdMap).forEach(timeoutId => { + clearTimeout(timeoutId as any) + }) + } + + render() { + const { list } = this.context + const { loadedRowCount, loadingRowCount } = this.state + + return ( + + {({ onRowsRendered, registerChild }) => ( + + {({ width }) => ( + + )} + + )} + + ) + } + + _clearData() { + this.setState({ + loadedRowCount: 0, + loadedRowsMap: {}, + loadingRowCount: 0 + }) + } + + _isRowLoaded({ index }) { + const { loadedRowsMap } = this.state + return !!loadedRowsMap[index] // STATUS_LOADING or STATUS_LOADED + } + + _loadMoreRows({ startIndex, stopIndex }) { + const { loadedRowsMap, loadingRowCount } = this.state + const increment = stopIndex - startIndex + 1 + + for (var i = startIndex; i <= stopIndex; i++) { + loadedRowsMap[i] = STATUS_LOADING + } + + this.setState({ + loadingRowCount: loadingRowCount + increment + }) + + const timeoutId = setTimeout(() => { + const { loadedRowCount, loadingRowCount } = this.state + + delete this._timeoutIdMap[timeoutId] + + for (var 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._timeoutIdMap[timeoutId] = true + + let promiseResolver + + return new Promise(resolve => { + promiseResolver = resolve + }) + } + + _rowRenderer({ index, key, style }) { + 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 = ( +
+ ) + } + + return ( +
+ {content} +
+ ) + } +} + +export class ListExample extends PureComponent { + + constructor(props, context) { + super(props, context) + + this.state = { + listHeight: 300, + listRowHeight: 50, + overscanRowCount: 10, + rowCount: context.list.size, + scrollToIndex: undefined, + showScrollingPlaceholder: false, + useDynamicRowHeight: false + } + + this._getRowHeight = this._getRowHeight.bind(this) + this._noRowsRenderer = this._noRowsRenderer.bind(this) + this._onRowCountChange = this._onRowCountChange.bind(this) + this._onScrollToRowChange = this._onScrollToRowChange.bind(this) + this._rowRenderer = this._rowRenderer.bind(this) + } + + render() { + const { + listHeight, + listRowHeight, + overscanRowCount, + rowCount, + scrollToIndex, + showScrollingPlaceholder, + useDynamicRowHeight + } = this.state + + return ( + + {({ width }) => ( + + )} + + ) + } + + _getDatum(index) { + const { list } = this.context + + return list.get(index % list.size) + } + + _getRowHeight({ index }) { + return this._getDatum(index).size + } + + _noRowsRenderer() { + return ( +
+ No rows +
+ ) + } + + _onRowCountChange(event) { + const rowCount = parseInt(event.target.value, 10) || 0 + + this.setState({ rowCount }) + } + + _onScrollToRowChange(event) { + const { rowCount } = this.state + let scrollToIndex = Math.min(rowCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToIndex)) { + scrollToIndex = undefined + } + + this.setState({ scrollToIndex }) + } + + _rowRenderer({ index, isScrolling, key, style }) { + const { + showScrollingPlaceholder, + useDynamicRowHeight + } = this.state + + if ( + showScrollingPlaceholder && + isScrolling + ) { + return ( +
+ Scrolling... +
+ ) + } + + const datum = this._getDatum(index) + + let additionalContent + + if (useDynamicRowHeight) { + switch (datum.size) { + case 75: + additionalContent =
It is medium-sized.
+ break + case 100: + additionalContent =
It is large-sized.
It has a 3rd row.
+ break + } + } + + return ( +
+
+ {datum.name.charAt(0)} +
+
+
+ {datum.name} +
+
+ This is row {index} +
+ {additionalContent} +
+ {useDynamicRowHeight && + + {datum.size}px + + } +
+ ) + } +} + +import { + WindowScroller, + createMasonryCellPositioner as createCellPositioner, + Positioner, + Masonry, + MasonryCellProps +} from 'react-virtualized' + +export class GridExample2 extends PureComponent { + _columnCount: number; + _cache: CellMeasurerCache; + _columnHeights: any; + _width: number; + _height: number; + _scrollTop: number; + _cellPositioner?: Positioner; + _masonry: Masonry; + + constructor(props, context) { + 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 + + let child + + if (windowScrollerEnabled) { + child = ( + + {this._renderAutoSizer} + + ) + } else { + child = this._renderAutoSizer({ height }) + } + + return ( +
+ {child} +
+ ) + } + + _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 ( + +
+
+ {datum.random} +
+ + ) + } + + _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 }) { + 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 ( + + {this._renderMasonry} + + ) + } + + _renderMasonry({ width }) { + this._width = width + + this._calculateColumnCount() + this._initCellPositioner() + + const { height, windowScrollerEnabled } = this.state + + return ( + + ) + } + + _resetCellPositioner() { + const { + columnWidth, + gutterSize + } = this.state + + this._cellPositioner.reset({ + columnCount: this._columnCount, + columnWidth, + spacer: gutterSize + }) + } + + _setMasonryRef(ref) { + 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 { + state + _onFixedColumnCountChange + _onFixedRowCountChange + _onScrollToColumnChange + _onScrollToRowChange + + constructor(props, context) { + super(props, context) + + this.state = { + fixedColumnCount: 2, + fixedRowCount: 1, + scrollToColumn: 0, + scrollToRow: 0 + } + + this._cellRenderer = this._cellRenderer.bind(this) + this._onFixedColumnCountChange = this._createEventHandler('fixedColumnCount') + this._onFixedRowCountChange = this._createEventHandler('fixedRowCount') + this._onScrollToColumnChange = this._createEventHandler('scrollToColumn') + this._onScrollToRowChange = this._createEventHandler('scrollToRow') + } + + render() { + return ( + + {({ width }) => ( + + )} + + ) + } + + _cellRenderer({ columnIndex, key, rowIndex, style }) { + return ( +
+ {columnIndex}, {rowIndex} +
+ ) + } + + _createEventHandler(property) { + return (event) => { + const value = parseInt(event.target.value, 10) || 0 + + this.setState({ + [property]: value + }) + } + } + + _createLabeledInput(property, eventHandler) { + const value = this.state[property] + + return ( + `` + ) + } +} + +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 { + state + constructor(props, context) { + super(props, context) + + this.state = { + columnWidth: 75, + columnCount: 50, + height: 300, + overscanColumnCount: 0, + overscanRowCount: 5, + rowHeight: 40, + rowCount: 100 + } + + this._renderBodyCell = this._renderBodyCell.bind(this) + this._renderHeaderCell = this._renderHeaderCell.bind(this) + this._renderLeftSideCell = this._renderLeftSideCell.bind(this) + } + + render() { + const { + columnCount, + columnWidth, + height, + overscanColumnCount, + overscanRowCount, + rowHeight, + rowCount + } = this.state + + return ( + + + {({ 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 ( +
+
+ +
+
+ +
+
+ + {({ width }) => ( +
+
+ +
+
+ +
+
+ )} +
+
+
+ ) + }} +
+ ) + } + + _renderBodyCell({ columnIndex, key, rowIndex, style }) { + if (columnIndex < 1) { + return + } + + return this._renderLeftSideCell({ columnIndex, key, rowIndex, style }) + } + + _renderHeaderCell({ columnIndex, key, rowIndex, style }) { + if (columnIndex < 1) { + return + } + + return this._renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) + } + + _renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) { + return ( +
+ {`C${columnIndex}`} +
+ ) + } + + _renderLeftSideCell({ columnIndex, key, rowIndex, style }) { + return ( +
+ {`R${rowIndex}, C${columnIndex}`} +
+ ) + } +} + +function hexToRgb(hex) { + 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, color2, amount) { + 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 { + state; + context; + constructor(props, context) { + super(props, context) + + this.state = { + disableHeader: false, + headerHeight: 30, + height: 270, + hideIndexRow: false, + overscanRowCount: 10, + rowHeight: 40, + rowCount: 1000, + scrollToIndex: undefined, + sortBy: 'index', + sortDirection: SortDirection.ASC, + useDynamicRowHeight: false + } + + this._getRowHeight = this._getRowHeight.bind(this) + this._headerRenderer = this._headerRenderer.bind(this) + this._noRowsRenderer = this._noRowsRenderer.bind(this) + this._onRowCountChange = this._onRowCountChange.bind(this) + this._onScrollToRowChange = this._onScrollToRowChange.bind(this) + this._rowClassName = this._rowClassName.bind(this) + this._sort = this._sort.bind(this) + } + + render() { + const { + disableHeader, + headerHeight, + height, + hideIndexRow, + overscanRowCount, + rowHeight, + rowCount, + scrollToIndex, + sortBy, + sortDirection, + useDynamicRowHeight + } = this.state + + const { list } = this.context + const sortedList = this._isSortEnabled() + ? list + .sortBy(item => item[sortBy]) + .update(list => + sortDirection === SortDirection.DESC + ? list.reverse() + : list + ) + : list + + const rowGetter = ({ index }) => this._getDatum(sortedList, index) + + return ( +
+ + {({ width }) => ( + + {!hideIndexRow && + rowData.index + } + dataKey='index' + disableSort={!this._isSortEnabled()} + width={60} + /> + } + + cellData + } + flexGrow={1} + /> +
+ )} +
+
+ ) + } + + _getDatum(list, index) { + return list.get(index % list.size) + } + + _getRowHeight({ index }) { + const { list } = this.context + + return this._getDatum(list, index).size + } + + _headerRenderer({ + columnData, + dataKey, + disableSort, + label, + sortBy, + sortDirection + }) { + return ( +
+ Full Name + {sortBy === dataKey && + + } +
+ ) + } + + _isSortEnabled() { + const { list } = this.context + const { rowCount } = this.state + + return rowCount <= list.size + } + + _noRowsRenderer() { + return ( +
+ No rows +
+ ) + } + + _onRowCountChange(event) { + const rowCount = parseInt(event.target.value, 10) || 0 + + this.setState({ rowCount }) + } + + _onScrollToRowChange(event) { + const { rowCount } = this.state + let scrollToIndex = Math.min(rowCount - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToIndex)) { + scrollToIndex = undefined + } + + this.setState({ scrollToIndex }) + } + + _rowClassName({ index }) { + if (index < 0) { + return 'styles.headerRow' + } else { + return index % 2 === 0 ? 'styles.evenRow' : 'styles.oddRow' + } + } + + _sort({ sortBy, sortDirection }) { + this.setState({ sortBy, sortDirection }) + } + + _updateUseDynamicRowHeight(value) { + this.setState({ + useDynamicRowHeight: value + }) + } +} + +export class WindowScrollerExample extends PureComponent { + state; + context; + _windowScroller: WindowScroller; + + constructor(props) { + super(props) + + this.state = { + showHeaderText: true + } + + this._hideHeader = this._hideHeader.bind(this) + this._rowRenderer = this._rowRenderer.bind(this) + this._onCheckboxChange = this._onCheckboxChange.bind(this) + this._setRef = this._setRef.bind(this) + } + + render() { + const { list, isScrollingCustomElement, customElement } = this.context + const { showHeaderText } = this.state + + return ( + +
+ + {({ height, isScrolling, scrollTop }) => ( + + {({ width }) => ( + this._rowRenderer({ index, isScrolling, isVisible, key, style })} + scrollTop={scrollTop} + width={width} + /> + )} + + )} + +
+ ) + } + + _hideHeader() { + const { showHeaderText } = this.state + + this.setState({ + showHeaderText: !showHeaderText + }, () => { + this._windowScroller.updatePosition() + }) + } + + _rowRenderer({ index, isScrolling, isVisible, key, style }) { + const { list } = this.context + const row = list.get(index) + + return ( +
+ {row.name} +
+ ) + } + + _setRef(windowScroller) { + this._windowScroller = windowScroller + } + + _onCheckboxChange(event) { + this.context.setScrollingCustomElement(event.target.checked) + } +} diff --git a/types/react-virtualized/tsconfig.json b/types/react-virtualized/tsconfig.json index 21a0e43a0d..6be15dbe8a 100644 --- a/types/react-virtualized/tsconfig.json +++ b/types/react-virtualized/tsconfig.json @@ -20,31 +20,19 @@ "files": [ "index.d.ts", "ArrowKeyStepper.d.ts", - "ArrowKeyStepper.test.tsx", "AutoSizer.d.ts", - "AutoSizer.test.tsx", "CellMeasurer.d.ts", - "CellMeasurer.test.tsx", "Collection.d.ts", - "Collection.test.tsx", "ColumnSizer.d.ts", - "ColumnSizer.test.tsx", "genericTypes.d.ts", "Grid.d.ts", - "Grid.test.tsx", "InfiniteLoader.d.ts", - "InfiniteLoader.test.tsx", "List.d.ts", - "List.test.tsx", "Masonry.d.ts", - "Masonry.test.tsx", "MultiGrid.d.ts", - "MultiGrid.test.tsx", "ScrollSync.d.ts", - "ScrollSync.test.tsx", "Table.d.ts", - "Table.test.tsx", "WindowScroller.d.ts", - "WindowScroller.test.tsx" + "react-virtualized-tests.tsx" ] } \ No newline at end of file From a500aedade3a27ccd6348c134ba0a032000a9257 Mon Sep 17 00:00:00 2001 From: Kalle Ott Date: Mon, 27 Mar 2017 21:58:19 +0200 Subject: [PATCH 4/6] update to typescript 2.2 for object type --- types/react-virtualized/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/react-virtualized/index.d.ts b/types/react-virtualized/index.d.ts index 31a6ee29c8..3280d8410d 100644 --- a/types/react-virtualized/index.d.ts +++ b/types/react-virtualized/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/bvaughn/react-virtualized // Definitions by: Kalle Ott // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.1 +// TypeScript Version: 2.2 export { ArrowKeyStepper, From 4e37f8d9f9913922d441bf2f03ea17d7293cf5ec Mon Sep 17 00:00:00 2001 From: Kalle Ott Date: Tue, 28 Mar 2017 09:14:58 +0200 Subject: [PATCH 5/6] fixed mapping to distribution folder structure --- .../dist/commonjs/ArrowKeyStepper.d.ts | 1 + .../dist/commonjs/AutoSizer.d.ts | 1 + .../dist/commonjs/CellMeasurer.d.ts | 1 + .../dist/commonjs/Collection.d.ts | 1 + .../dist/commonjs/ColumnSizer.d.ts | 1 + .../react-virtualized/dist/commonjs/Grid.d.ts | 1 + .../dist/commonjs/InfiniteLoader.d.ts | 1 + .../react-virtualized/dist/commonjs/List.d.ts | 1 + .../dist/commonjs/Masonry.d.ts | 1 + .../dist/commonjs/MultiGrid.d.ts | 1 + .../dist/commonjs/ScrollSync.d.ts | 1 + .../dist/commonjs/Table.d.ts | 1 + .../dist/commonjs/WindowScroller.d.ts | 1 + .../{ => dist/es}/ArrowKeyStepper.d.ts | 0 .../{ => dist/es}/AutoSizer.d.ts | 0 .../{ => dist/es}/CellMeasurer.d.ts | 0 .../{ => dist/es}/Collection.d.ts | 3 +- .../{ => dist/es}/ColumnSizer.d.ts | 0 .../react-virtualized/{ => dist/es}/Grid.d.ts | 3 +- .../{ => dist/es}/InfiniteLoader.d.ts | 2 +- .../react-virtualized/{ => dist/es}/List.d.ts | 3 +- .../{ => dist/es}/Masonry.d.ts | 1 - .../{ => dist/es}/MultiGrid.d.ts | 0 .../{ => dist/es}/ScrollSync.d.ts | 0 .../{ => dist/es}/Table.d.ts | 2 +- .../{ => dist/es}/WindowScroller.d.ts | 1 - types/react-virtualized/genericTypes.d.ts | 40 ---------- types/react-virtualized/index.d.ts | 77 +++++++++++++------ 28 files changed, 71 insertions(+), 74 deletions(-) create mode 100644 types/react-virtualized/dist/commonjs/ArrowKeyStepper.d.ts create mode 100644 types/react-virtualized/dist/commonjs/AutoSizer.d.ts create mode 100644 types/react-virtualized/dist/commonjs/CellMeasurer.d.ts create mode 100644 types/react-virtualized/dist/commonjs/Collection.d.ts create mode 100644 types/react-virtualized/dist/commonjs/ColumnSizer.d.ts create mode 100644 types/react-virtualized/dist/commonjs/Grid.d.ts create mode 100644 types/react-virtualized/dist/commonjs/InfiniteLoader.d.ts create mode 100644 types/react-virtualized/dist/commonjs/List.d.ts create mode 100644 types/react-virtualized/dist/commonjs/Masonry.d.ts create mode 100644 types/react-virtualized/dist/commonjs/MultiGrid.d.ts create mode 100644 types/react-virtualized/dist/commonjs/ScrollSync.d.ts create mode 100644 types/react-virtualized/dist/commonjs/Table.d.ts create mode 100644 types/react-virtualized/dist/commonjs/WindowScroller.d.ts rename types/react-virtualized/{ => dist/es}/ArrowKeyStepper.d.ts (100%) rename types/react-virtualized/{ => dist/es}/AutoSizer.d.ts (100%) rename types/react-virtualized/{ => dist/es}/CellMeasurer.d.ts (100%) rename types/react-virtualized/{ => dist/es}/Collection.d.ts (99%) rename types/react-virtualized/{ => dist/es}/ColumnSizer.d.ts (100%) rename types/react-virtualized/{ => dist/es}/Grid.d.ts (99%) rename types/react-virtualized/{ => dist/es}/InfiniteLoader.d.ts (98%) rename types/react-virtualized/{ => dist/es}/List.d.ts (98%) rename types/react-virtualized/{ => dist/es}/Masonry.d.ts (99%) rename types/react-virtualized/{ => dist/es}/MultiGrid.d.ts (100%) rename types/react-virtualized/{ => dist/es}/ScrollSync.d.ts (100%) rename types/react-virtualized/{ => dist/es}/Table.d.ts (99%) rename types/react-virtualized/{ => dist/es}/WindowScroller.d.ts (99%) delete mode 100644 types/react-virtualized/genericTypes.d.ts diff --git a/types/react-virtualized/dist/commonjs/ArrowKeyStepper.d.ts b/types/react-virtualized/dist/commonjs/ArrowKeyStepper.d.ts new file mode 100644 index 0000000000..fd16c58feb --- /dev/null +++ b/types/react-virtualized/dist/commonjs/ArrowKeyStepper.d.ts @@ -0,0 +1 @@ +export * from '../es/ArrowKeyStepper'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/AutoSizer.d.ts b/types/react-virtualized/dist/commonjs/AutoSizer.d.ts new file mode 100644 index 0000000000..c0551a98a4 --- /dev/null +++ b/types/react-virtualized/dist/commonjs/AutoSizer.d.ts @@ -0,0 +1 @@ +export * from '../es/AutoSizer'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/CellMeasurer.d.ts b/types/react-virtualized/dist/commonjs/CellMeasurer.d.ts new file mode 100644 index 0000000000..907eafee51 --- /dev/null +++ b/types/react-virtualized/dist/commonjs/CellMeasurer.d.ts @@ -0,0 +1 @@ +export * from '../es/CellMeasurer'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/Collection.d.ts b/types/react-virtualized/dist/commonjs/Collection.d.ts new file mode 100644 index 0000000000..2764686c76 --- /dev/null +++ b/types/react-virtualized/dist/commonjs/Collection.d.ts @@ -0,0 +1 @@ +export * from '../es/Collection'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/ColumnSizer.d.ts b/types/react-virtualized/dist/commonjs/ColumnSizer.d.ts new file mode 100644 index 0000000000..80c9cf5d2e --- /dev/null +++ b/types/react-virtualized/dist/commonjs/ColumnSizer.d.ts @@ -0,0 +1 @@ +export * from '../es/ColumnSizer'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/Grid.d.ts b/types/react-virtualized/dist/commonjs/Grid.d.ts new file mode 100644 index 0000000000..168a11ac52 --- /dev/null +++ b/types/react-virtualized/dist/commonjs/Grid.d.ts @@ -0,0 +1 @@ +export * from '../es/Grid'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/InfiniteLoader.d.ts b/types/react-virtualized/dist/commonjs/InfiniteLoader.d.ts new file mode 100644 index 0000000000..29449c85ff --- /dev/null +++ b/types/react-virtualized/dist/commonjs/InfiniteLoader.d.ts @@ -0,0 +1 @@ +export * from '../es/InfiniteLoader'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/List.d.ts b/types/react-virtualized/dist/commonjs/List.d.ts new file mode 100644 index 0000000000..6fdfde2dc0 --- /dev/null +++ b/types/react-virtualized/dist/commonjs/List.d.ts @@ -0,0 +1 @@ +export * from '../es/List'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/Masonry.d.ts b/types/react-virtualized/dist/commonjs/Masonry.d.ts new file mode 100644 index 0000000000..e5189fb5f9 --- /dev/null +++ b/types/react-virtualized/dist/commonjs/Masonry.d.ts @@ -0,0 +1 @@ +export * from '../es/Masonry'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/MultiGrid.d.ts b/types/react-virtualized/dist/commonjs/MultiGrid.d.ts new file mode 100644 index 0000000000..09f385eca4 --- /dev/null +++ b/types/react-virtualized/dist/commonjs/MultiGrid.d.ts @@ -0,0 +1 @@ +export * from '../es/MultiGrid'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/ScrollSync.d.ts b/types/react-virtualized/dist/commonjs/ScrollSync.d.ts new file mode 100644 index 0000000000..ffb4423c0a --- /dev/null +++ b/types/react-virtualized/dist/commonjs/ScrollSync.d.ts @@ -0,0 +1 @@ +export * from '../es/ScrollSync'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/Table.d.ts b/types/react-virtualized/dist/commonjs/Table.d.ts new file mode 100644 index 0000000000..db2670ceda --- /dev/null +++ b/types/react-virtualized/dist/commonjs/Table.d.ts @@ -0,0 +1 @@ +export * from '../es/Table'; \ No newline at end of file diff --git a/types/react-virtualized/dist/commonjs/WindowScroller.d.ts b/types/react-virtualized/dist/commonjs/WindowScroller.d.ts new file mode 100644 index 0000000000..0380f0a4fb --- /dev/null +++ b/types/react-virtualized/dist/commonjs/WindowScroller.d.ts @@ -0,0 +1 @@ +export * from '../es/WindowScroller'; \ No newline at end of file diff --git a/types/react-virtualized/ArrowKeyStepper.d.ts b/types/react-virtualized/dist/es/ArrowKeyStepper.d.ts similarity index 100% rename from types/react-virtualized/ArrowKeyStepper.d.ts rename to types/react-virtualized/dist/es/ArrowKeyStepper.d.ts diff --git a/types/react-virtualized/AutoSizer.d.ts b/types/react-virtualized/dist/es/AutoSizer.d.ts similarity index 100% rename from types/react-virtualized/AutoSizer.d.ts rename to types/react-virtualized/dist/es/AutoSizer.d.ts diff --git a/types/react-virtualized/CellMeasurer.d.ts b/types/react-virtualized/dist/es/CellMeasurer.d.ts similarity index 100% rename from types/react-virtualized/CellMeasurer.d.ts rename to types/react-virtualized/dist/es/CellMeasurer.d.ts diff --git a/types/react-virtualized/Collection.d.ts b/types/react-virtualized/dist/es/Collection.d.ts similarity index 99% rename from types/react-virtualized/Collection.d.ts rename to types/react-virtualized/dist/es/Collection.d.ts index 52a69de286..404d329222 100644 --- a/types/react-virtualized/Collection.d.ts +++ b/types/react-virtualized/dist/es/Collection.d.ts @@ -1,11 +1,10 @@ -/** @flow */ import { PureComponent, Validator, Requireable } from 'react' import { Index, ScrollPosition, SizeInfo, SizeAndPositionInfo -} from './genericTypes'; +} from '../../index'; export type CollectionCellSizeAndPosition = { height: number, width: number, x: number, y: number }; export type CollectionCellSizeAndPositionGetter = (params: Index) => CollectionCellSizeAndPosition; diff --git a/types/react-virtualized/ColumnSizer.d.ts b/types/react-virtualized/dist/es/ColumnSizer.d.ts similarity index 100% rename from types/react-virtualized/ColumnSizer.d.ts rename to types/react-virtualized/dist/es/ColumnSizer.d.ts diff --git a/types/react-virtualized/Grid.d.ts b/types/react-virtualized/dist/es/Grid.d.ts similarity index 99% rename from types/react-virtualized/Grid.d.ts rename to types/react-virtualized/dist/es/Grid.d.ts index ea7130857c..b68cf45956 100644 --- a/types/react-virtualized/Grid.d.ts +++ b/types/react-virtualized/dist/es/Grid.d.ts @@ -1,9 +1,8 @@ -/** @flow */ import { Validator, Requireable, PureComponent } from 'react' import { List } from './List'; import { Table } from './Table'; import { CellMeasurerCache } from './CellMeasurer'; -import { Index, Map, Alignment } from './genericTypes'; +import { Index, Map, Alignment } from '../../index'; export type GridCellProps = { columnIndex: number; diff --git a/types/react-virtualized/InfiniteLoader.d.ts b/types/react-virtualized/dist/es/InfiniteLoader.d.ts similarity index 98% rename from types/react-virtualized/InfiniteLoader.d.ts rename to types/react-virtualized/dist/es/InfiniteLoader.d.ts index 4493921e72..e16359adca 100644 --- a/types/react-virtualized/InfiniteLoader.d.ts +++ b/types/react-virtualized/dist/es/InfiniteLoader.d.ts @@ -1,5 +1,5 @@ import { PureComponent, Validator, Requireable } from 'react' -import { Index, IndexRange } from './genericTypes'; +import { Index, IndexRange } from '../../index'; export type InfiniteLoaderChildProps = { onRowsRendered: (params: { startIndex: number, stopIndex: number }) => void, diff --git a/types/react-virtualized/List.d.ts b/types/react-virtualized/dist/es/List.d.ts similarity index 98% rename from types/react-virtualized/List.d.ts rename to types/react-virtualized/dist/es/List.d.ts index d4d5196a34..2a4f30dbfe 100644 --- a/types/react-virtualized/List.d.ts +++ b/types/react-virtualized/dist/es/List.d.ts @@ -1,7 +1,6 @@ -/** @flow */ import { PureComponent, Validator, Requireable } from 'react' import { Grid, GridCellProps } from './Grid' -import { Index, IndexRange, Alignment } from './genericTypes' +import { Index, IndexRange, Alignment } from '../../index' import { CellMeasurerCache } from './CellMeasurer' export type ListRowProps = GridCellProps & { index: number, style: React.CSSProperties }; diff --git a/types/react-virtualized/Masonry.d.ts b/types/react-virtualized/dist/es/Masonry.d.ts similarity index 99% rename from types/react-virtualized/Masonry.d.ts rename to types/react-virtualized/dist/es/Masonry.d.ts index c4187bf611..51c59a90fc 100644 --- a/types/react-virtualized/Masonry.d.ts +++ b/types/react-virtualized/dist/es/Masonry.d.ts @@ -1,5 +1,4 @@ import { PureComponent, Validator, Requireable } from 'react' -import { } from './genericTypes'; import { CellMeasurerCache, KeyMapper } from './CellMeasurer'; import { GridCellRenderer } from './Grid'; /** diff --git a/types/react-virtualized/MultiGrid.d.ts b/types/react-virtualized/dist/es/MultiGrid.d.ts similarity index 100% rename from types/react-virtualized/MultiGrid.d.ts rename to types/react-virtualized/dist/es/MultiGrid.d.ts diff --git a/types/react-virtualized/ScrollSync.d.ts b/types/react-virtualized/dist/es/ScrollSync.d.ts similarity index 100% rename from types/react-virtualized/ScrollSync.d.ts rename to types/react-virtualized/dist/es/ScrollSync.d.ts diff --git a/types/react-virtualized/Table.d.ts b/types/react-virtualized/dist/es/Table.d.ts similarity index 99% rename from types/react-virtualized/Table.d.ts rename to types/react-virtualized/dist/es/Table.d.ts index af5cf9b0b5..6607211dcf 100644 --- a/types/react-virtualized/Table.d.ts +++ b/types/react-virtualized/dist/es/Table.d.ts @@ -1,6 +1,6 @@ import { Validator, Requireable, PureComponent, Component } from 'react'; import { CellMeasurerCache } from './CellMeasurer'; -import { Index, Alignment, ScrollEventData, IndexRange, OverscanIndexRange } from './genericTypes'; +import { Index, Alignment, ScrollEventData, IndexRange, OverscanIndexRange } from '../../index'; import { Grid } from './Grid'; export type TableCellDataGetterParams = { diff --git a/types/react-virtualized/WindowScroller.d.ts b/types/react-virtualized/dist/es/WindowScroller.d.ts similarity index 99% rename from types/react-virtualized/WindowScroller.d.ts rename to types/react-virtualized/dist/es/WindowScroller.d.ts index 093debdd78..7e0a09379e 100644 --- a/types/react-virtualized/WindowScroller.d.ts +++ b/types/react-virtualized/dist/es/WindowScroller.d.ts @@ -1,4 +1,3 @@ -/** @flow */ import { Validator, Requireable, PureComponent } from 'react' export type WindowScrollerChildProps = { diff --git a/types/react-virtualized/genericTypes.d.ts b/types/react-virtualized/genericTypes.d.ts deleted file mode 100644 index 7f4b6ff4b4..0000000000 --- a/types/react-virtualized/genericTypes.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -export type Index = { - index: number -}; - -export type PositionInfo = { - x: number, - y: number -}; - -export type ScrollPosition = { - scrollLeft: number, - scrollTop: number -}; - -export type SizeInfo = { - height: number, - width: number -}; - -export type SizeAndPositionInfo = SizeInfo & PositionInfo; - -export type Map = { [key: string]: T }; - -export type Alignment = 'auto' | 'end' | 'start' | 'center'; - -export type IndexRange = { - startIndex: number, - stopIndex: number -} - -export type OverscanIndexRange = { - overscanStartIndex: number, - overscanStopIndex: number, -} - -export type ScrollEventData = { - clientHeight: number, - scrollHeight: number, - scrollTop: number -} \ No newline at end of file diff --git a/types/react-virtualized/index.d.ts b/types/react-virtualized/index.d.ts index 3280d8410d..d6860176ed 100644 --- a/types/react-virtualized/index.d.ts +++ b/types/react-virtualized/index.d.ts @@ -8,19 +8,19 @@ export { ArrowKeyStepper, ArrowKeyStepperProps, ChildProps as ArrowKeyStepperChildProps -} from './ArrowKeyStepper' +} from './dist/es/ArrowKeyStepper' export { AutoSizer, AutoSizerProps, Dimensions -} from './AutoSizer' +} from './dist/es/AutoSizer' export { CellMeasurer, CellMeasurerCache, CellMeasurerCacheParams, CellMeasurerProps, KeyMapper -} from './CellMeasurer' +} from './dist/es/CellMeasurer' export { Collection, CollectionCellGroupRenderer, @@ -30,12 +30,12 @@ export { CollectionCellSizeAndPosition, CollectionCellSizeAndPositionGetter, CollectionProps -} from './Collection' +} from './dist/es/Collection' export { ColumnSizer, ColumnSizerProps, SizedColumnProps -} from './ColumnSizer' +} from './dist/es/ColumnSizer' export { defaultCellRangeRenderer, Grid, @@ -56,18 +56,18 @@ export { SectionRenderedParams, SizeAndPositionData, VisibleCellRange -} from './Grid' +} from './dist/es/Grid' export { InfiniteLoader, InfiniteLoaderChildProps, InfiniteLoaderProps -} from './InfiniteLoader' +} from './dist/es/InfiniteLoader' export { List, ListProps, ListRowProps, ListRowRenderer -} from './List' +} from './dist/es/List' export { createCellPositioner as createMasonryCellPositioner, Masonry, @@ -79,19 +79,19 @@ export { OnScrollCallback, Position, Positioner -} from './Masonry' +} from './dist/es/Masonry' export { MultiGrid, MultiGridProps, MultiGridState -} from './MultiGrid' +} from './dist/es/MultiGrid' export { ScrollSync, OnScrollParams, ScrollSyncChildProps, ScrollSyncProps, ScrollSyncState -} from './ScrollSync' +} from './dist/es/ScrollSync' export { defaultTableCellDataGetter, defaultTableCellRenderer, @@ -117,22 +117,51 @@ export { TableProps, TableRowProps, TableRowRenderer -} from './Table' +} from './dist/es/Table' export { WindowScroller, WindowScrollerChildProps, WindowScrollerProps, WindowScrollerState -} from './WindowScroller' +} from './dist/es/WindowScroller' -export { - Alignment, - Index, - IndexRange, - Map, - PositionInfo, - ScrollEventData, - ScrollPosition, - SizeAndPositionInfo, - SizeInfo -} from './genericTypes' \ No newline at end of file +export type Index = { + index: number +}; + +export type PositionInfo = { + x: number, + y: number +}; + +export type ScrollPosition = { + scrollLeft: number, + scrollTop: number +}; + +export type SizeInfo = { + height: number, + width: number +}; + +export type SizeAndPositionInfo = SizeInfo & PositionInfo; + +export type Map = { [key: string]: T }; + +export type Alignment = 'auto' | 'end' | 'start' | 'center'; + +export type IndexRange = { + startIndex: number, + stopIndex: number +} + +export type OverscanIndexRange = { + overscanStartIndex: number, + overscanStopIndex: number, +} + +export type ScrollEventData = { + clientHeight: number, + scrollHeight: number, + scrollTop: number +} \ No newline at end of file From 7835e89a401fae0283530a91db2846e00e3dbf31 Mon Sep 17 00:00:00 2001 From: Kalle Ott Date: Tue, 28 Mar 2017 09:21:51 +0200 Subject: [PATCH 6/6] fixed tsconfig --- types/react-virtualized/tsconfig.json | 40 +++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/types/react-virtualized/tsconfig.json b/types/react-virtualized/tsconfig.json index 6be15dbe8a..7e2936975f 100644 --- a/types/react-virtualized/tsconfig.json +++ b/types/react-virtualized/tsconfig.json @@ -19,20 +19,32 @@ }, "files": [ "index.d.ts", - "ArrowKeyStepper.d.ts", - "AutoSizer.d.ts", - "CellMeasurer.d.ts", - "Collection.d.ts", - "ColumnSizer.d.ts", - "genericTypes.d.ts", - "Grid.d.ts", - "InfiniteLoader.d.ts", - "List.d.ts", - "Masonry.d.ts", - "MultiGrid.d.ts", - "ScrollSync.d.ts", - "Table.d.ts", - "WindowScroller.d.ts", + "dist/es/ArrowKeyStepper.d.ts", + "dist/es/AutoSizer.d.ts", + "dist/es/CellMeasurer.d.ts", + "dist/es/Collection.d.ts", + "dist/es/ColumnSizer.d.ts", + "dist/es/Grid.d.ts", + "dist/es/InfiniteLoader.d.ts", + "dist/es/List.d.ts", + "dist/es/Masonry.d.ts", + "dist/es/MultiGrid.d.ts", + "dist/es/ScrollSync.d.ts", + "dist/es/Table.d.ts", + "dist/es/WindowScroller.d.ts", + "dist/commonjs/ArrowKeyStepper.d.ts", + "dist/commonjs/AutoSizer.d.ts", + "dist/commonjs/CellMeasurer.d.ts", + "dist/commonjs/Collection.d.ts", + "dist/commonjs/ColumnSizer.d.ts", + "dist/commonjs/Grid.d.ts", + "dist/commonjs/InfiniteLoader.d.ts", + "dist/commonjs/List.d.ts", + "dist/commonjs/Masonry.d.ts", + "dist/commonjs/MultiGrid.d.ts", + "dist/commonjs/ScrollSync.d.ts", + "dist/commonjs/Table.d.ts", + "dist/commonjs/WindowScroller.d.ts", "react-virtualized-tests.tsx" ] } \ No newline at end of file