diff --git a/src/components/lazy-rendered-list.jsx b/src/components/lazy-rendered-list.jsx
new file mode 100644
index 000000000..29ca468de
--- /dev/null
+++ b/src/components/lazy-rendered-list.jsx
@@ -0,0 +1,83 @@
+import React, {Component, PropTypes} from 'react'
+import {findDOMNode} from 'react-dom'
+
+
+const MIN_RANGE_SIZE = 2
+
+function getRange({total, itemHeight, containerHeight, scrollTop}) {
+ const itemsPerBody = Math.floor((containerHeight) / itemHeight);
+ const start = Math.max(0, Math.floor(scrollTop / itemHeight) - (itemsPerBody * 2));
+ const end = Math.max(MIN_RANGE_SIZE, Math.min(start + (4 * itemsPerBody), total));
+ return {start, end}
+}
+
+class LazyRenderedList extends Component {
+ static propTypes = {
+ items: PropTypes.array,
+ itemHeight: PropTypes.number,
+ containerHeight: PropTypes.number,
+ BufferTag: PropTypes.string,
+ ItemRenderer: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
+ RootRenderer: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
+ }
+
+ static defaultProps = {
+ itemHeight: 30,
+ containerHeight: 150,
+ BufferTag: 'div',
+ }
+
+ constructor(props) {
+ super(props)
+ this.state = {start: 0, end: MIN_RANGE_SIZE}
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.updateRangeState(nextProps)
+ }
+
+ onScroll() {
+ this.updateRangeState(this.props)
+ }
+
+ updateRangeState({itemHeight, items, containerHeight}) {
+ const {scrollTop} = findDOMNode(this)
+ this.setState(getRange({total: items.length, itemHeight, containerHeight, scrollTop}))
+ }
+
+ renderItems() {
+ const {items, itemHeight, BufferTag, ItemRenderer} = this.props
+ const {start, end} = this.state
+ const topHeight = start * itemHeight
+ const bottomHeight = (items.length - end) * itemHeight
+
+ const top =
+ const bottom =
+ const elements = items.slice(start, end).map((item, idx) => (
+
+ ))
+ elements.unshift(top)
+ elements.push(bottom)
+
+ return elements
+ }
+
+ render() {
+ const {RootRenderer, containerHeight} = this.props
+ return (
+
+ {this.renderItems()}
+
+ )
+ }
+}
+
+
+export default LazyRenderedList
diff --git a/src/components/selectable-table.jsx b/src/components/selectable-table.jsx
index 0282ba275..cc809da85 100644
--- a/src/components/selectable-table.jsx
+++ b/src/components/selectable-table.jsx
@@ -13,8 +13,8 @@ export class SelectableCell extends Component {
static propTypes = {
className: PropTypes.string,
tableData: Table.propTypes.tableData,
- rowIdx: TableCell.propTypes.rowIdx,
- colIdx: TableCell.propTypes.colIdx,
+ rowIdx: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ colIdx: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
selection: PropTypes.object,
onSetSelection: PropTypes.func.isRequired,
}
diff --git a/src/components/table.jsx b/src/components/table.jsx
index 50c8d25ba..5574179b8 100644
--- a/src/components/table.jsx
+++ b/src/components/table.jsx
@@ -1,47 +1,28 @@
import _ from 'underscore'
import classnames from 'classnames'
import React, {Component, PropTypes} from 'react'
+import LazyRenderedList from './lazy-rendered-list'
-// TODO Ugh gross. Use flow
-const RowDataType = PropTypes.arrayOf(PropTypes.node)
const RendererType = PropTypes.oneOfType([PropTypes.func, PropTypes.string])
const IndexType = PropTypes.oneOfType([PropTypes.number, PropTypes.string])
const TablePropTypes = {
idx: IndexType,
renderer: RendererType,
tableData: PropTypes.shape({
- rows: PropTypes.arrayOf(RowDataType),
+ rows: PropTypes.array,
}),
}
-
-export class TableCell extends Component {
-
- static propTypes = {
- className: PropTypes.string,
- isHeader: PropTypes.bool,
- tableData: TablePropTypes.tableData.isRequired,
- rowIdx: TablePropTypes.idx.isRequired,
- colIdx: TablePropTypes.idx.isRequired,
- }
-
- static defaultProps = {
- className: '',
- }
-
- render() {
- const {className, isHeader, children, ...props} = this.props
- const CellTag = isHeader ? 'th' : 'td'
- return (
-
- {children}
-
- )
- }
+export function TableCell({className = '', isHeader, children, ...props}) {
+ const CellTag = isHeader ? 'th' : 'td'
+ return (
+
+ {children}
+
+ )
}
-
export class TableRow extends Component {
static propTypes = {
@@ -102,6 +83,8 @@ export default class Table extends Component {
className: PropTypes.string,
displayHeader: PropTypes.bool,
displayNumbers: PropTypes.bool,
+ rowHeight: PropTypes.number,
+ bodyHeight: PropTypes.number,
tableData: TablePropTypes.tableData.isRequired,
extraProps: PropTypes.object,
RowRenderer: TablePropTypes.renderer,
@@ -116,10 +99,10 @@ export default class Table extends Component {
}
renderBody() {
- const {tableData, displayNumbers, displayHeader, extraProps, RowRenderer, CellRenderer} = this.props
+ const {tableData, rowHeight, bodyHeight, displayNumbers, displayHeader, extraProps, RowRenderer, CellRenderer} = this.props
const rows = displayHeader ? tableData.rows.slice(1) : tableData.rows
- const rowElements = rows.map((row, idx) => {
+ const itemRenderer = ({idx}) => {
const rowIdx = displayHeader ? idx + 1 : idx;
return (
)
- })
+ }
return (
-
- {rowElements}
-
+
)
}
@@ -161,10 +149,10 @@ export default class Table extends Component {
}
render() {
- const {className} = this.props
+ const {className, ...otherProps} = this.props
return (
-
+
{this.renderHeader()}
{this.renderBody()}
diff --git a/src/pro b/src/pro
index 91b58e912..a79583931 160000
--- a/src/pro
+++ b/src/pro
@@ -1 +1 @@
-Subproject commit 91b58e912a7f2d9d68632eb2b434ba185af352ba
+Subproject commit a795839311c962f5e84fe29b753e91a1949f6999
diff --git a/static/components/table.less b/static/components/table.less
index a0cbdd89c..036ae577a 100644
--- a/static/components/table.less
+++ b/static/components/table.less
@@ -7,7 +7,12 @@
.nylas-table {
height: 100%;
width: 100%;
- overflow: scroll;
+ overflow-y: hidden;
+ overflow-x: scroll;
+
+ thead, tbody {
+ display: block;
+ }
.table-row {