Skip to content

Commit 35ad0c0

Browse files
committed
Merge pull request #159 from /issues/156
Version 6.0
2 parents 40340b0 + b569da7 commit 35ad0c0

21 files changed

Lines changed: 505 additions & 192 deletions

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Examples for each component can be seen in [the documentation](docs/README.md).
5757

5858
Here are some online demos of each component:
5959

60+
* [ArrowKeyStepper](https://bvaughn.github.io/react-virtualized/?component=ArrowKeyStepper)
6061
* [AutoSizer](https://bvaughn.github.io/react-virtualized/?component=AutoSizer)
6162
* [ColumnSizer](https://bvaughn.github.io/react-virtualized/?component=ColumnSizer)
6263
* [FlexTable](https://bvaughn.github.io/react-virtualized/?component=FlexTable)

docs/ArrowKeyStepper.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
ArrowKeyStepper
2+
---------------
3+
4+
High-order component that decorates another virtualized component and responds to arrow-key events by scrolling one row or column at a time.
5+
This provides a snap-to behavior rather than the default browser scrolling behavior.
6+
7+
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.
8+
The appearance of this wrapper element can be customized using the `className` property.
9+
10+
### Prop Types
11+
| Property | Type | Required? | Description |
12+
|:---|:---|:---:|:---|
13+
| children | Function || Function respondible for rendering children. This function should implement the following signature: `({ onKeyDown, onSectionRendered, scrollToColumn, scrollToRow }) => PropTypes.element` |
14+
| className | String | | CSS class name to attach to the wrapper `<div>`. |
15+
| columnsCount | Number || Number of columns in grid; for `FlexTable` and `VirtualScroll` this property should always be `1`. |
16+
| rowsCount | Number || Number of rows in grid. |
17+
18+
### Children function
19+
20+
The child function is passed the following named parameters:
21+
22+
| Parameter | Type | Description |
23+
|:---|:---|:---:|
24+
| onKeyDown | Function | Key-down event handler to be attached to the DOM hierarchy. |
25+
| onSectionRendered | Function | Pass-through callback to be attached to child component; informs the key-stepper which range of cells are currently visible. |
26+
| scrollToColumn | Number | Specifies which column in the child component should be visible |
27+
| scrollToRow | Number | Specifies which row in the child component should be visible |
28+
29+
### Examples
30+
31+
You can decorate any virtualized component (eg. `FlexTable`, `Grid`, or `VirtualScroll`) with arrow-key snapping like so:
32+
33+
```javascript
34+
import React from 'react';
35+
import ReactDOM from 'react-dom';
36+
import { ArrowKeyStepper, Grid } from 'react-virtualized';
37+
import 'react-virtualized/styles.css'; // only needs to be imported once
38+
39+
ReactDOM.render(
40+
<ArrowKeyStepper
41+
columnsCount={columnsCount}
42+
rowsCount={rowsCount}
43+
>
44+
{({ onKeyDown, onSectionRendered, scrollToColumn, scrollToRow }) => (
45+
<div onKeyDown={onKeyDown}>
46+
<Grid
47+
columnsCount={columnsCount}
48+
onSectionRendered={onSectionRendered}
49+
rowsCount={rowsCount}
50+
scrollToColumn={scrollToColumn}
51+
scrollToRow={scrollToRow}
52+
{...otherGridProps}
53+
/>
54+
</div>
55+
)}
56+
</ArrowKeyStepper>,
57+
document.getElementById('example')
58+
);
59+
```

docs/AutoSizer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ High-order component that automatically adjusts the width and height of a single
66
### Prop Types
77
| Property | Type | Required? | Description |
88
|:---|:---|:---:|:---|
9-
| children | PropTypes.Element || Function respondible for rendering children. This function should implement the following signature: `({ height, width }) => PropTypes.element` |
9+
| children | Function || Function respondible for rendering children. This function should implement the following signature: `({ height, width }) => PropTypes.element` |
1010
| disableHeight | Boolean | | If true the child's `height` property will not be managed |
1111
| disableWidth | Boolean | | If true the child's `width` property will not be managed |
1212
| onResize | Function | Callback to be invoked on-resize; it is passed the following named parameters: `({ height, width })` |

docs/ColumnSizer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ High-order component that auto-calculates column-widths for `Grid` cells.
66
### Prop Types
77
| Property | Type | Required? | Description |
88
|:---|:---|:---:|:---|
9-
| children | PropTypes.Element || Function respondible for rendering a virtualized Grid. This function should implement the following signature: `({ adjustedWidth, getColumnWidth, registerChild }) => PropTypes.element` |
9+
| children | Function || Function respondible for rendering a virtualized Grid. This function should implement the following signature: `({ adjustedWidth, getColumnWidth, registerChild }) => PropTypes.element` |
1010
| columnMaxWidth | Number | | Optional maximum allowed column width |
1111
| columnMinWidth | Number | | Optional minimum allowed column width |
1212
| width | Number || Width of Grid or `FlexTable` child |

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Documentation
1010
* [VirtualScroll](VirtualScroll.md)
1111

1212
### High-Order Components
13+
* [ArrowKeyStepper](ArrowKeyStepper.md)
1314
* [AutoSizer](AutoSizer.md)
1415
* [ColumnSizer](ColumnSizer.md)
1516
* [InfiniteLoader](InfiniteLoader.md)

docs/ScrollSync.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ High order component that simplifies the process of synchronizing scrolling betw
66
### Prop Types
77
| Property | Type | Required? | Description |
88
|:---|:---|:---:|:---|
9-
| children | PropTypes.Element || Function respondible for rendering 2 or more virtualized components. This function should implement the following signature: `({ onScroll, scrollLeft, scrollTop }) => PropTypes.element` |
9+
| children | Function || Function respondible for rendering 2 or more virtualized components. This function should implement the following signature: `({ onScroll, scrollLeft, scrollTop }) => PropTypes.element` |
1010

1111
### Children function
1212

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.Grid {
2+
border: 1px solid #e0e0e0;
3+
}
4+
5+
.Cell {
6+
height: 100%;
7+
display: flex;
8+
align-items: center;
9+
justify-content: center;
10+
border-right: 1px solid #e0e0e0;
11+
border-bottom: 1px solid #e0e0e0;
12+
}
13+
14+
.FocusedCell {
15+
background-color: #e0e0e0;
16+
font-weight: bold;
17+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/** @flow */
2+
import Immutable from 'immutable'
3+
import React, { Component, PropTypes } from 'react'
4+
import { ContentBox, ContentBoxHeader, ContentBoxParagraph } from '../demo/ContentBox'
5+
import ArrowKeyStepper from './ArrowKeyStepper'
6+
import AutoSizer from '../AutoSizer'
7+
import Grid from '../Grid'
8+
import shouldPureComponentUpdate from 'react-pure-render/function'
9+
import cn from 'classnames'
10+
import styles from './ArrowKeyStepper.example.css'
11+
12+
export default class ArrowKeyStepperExample extends Component {
13+
shouldComponentUpdate = shouldPureComponentUpdate
14+
15+
static propTypes = {
16+
list: PropTypes.instanceOf(Immutable.List).isRequired
17+
}
18+
19+
constructor (props) {
20+
super(props)
21+
22+
this._getColumnWidth = this._getColumnWidth.bind(this)
23+
this._getRowHeight = this._getRowHeight.bind(this)
24+
this._renderCell = this._renderCell.bind(this)
25+
}
26+
27+
render () {
28+
const { list, ...props } = this.props
29+
30+
return (
31+
<ContentBox {...props}>
32+
<ContentBoxHeader
33+
text='ArrowKeyStepper'
34+
sourceLink='https://github.com/bvaughn/react-virtualized/blob/master/source/ArrowKeyStepper/ArrowKeyStepper.example.js'
35+
docsLink='https://github.com/bvaughn/react-virtualized/blob/master/docs/ArrowKeyStepper.md'
36+
/>
37+
38+
<ContentBoxParagraph>
39+
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.
40+
Focus in the `Grid` below and use the left, right, up, or down arrow keys to move around within the grid.
41+
</ContentBoxParagraph>
42+
43+
<ContentBoxParagraph>
44+
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.
45+
</ContentBoxParagraph>
46+
47+
<ArrowKeyStepper
48+
columnsCount={100}
49+
rowsCount={100}
50+
>
51+
{({ onSectionRendered, scrollToColumn, scrollToRow }) => (
52+
<div>
53+
<ContentBoxParagraph>
54+
{`Most-recently-stepped column: ${scrollToColumn}, row: ${scrollToRow}`}
55+
</ContentBoxParagraph>
56+
57+
<AutoSizer disableHeight>
58+
{({ width }) => (
59+
<Grid
60+
className={styles.Grid}
61+
columnWidth={this._getColumnWidth}
62+
columnsCount={100}
63+
height={200}
64+
onSectionRendered={onSectionRendered}
65+
renderCell={({ columnIndex, rowIndex }) => this._renderCell({ columnIndex, rowIndex, scrollToColumn, scrollToRow }) }
66+
rowHeight={this._getRowHeight}
67+
rowsCount={100}
68+
scrollToColumn={scrollToColumn}
69+
scrollToRow={scrollToRow}
70+
width={width}
71+
/>
72+
)}
73+
</AutoSizer>
74+
</div>
75+
)}
76+
</ArrowKeyStepper>
77+
</ContentBox>
78+
)
79+
}
80+
81+
_getColumnWidth (index) {
82+
return (1 + (index % 3)) * 60
83+
}
84+
85+
_getRowHeight (index) {
86+
return (1 + (index % 3)) * 30
87+
}
88+
89+
_renderCell ({ columnIndex, rowIndex, scrollToColumn, scrollToRow }) {
90+
const className = cn(styles.Cell, {
91+
[styles.FocusedCell]: columnIndex === scrollToColumn && rowIndex === scrollToRow
92+
})
93+
94+
return (
95+
<div className={className}>
96+
{`r:${rowIndex}, c:${columnIndex}`}
97+
</div>
98+
)
99+
}
100+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/** @flow */
2+
import React, { Component, PropTypes } from 'react'
3+
import shouldPureComponentUpdate from 'react-pure-render/function'
4+
5+
/**
6+
* This HOC decorates a virtualized component and responds to arrow-key events by scrolling one row or column at a time.
7+
*/
8+
export default class ArrowKeyStepper extends Component {
9+
shouldComponentUpdate = shouldPureComponentUpdate
10+
11+
static propTypes = {
12+
children: PropTypes.func.isRequired,
13+
className: PropTypes.string,
14+
columnsCount: PropTypes.number.isRequired,
15+
rowsCount: PropTypes.number.isRequired
16+
}
17+
18+
constructor (props, context) {
19+
super(props, context)
20+
21+
this.state = {
22+
scrollToColumn: 0,
23+
scrollToRow: 0
24+
}
25+
26+
this._columnStartIndex = 0
27+
this._columnStopIndex = 0
28+
this._rowStartIndex = 0
29+
this._rowStopIndex = 0
30+
31+
this._onKeyDown = this._onKeyDown.bind(this)
32+
this._onSectionRendered = this._onSectionRendered.bind(this)
33+
}
34+
35+
render () {
36+
const { className, children } = this.props
37+
const { scrollToColumn, scrollToRow } = this.state
38+
39+
return (
40+
<div
41+
className={className}
42+
onKeyDown={this._onKeyDown}
43+
>
44+
{children({
45+
onSectionRendered: this._onSectionRendered,
46+
scrollToColumn,
47+
scrollToRow
48+
})}
49+
</div>
50+
)
51+
}
52+
53+
_onKeyDown (event) {
54+
const { columnsCount, rowsCount } = this.props
55+
56+
// The above cases all prevent default event event behavior.
57+
// This is to keep the grid from scrolling after the snap-to update.
58+
switch (event.key) {
59+
case 'ArrowDown':
60+
event.preventDefault()
61+
this.setState({
62+
scrollToRow: Math.min(this._rowStopIndex + 1, rowsCount - 1)
63+
})
64+
break
65+
case 'ArrowLeft':
66+
event.preventDefault()
67+
this.setState({
68+
scrollToColumn: Math.max(this._columnStartIndex - 1, 0)
69+
})
70+
break
71+
case 'ArrowRight':
72+
event.preventDefault()
73+
this.setState({
74+
scrollToColumn: Math.min(this._columnStopIndex + 1, columnsCount - 1)
75+
})
76+
break
77+
case 'ArrowUp':
78+
event.preventDefault()
79+
this.setState({
80+
scrollToRow: Math.max(this._rowStartIndex - 1, 0)
81+
})
82+
break
83+
}
84+
}
85+
86+
_onSectionRendered ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) {
87+
this._columnStartIndex = columnStartIndex
88+
this._columnStopIndex = columnStopIndex
89+
this._rowStartIndex = rowStartIndex
90+
this._rowStopIndex = rowStopIndex
91+
}
92+
}

0 commit comments

Comments
 (0)