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/dist/es/ArrowKeyStepper.d.ts b/types/react-virtualized/dist/es/ArrowKeyStepper.d.ts new file mode 100644 index 0000000000..e42ff353f2 --- /dev/null +++ b/types/react-virtualized/dist/es/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/dist/es/AutoSizer.d.ts b/types/react-virtualized/dist/es/AutoSizer.d.ts new file mode 100644 index 0000000000..6d82a44482 --- /dev/null +++ b/types/react-virtualized/dist/es/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/dist/es/CellMeasurer.d.ts b/types/react-virtualized/dist/es/CellMeasurer.d.ts new file mode 100644 index 0000000000..5e1e0db3fb --- /dev/null +++ b/types/react-virtualized/dist/es/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/dist/es/Collection.d.ts b/types/react-virtualized/dist/es/Collection.d.ts new file mode 100644 index 0000000000..404d329222 --- /dev/null +++ b/types/react-virtualized/dist/es/Collection.d.ts @@ -0,0 +1,123 @@ +import { PureComponent, Validator, Requireable } from 'react' +import { + Index, + ScrollPosition, + SizeInfo, + SizeAndPositionInfo +} from '../../index'; + +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/dist/es/ColumnSizer.d.ts b/types/react-virtualized/dist/es/ColumnSizer.d.ts new file mode 100644 index 0000000000..6efcf8c044 --- /dev/null +++ b/types/react-virtualized/dist/es/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/dist/es/Grid.d.ts b/types/react-virtualized/dist/es/Grid.d.ts new file mode 100644 index 0000000000..b68cf45956 --- /dev/null +++ b/types/react-virtualized/dist/es/Grid.d.ts @@ -0,0 +1,461 @@ +import { Validator, Requireable, PureComponent } from 'react' +import { List } from './List'; +import { Table } from './Table'; +import { CellMeasurerCache } from './CellMeasurer'; +import { Index, Map, Alignment } from '../../index'; + +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/dist/es/InfiniteLoader.d.ts b/types/react-virtualized/dist/es/InfiniteLoader.d.ts new file mode 100644 index 0000000000..e16359adca --- /dev/null +++ b/types/react-virtualized/dist/es/InfiniteLoader.d.ts @@ -0,0 +1,80 @@ +import { PureComponent, Validator, Requireable } from 'react' +import { Index, IndexRange } from '../../index'; + +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/dist/es/List.d.ts b/types/react-virtualized/dist/es/List.d.ts new file mode 100644 index 0000000000..2a4f30dbfe --- /dev/null +++ b/types/react-virtualized/dist/es/List.d.ts @@ -0,0 +1,137 @@ +import { PureComponent, Validator, Requireable } from 'react' +import { Grid, GridCellProps } from './Grid' +import { Index, IndexRange, Alignment } from '../../index' +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/dist/es/Masonry.d.ts b/types/react-virtualized/dist/es/Masonry.d.ts new file mode 100644 index 0000000000..51c59a90fc --- /dev/null +++ b/types/react-virtualized/dist/es/Masonry.d.ts @@ -0,0 +1,145 @@ +import { PureComponent, Validator, Requireable } from 'react' +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/dist/es/MultiGrid.d.ts b/types/react-virtualized/dist/es/MultiGrid.d.ts new file mode 100644 index 0000000000..1bb8b7dfac --- /dev/null +++ b/types/react-virtualized/dist/es/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/dist/es/ScrollSync.d.ts b/types/react-virtualized/dist/es/ScrollSync.d.ts new file mode 100644 index 0000000000..4f1e924a69 --- /dev/null +++ b/types/react-virtualized/dist/es/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/dist/es/Table.d.ts b/types/react-virtualized/dist/es/Table.d.ts new file mode 100644 index 0000000000..6607211dcf --- /dev/null +++ b/types/react-virtualized/dist/es/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 '../../index'; +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/dist/es/WindowScroller.d.ts b/types/react-virtualized/dist/es/WindowScroller.d.ts new file mode 100644 index 0000000000..7e0a09379e --- /dev/null +++ b/types/react-virtualized/dist/es/WindowScroller.d.ts @@ -0,0 +1,59 @@ +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/index.d.ts b/types/react-virtualized/index.d.ts index f89183c90f..d6860176ed 100644 --- a/types/react-virtualized/index.d.ts +++ b/types/react-virtualized/index.d.ts @@ -1,545 +1,167 @@ -// 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 +// TypeScript Version: 2.2 -import * as React from "react"; +export { + ArrowKeyStepper, + ArrowKeyStepperProps, + ChildProps as ArrowKeyStepperChildProps +} from './dist/es/ArrowKeyStepper' +export { + AutoSizer, + AutoSizerProps, + Dimensions +} from './dist/es/AutoSizer' +export { + CellMeasurer, + CellMeasurerCache, + CellMeasurerCacheParams, + CellMeasurerProps, + KeyMapper +} from './dist/es/CellMeasurer' +export { + Collection, + CollectionCellGroupRenderer, + CollectionCellGroupRendererParams, + CollectionCellRenderer, + CollectionCellRendererParams, + CollectionCellSizeAndPosition, + CollectionCellSizeAndPositionGetter, + CollectionProps +} from './dist/es/Collection' +export { + ColumnSizer, + ColumnSizerProps, + SizedColumnProps +} from './dist/es/ColumnSizer' +export { + defaultCellRangeRenderer, + Grid, + CellSizeAndPositionManager, + ConfigureParams, + ContainerSizeAndOffset, + GetVisibleCellRangeParams, + GridCellProps, + GridCellRangeProps, + GridCellRangeRenderer, + GridCellRenderer, + GridProps, + GridState, + OverscanIndices, + OverscanIndicesGetterParams, + ScrollDirection, + ScrollParams, + SectionRenderedParams, + SizeAndPositionData, + VisibleCellRange +} from './dist/es/Grid' +export { + InfiniteLoader, + InfiniteLoaderChildProps, + InfiniteLoaderProps +} from './dist/es/InfiniteLoader' +export { + List, + ListProps, + ListRowProps, + ListRowRenderer +} from './dist/es/List' +export { + createCellPositioner as createMasonryCellPositioner, + Masonry, + CellRenderer, + MasonryCellProps, + MasonryProps, + MasonryState, + OnCellsRenderedCallback, + OnScrollCallback, + Position, + Positioner +} from './dist/es/Masonry' +export { + MultiGrid, + MultiGridProps, + MultiGridState +} from './dist/es/MultiGrid' +export { + ScrollSync, + OnScrollParams, + ScrollSyncChildProps, + ScrollSyncProps, + ScrollSyncState +} from './dist/es/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 './dist/es/Table' +export { + WindowScroller, + WindowScrollerChildProps, + WindowScrollerProps, + WindowScrollerState +} from './dist/es/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 = { +export type Index = { 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 type PositionInfo = { + x: number, + y: 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 ScrollPosition = { + scrollLeft: number, + scrollTop: number +}; -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, +export type SizeInfo = { 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; +export type SizeAndPositionInfo = SizeInfo & PositionInfo; -// 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 Map = { [key: string]: T }; -export type RowClickHandlerParams = { - rowData: { - columnData: Object, - id: string, - index: number - } +export type Alignment = 'auto' | 'end' | 'start' | 'center'; + +export type IndexRange = { + startIndex: number, + stopIndex: 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 type OverscanIndexRange = { + overscanStartIndex: number, + overscanStopIndex: number, } -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, +export type ScrollEventData = { + clientHeight: number, + scrollHeight: 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 { } +} \ No newline at end of file diff --git a/types/react-virtualized/react-virtualized-tests.tsx b/types/react-virtualized/react-virtualized-tests.tsx index aa1dc087a9..71386b2780 100644 --- a/types/react-virtualized/react-virtualized-tests.tsx +++ b/types/react-virtualized/react-virtualized-tests.tsx @@ -1,156 +1,106 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import { PureComponent } from 'react' +import { ArrowKeyStepper, AutoSizer, Grid } from 'react-virtualized' -import { - Collection, - SortDirection, - Grid, - ArrowKeyStepper, - AutoSizer, - CellMeasurer, - ColumnSizer, - InfiniteLoader, - ScrollSync, - WindowScroller, - WindowScrollerRenderCallBackParams, - List, - Column, - Table, -} from "react-virtualized"; +export class ArrowKeyStepperExample extends PureComponent { + constructor(props) { + super(props) -/* - * Collection - */ + this._getColumnWidth = this._getColumnWidth.bind(this) + this._getRowHeight = this._getRowHeight.bind(this) + this._cellRenderer = this._cellRenderer.bind(this) + } -function CollectionTest() { - const list = [ - { name: "Brian Vaughn", x: 13, y: 34, width: 123, size: 234, height: 123 } - ]; + render() { + const { mode } = this.state - // 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") - ); + 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}`} +
+ ) + } } -function GridTest() { - // Grid data as an array of arrays - const list = [ - ['Brian Vaughn', 'Software Engineer', 'San Jose', 'CA', 95125 /* ... */] - // And so on... - ]; +import { List } from 'react-virtualized' - // Render your grid - ReactDOM.render( - list[rowIndex][columnIndex]} - />, - document.getElementById('example') - ); -} +export class AutoSizerExample extends PureComponent { + constructor(props) { + super(props) -function ListTest() { - // List data - const list = [ - { name: 'Brian Vaughn', occupation: 'Software Engineer', location: 'San Jose, CA, 95125' /* ... */ } - // And so on... - ]; + this._rowRenderer = this._rowRenderer.bind(this) + } - // Render your List - ReactDOM.render( - list[index]} - />, - document.getElementById('example') - ); -} + render() { + const { list } = this.context + const { hideDescription } = this.state -function TableTest() { - const list = [ - { name: 'Brian Vaughn', description: 'Software engineer' } - // And so on... - ]; - ReactDOM.render( - list[index]} - > - - -
, - document.getElementById('example') - ); -} + return ( + + {({ width, height }) => ( + + )} + + ) + } -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]; + _rowRenderer({ index, key, style }) { + const { list } = this.context + const row = list.get(index) return (
- {row} + {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}
) } - // Render your list - ReactDOM.render( - - {({ width, height }) => ( - { - const row = list[index]; + _cellSizeAndPositionGetter({ index }) { + const { list } = this.context + const { columnCount } = this.state - return ( -
- {row} -
- ) - }} - width={width} - /> - )} -
, - document.getElementById('example') - ); -} + const columnPosition = index % (columnCount || 1) + const datum = list.get(index % list.size) -function CellMeasurerTest() { - const columnCount = 12; - const rowCount = 3; - const cellRenderer = ({ columnIndex, rowIndex }) => `${rowIndex}, ${columnIndex}`; - const fixedRowHeight = 42; - const height = 12; - const width = 12; + // 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 - ReactDOM.render( - - {({ getColumnWidth }) => ( - - )} - , - document.getElementById('example') - ); -} + this._columnYMap[columnPosition] = y + height + GUTTER_SIZE -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]; + return { + height, + width, + x, + y + } } - function loadMoreRows({ startIndex, stopIndex }: { startIndex: number, stopIndex: number }) { - return new Promise(resolve => resolve(list.push('test'))); + _getColumnCount(cellCount) { + return Math.round(Math.sqrt(cellCount)) } - function rowRenderer({ index, key, style }) { - const content = list[index]; + _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 (
) } - - - // 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 +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) } - 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; + render() { + const { + listHeight, + listRowHeight, + overscanRowCount, + rowCount, + scrollToIndex, + showScrollingPlaceholder, + useDynamicRowHeight + } = this.state + return ( + + {({ width }) => ( + + )} + + ) + } - function mixColors(color1, color2, amount) { - const weight1 = amount - const weight2 = 1 - amount + _getDatum(index) { + const { list } = this.context - 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 list.get(index % list.size) + } - return { r, g, b } - }; + _getRowHeight({ index }) { + return this._getDatum(index).size + } - function renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) { + _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 (
) - }; - 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(' ') + } + _renderLeftSideCell({ columnIndex, key, rowIndex, style }) { return (
{`R${rowIndex}, C${columnIndex}`}
) - }; + } +} - function renderHeaderCell({ columnIndex, key, rowIndex, style }) { - if (columnIndex < 1) { - return +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 } - return renderLeftHeaderCell({ columnIndex, key, rowIndex, style }) - }; - - function renderBodyCell({ columnIndex, key, rowIndex, style }) { - if (columnIndex < 1) { - return - } - - return renderLeftSideCell({ columnIndex, key, rowIndex, style }) + 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) } - return ( - - {({ clientHeight, clientWidth, onScroll, scrollHeight, scrollLeft, scrollTop, scrollWidth }) => { - const x = scrollLeft / (scrollWidth - clientWidth) - const y = scrollTop / (scrollHeight - clientHeight) + render() { + const { + disableHeader, + headerHeight, + height, + hideIndexRow, + overscanRowCount, + rowHeight, + rowCount, + scrollToIndex, + sortBy, + sortDirection, + useDynamicRowHeight + } = this.state - 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 }) => ( -
-
- -
-
- -
-
- )} -
-
-
+ 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 + }) + } } -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} - /> +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} + /> + )} + )} - - )} - , - document.getElementById('example') - ); - // test that onScroll & onResize are optional - ReactDOM.render( - , - document.getElementById('example') - ); + +
+ ) + } + + _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 ac62cf83d8..7e2936975f 100644 --- a/types/react-virtualized/tsconfig.json +++ b/types/react-virtualized/tsconfig.json @@ -19,6 +19,32 @@ }, "files": [ "index.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 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