Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 6.0 #159

Merged
merged 11 commits into from
Mar 19, 2016
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Examples for each component can be seen in [the documentation](docs/README.md).

Here are some online demos of each component:

* [ArrowKeyStepper](https://bvaughn.github.io/react-virtualized/?component=ArrowKeyStepper)
* [AutoSizer](https://bvaughn.github.io/react-virtualized/?component=AutoSizer)
* [ColumnSizer](https://bvaughn.github.io/react-virtualized/?component=ColumnSizer)
* [FlexTable](https://bvaughn.github.io/react-virtualized/?component=FlexTable)
Expand Down
59 changes: 59 additions & 0 deletions docs/ArrowKeyStepper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
ArrowKeyStepper
---------------

High-order component that decorates another virtualized component and responds to arrow-key events by scrolling one row or column at a time.
This provides a snap-to behavior rather than the default browser scrolling behavior.

Note that unlike the other HOCs in react-virtualized, the `ArrowKeyStepper` adds a `<div>` element around its children in order to attach a key-down event handler.
The appearance of this wrapper element can be customized using the `className` property.

### Prop Types
| Property | Type | Required? | Description |
|:---|:---|:---:|:---|
| children | Function || Function respondible for rendering children. This function should implement the following signature: `({ onKeyDown, onSectionRendered, scrollToColumn, scrollToRow }) => PropTypes.element` |
| className | String | | CSS class name to attach to the wrapper `<div>`. |
| columnsCount | Number || Number of columns in grid; for `FlexTable` and `VirtualScroll` this property should always be `1`. |
| rowsCount | Number || Number of rows in grid. |

### Children function

The child function is passed the following named parameters:

| Parameter | Type | Description |
|:---|:---|:---:|
| onKeyDown | Function | Key-down event handler to be attached to the DOM hierarchy. |
| onSectionRendered | Function | Pass-through callback to be attached to child component; informs the key-stepper which range of cells are currently visible. |
| scrollToColumn | Number | Specifies which column in the child component should be visible |
| scrollToRow | Number | Specifies which row in the child component should be visible |

### Examples

You can decorate any virtualized component (eg. `FlexTable`, `Grid`, or `VirtualScroll`) with arrow-key snapping like so:

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { ArrowKeyStepper, Grid } from 'react-virtualized';
import 'react-virtualized/styles.css'; // only needs to be imported once

ReactDOM.render(
<ArrowKeyStepper
columnsCount={columnsCount}
rowsCount={rowsCount}
>
{({ onKeyDown, onSectionRendered, scrollToColumn, scrollToRow }) => (
<div onKeyDown={onKeyDown}>
<Grid
columnsCount={columnsCount}
onSectionRendered={onSectionRendered}
rowsCount={rowsCount}
scrollToColumn={scrollToColumn}
scrollToRow={scrollToRow}
{...otherGridProps}
/>
</div>
)}
</ArrowKeyStepper>,
document.getElementById('example')
);
```
2 changes: 1 addition & 1 deletion docs/AutoSizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ High-order component that automatically adjusts the width and height of a single
### Prop Types
| Property | Type | Required? | Description |
|:---|:---|:---:|:---|
| children | PropTypes.Element || Function respondible for rendering children. This function should implement the following signature: `({ height, width }) => PropTypes.element` |
| children | Function || Function respondible for rendering children. This function should implement the following signature: `({ height, width }) => PropTypes.element` |
| disableHeight | Boolean | | If true the child's `height` property will not be managed |
| disableWidth | Boolean | | If true the child's `width` property will not be managed |
| onResize | Function | Callback to be invoked on-resize; it is passed the following named parameters: `({ height, width })` |
Expand Down
2 changes: 1 addition & 1 deletion docs/ColumnSizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ High-order component that auto-calculates column-widths for `Grid` cells.
### Prop Types
| Property | Type | Required? | Description |
|:---|:---|:---:|:---|
| children | PropTypes.Element || Function respondible for rendering a virtualized Grid. This function should implement the following signature: `({ adjustedWidth, getColumnWidth, registerChild }) => PropTypes.element` |
| children | Function || Function respondible for rendering a virtualized Grid. This function should implement the following signature: `({ adjustedWidth, getColumnWidth, registerChild }) => PropTypes.element` |
| columnMaxWidth | Number | | Optional maximum allowed column width |
| columnMinWidth | Number | | Optional minimum allowed column width |
| width | Number || Width of Grid or `FlexTable` child |
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Documentation
* [VirtualScroll](VirtualScroll.md)

### High-Order Components
* [ArrowKeyStepper](ArrowKeyStepper.md)
* [AutoSizer](AutoSizer.md)
* [ColumnSizer](ColumnSizer.md)
* [InfiniteLoader](InfiniteLoader.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/ScrollSync.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ High order component that simplifies the process of synchronizing scrolling betw
### Prop Types
| Property | Type | Required? | Description |
|:---|:---|:---:|:---|
| children | PropTypes.Element || Function respondible for rendering 2 or more virtualized components. This function should implement the following signature: `({ onScroll, scrollLeft, scrollTop }) => PropTypes.element` |
| children | Function || Function respondible for rendering 2 or more virtualized components. This function should implement the following signature: `({ onScroll, scrollLeft, scrollTop }) => PropTypes.element` |

### Children function

Expand Down
17 changes: 17 additions & 0 deletions source/ArrowKeyStepper/ArrowKeyStepper.example.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.Grid {
border: 1px solid #e0e0e0;
}

.Cell {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border-right: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
}

.FocusedCell {
background-color: #e0e0e0;
font-weight: bold;
}
100 changes: 100 additions & 0 deletions source/ArrowKeyStepper/ArrowKeyStepper.example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/** @flow */
import Immutable from 'immutable'
import React, { Component, PropTypes } from 'react'
import { ContentBox, ContentBoxHeader, ContentBoxParagraph } from '../demo/ContentBox'
import ArrowKeyStepper from './ArrowKeyStepper'
import AutoSizer from '../AutoSizer'
import Grid from '../Grid'
import shouldPureComponentUpdate from 'react-pure-render/function'
import cn from 'classnames'
import styles from './ArrowKeyStepper.example.css'

export default class ArrowKeyStepperExample extends Component {
shouldComponentUpdate = shouldPureComponentUpdate

static propTypes = {
list: PropTypes.instanceOf(Immutable.List).isRequired
}

constructor (props) {
super(props)

this._getColumnWidth = this._getColumnWidth.bind(this)
this._getRowHeight = this._getRowHeight.bind(this)
this._renderCell = this._renderCell.bind(this)
}

render () {
const { list, ...props } = this.props

return (
<ContentBox {...props}>
<ContentBoxHeader
text='ArrowKeyStepper'
sourceLink='https://github.com/bvaughn/react-virtualized/blob/master/source/ArrowKeyStepper/ArrowKeyStepper.example.js'
docsLink='https://github.com/bvaughn/react-virtualized/blob/master/docs/ArrowKeyStepper.md'
/>

<ContentBoxParagraph>
This high-order component decorates a <code>VirtualScroll</code>, <code>FlexTable</code>, or <code>Grid</code> and responds to arrow-key events by scrolling one row or column at a time.
Focus in the `Grid` below and use the left, right, up, or down arrow keys to move around within the grid.
</ContentBoxParagraph>

<ContentBoxParagraph>
Note that unlike the other HOCs in react-virtualized, the <code>ArrowKeyStepper</code> adds a <code>&lt;div&gt;</code> element around its children in order to attach a key-down event handler.
</ContentBoxParagraph>

<ArrowKeyStepper
columnsCount={100}
rowsCount={100}
>
{({ onSectionRendered, scrollToColumn, scrollToRow }) => (
<div>
<ContentBoxParagraph>
{`Most-recently-stepped column: ${scrollToColumn}, row: ${scrollToRow}`}
</ContentBoxParagraph>

<AutoSizer disableHeight>
{({ width }) => (
<Grid
className={styles.Grid}
columnWidth={this._getColumnWidth}
columnsCount={100}
height={200}
onSectionRendered={onSectionRendered}
renderCell={({ columnIndex, rowIndex }) => this._renderCell({ columnIndex, rowIndex, scrollToColumn, scrollToRow }) }
rowHeight={this._getRowHeight}
rowsCount={100}
scrollToColumn={scrollToColumn}
scrollToRow={scrollToRow}
width={width}
/>
)}
</AutoSizer>
</div>
)}
</ArrowKeyStepper>
</ContentBox>
)
}

_getColumnWidth (index) {
return (1 + (index % 3)) * 60
}

_getRowHeight (index) {
return (1 + (index % 3)) * 30
}

_renderCell ({ columnIndex, rowIndex, scrollToColumn, scrollToRow }) {
const className = cn(styles.Cell, {
[styles.FocusedCell]: columnIndex === scrollToColumn && rowIndex === scrollToRow
})

return (
<div className={className}>
{`r:${rowIndex}, c:${columnIndex}`}
</div>
)
}
}
92 changes: 92 additions & 0 deletions source/ArrowKeyStepper/ArrowKeyStepper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/** @flow */
import React, { Component, PropTypes } from 'react'
import shouldPureComponentUpdate from 'react-pure-render/function'

/**
* This HOC decorates a virtualized component and responds to arrow-key events by scrolling one row or column at a time.
*/
export default class ArrowKeyStepper extends Component {
shouldComponentUpdate = shouldPureComponentUpdate

static propTypes = {
children: PropTypes.func.isRequired,
className: PropTypes.string,
columnsCount: PropTypes.number.isRequired,
rowsCount: PropTypes.number.isRequired
}

constructor (props, context) {
super(props, context)

this.state = {
scrollToColumn: 0,
scrollToRow: 0
}

this._columnStartIndex = 0
this._columnStopIndex = 0
this._rowStartIndex = 0
this._rowStopIndex = 0

this._onKeyDown = this._onKeyDown.bind(this)
this._onSectionRendered = this._onSectionRendered.bind(this)
}

render () {
const { className, children } = this.props
const { scrollToColumn, scrollToRow } = this.state

return (
<div
className={className}
onKeyDown={this._onKeyDown}
>
{children({
onSectionRendered: this._onSectionRendered,
scrollToColumn,
scrollToRow
})}
</div>
)
}

_onKeyDown (event) {
const { columnsCount, rowsCount } = this.props

// The above cases all prevent default event event behavior.
// This is to keep the grid from scrolling after the snap-to update.
switch (event.key) {
case 'ArrowDown':
event.preventDefault()
this.setState({
scrollToRow: Math.min(this._rowStopIndex + 1, rowsCount - 1)
})
break
case 'ArrowLeft':
event.preventDefault()
this.setState({
scrollToColumn: Math.max(this._columnStartIndex - 1, 0)
})
break
case 'ArrowRight':
event.preventDefault()
this.setState({
scrollToColumn: Math.min(this._columnStopIndex + 1, columnsCount - 1)
})
break
case 'ArrowUp':
event.preventDefault()
this.setState({
scrollToRow: Math.max(this._rowStartIndex - 1, 0)
})
break
}
}

_onSectionRendered ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) {
this._columnStartIndex = columnStartIndex
this._columnStopIndex = columnStopIndex
this._rowStartIndex = rowStartIndex
this._rowStopIndex = rowStopIndex
}
}
Loading