Last active
August 16, 2017 21:44
-
-
Save ardok/4aa9500f5dae3b462427b7cd54404176 to your computer and use it in GitHub Desktop.
Fixed Data Table 2 Wrapper to have fixed right columns!
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
/* eslint-disable no-return-assign */ | |
import React, {Component} from 'react'; | |
import debounce from 'debounce'; | |
import {Table, Column} from 'fixed-data-table-2'; | |
function setHeadersFixed(containerEl) { | |
const els = containerEl.getElementsByClassName('fixedDataTableLayout_header'); | |
[].forEach.call(els, (el) => { | |
const parentNode = el.parentNode; | |
parentNode.style.position = 'fixed'; | |
parentNode.style.top = 0; | |
}); | |
} | |
function resetHeadersFixed(containerEl) { | |
const els = containerEl.getElementsByClassName('fixedDataTableLayout_header'); | |
[].forEach.call(els, (el) => { | |
const parentNode = el.parentNode; | |
parentNode.style.position = 'inherit'; | |
}); | |
} | |
const scrollbarWidth = 17; | |
const debounceTimeout = 250; | |
/* | |
This table will have height to fit the entire rows. So expect no vertical scrolling. | |
*/ | |
export default class FixedDataTableWrapper extends Component { | |
props: { | |
rowHeight: number, | |
headerHeight: number, | |
rowsCount: number, | |
width?: number, | |
rowData: Array<{[columnKey: string]: mixed}>, | |
// This is @ardo invention, to make headers fixed | |
fixedHeaders?: boolean, | |
columns: Array<{ | |
columnKey: string, | |
header: string|React$Element<*>|React$Component<*, *, *>, | |
cell: string|React$Element<*>|React$Component<*, *, *>, | |
width: number, | |
allowCellsRecycling: boolean, | |
pureRendering: boolean, | |
// Default `fixed` is for left fixed | |
fixed: boolean, | |
// This is @ardo invention, to make it fixed on right side | |
fixedRight: boolean, | |
}>, | |
}; | |
state: { | |
tableWidth: number, | |
tableHeight: number, | |
}; | |
constructor(props) { | |
super(props); | |
this.state = { | |
tableWidth: 0, | |
tableHeight: 0, | |
}; | |
this.containerEl = null; | |
} | |
componentDidMount() { | |
const {fixedHeaders} = this.props; | |
window.addEventListener('resize', this.onResize, false); | |
if (fixedHeaders) { | |
window.addEventListener('scroll', this.onScroll, false); | |
} | |
setTimeout(() => { | |
this.onResize(); | |
this.onScroll(); | |
}, debounceTimeout); | |
} | |
componentWillUnmount() { | |
window.removeEventListener('resize', this.onResize); | |
if (this.props.fixedHeaders) { | |
window.removeEventListener('scroll', this.onScroll); | |
} | |
} | |
onResize = debounce(() => { | |
const {width, rowData, rowHeight, headerHeight} = this.props; | |
const nextState = {}; | |
if (width === undefined) { | |
nextState.tableWidth = this.containerEl.offsetWidth; | |
} | |
nextState.tableHeight = rowData.length * rowHeight + headerHeight + scrollbarWidth; | |
this.setState(nextState); | |
}, debounceTimeout); | |
onScroll = debounce(() => { | |
const {headerHeight} = this.props; | |
const containerTop = this.containerEl.offsetTop; | |
const scrollTop = document.body.scrollTop; | |
if (scrollTop > containerTop && | |
scrollTop < (containerTop + this.containerEl.offsetHeight - headerHeight - scrollbarWidth)) { | |
// Only make it fixed if the scroll is in between of the table element | |
setHeadersFixed(this.containerEl); | |
} else { | |
resetHeadersFixed(this.containerEl); | |
} | |
}, debounceTimeout); | |
getTotalFixedRightColsWidth() { | |
return this.props.columns.reduce((final, {fixedRight, width}) => ( | |
fixedRight ? (final + width) : final | |
), 0); | |
} | |
buildColumns() { | |
const {columns} = this.props; | |
return columns.reduce((final, col) => { | |
if (!col.fixedRight) { | |
final.push( | |
<Column key={col.columnKey} {...col} /> | |
); | |
} | |
return final; | |
}, []); | |
} | |
buildFixedRightTable(totalFixedRightColsWidth) { | |
const {tableHeight} = this.state; | |
/* eslint-disable no-unused-vars */ | |
const {rowData, columns, ...otherProps} = this.props; | |
/* eslint-enable no-unused-vars */ | |
// Find the fixedRight | |
const rightFixedCols = columns.reduce((final, col) => { | |
const {fixedRight, ...rest} = col; | |
if (fixedRight) { | |
final.push( | |
<Column key={col.columnKey} {...rest} /> | |
); | |
} | |
return final; | |
}, []); | |
if (rightFixedCols.length === 0) { | |
return null; | |
} | |
return ( | |
<Table {...otherProps} height={tableHeight} width={totalFixedRightColsWidth || this.getTotalFixedRightColsWidth()}> | |
{rightFixedCols} | |
</Table> | |
); | |
} | |
render() { | |
/* eslint-disable no-unused-vars */ | |
const {rowData, columns, ...otherProps} = this.props; | |
/* eslint-enable no-unused-vars */ | |
const {tableWidth, tableHeight} = this.state; | |
const totalFixedRightColsWidth = this.getTotalFixedRightColsWidth(); | |
return ( | |
<div ref={(c) => this.containerEl = c} style={{display: 'flex'}}> | |
<Table {...otherProps} width={tableWidth - totalFixedRightColsWidth} height={tableHeight}> | |
{this.buildColumns()} | |
</Table> | |
{this.buildFixedRightTable(totalFixedRightColsWidth)} | |
</div> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment