-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #159 from /issues/156
Version 6.0
- Loading branch information
Showing
21 changed files
with
505 additions
and
192 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') | ||
); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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><div></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> | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
Oops, something went wrong.