Skip to content

Commit

Permalink
Merge pull request #159 from /issues/156
Browse files Browse the repository at this point in the history
Version 6.0
  • Loading branch information
bvaughn committed Mar 19, 2016
2 parents 40340b0 + b569da7 commit 35ad0c0
Show file tree
Hide file tree
Showing 21 changed files with 505 additions and 192 deletions.
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

0 comments on commit 35ad0c0

Please sign in to comment.