This gist contains snippets of code used by my blog. 💭 ❤️
Last active
May 14, 2018 15:44
-
-
Save febret/1e4fc7cc0731e45ed6829ca7b2f07b96 to your computer and use it in GitHub Desktop.
Blog snippets
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
import React from 'react'; | |
import {isFunction} from 'lodash'; | |
import defaultStyles from './grid.scss'; | |
/** | |
* Implements a generic grid component | |
* @prop data - an array of data items that the grid will render | |
* @prop config - grid configuration object | |
* The configuration object has two sections | |
* table - contains table-wide configuration settings: | |
* autoPointer - if set to true, cells and headings with an onClick handler set | |
* will have cursor style switch to pointer automatically. Default: true | |
* styles - the styles object to use to style this table | |
* tableClass - class name for the entire table | |
* tableStyle - object with additional styles for the table | |
* headingRowClass / headingRowStyle - class name / style object for the heading row | |
* contentClass/contentStyle - class name for the content section of the table | |
* rowClass / rowStyle - class name / style object for a table row, or a | |
* function (d, i) returing a class name / style object where: | |
* d - the data object for the current row from the data array | |
* i - the index of the data object | |
* columns - an array of objects containing each a column definition as follows: | |
* headingClass / headingStyle - class name / style object for the column | |
* heading or a function (d, i) returing a class name / style object where: | |
* d - the column definition | |
* i - the column definition index in the columns array | |
* NOTE: If no heading style is present, cellStyle will be used instead | |
* onHeadingClick - a function handling clicks on the heading with the following args: | |
* d - the column definition | |
* i - the column definition index | |
* evt - the click event | |
* label - the label to use for the heading | |
* headingRenderer - a function returning jsx for the heading with the following args | |
* d - the column definition | |
* i - the column definition index | |
* NOTE: if headingRenderer is present, label won't be used | |
* field - the field name from the row object to use for this column | |
* cellClass / cellStyle - class name / style object for a cell in this column | |
* or function(value, c, j, d, i) returning a class name / style object: | |
* value - value from row object field key | |
* c - column definition | |
* j - column index | |
* d - row object | |
* i - row index | |
* onClick - function(value, d, i, c, j) handling clicks on the cell with | |
* arguments same as above. | |
* cellRenderer - function(value, d, i, c, j) to render the cell with | |
* arguments same as above. If this function is not present, cell will render | |
* field from the row data object. | |
*/ | |
export default class Grid extends React.PureComponent { | |
render() { | |
const {config: {columns, table}, data} = this.props; | |
const styles = table.styles || defaultStyles; | |
const autoPointer = 'autoPointer' in table ? table.autoPointer : true; | |
return ( | |
<div | |
className={table.tableClass || styles['table']} | |
style={table.tableStyle || {}} | |
> | |
<div | |
className={table.headingRowClass || styles['table-heading-row']} | |
style={table.headingRowStyle || {}} | |
> | |
{columns && columns.map((d, i) => { | |
let headingClass = styles['table-heading-column']; | |
if (d.headingClass) { | |
headingClass = isFunction(d.headingClass) ? d.headingClass(d, i) : d.headingClass; | |
} | |
// Headings use cell style first, if available, this way configs don't | |
// need to repeat same style twice if no special styling is needed | |
// for headings. | |
let headingStyle = {}; | |
if (d.cellStyle) { | |
headingStyle = isFunction(d.cellStyle) ? d.cellStyle(d, i) : {...d.cellStyle}; | |
} | |
if (d.headingStyle) { | |
headingStyle = isFunction(d.headingStyle) ? d.headingStyle(d, i) : {...d.headingStyle}; | |
} | |
if (autoPointer) { | |
headingStyle.cursor = d.onHeadingClick ? 'pointer' : 'default'; | |
} | |
return ( | |
<div | |
className={headingClass} | |
style={headingStyle} | |
key={`col-${i}`} | |
onClick={(evt) => d.onHeadingClick && d.onHeadingClick(d, i, evt)} | |
> | |
{d.headingRenderer ? d.headingRenderer(d, i) : d.label} | |
</div> | |
); | |
})} | |
</div> | |
<div | |
className={table.contentClass || styles['table-content']} | |
style={table.contentStyle || {}} | |
> | |
{data && data.map((d, i) => { | |
let rowClass = styles['table-row']; | |
if (table.rowClass) { | |
rowClass = isFunction(table.rowClass) ? table.rowClass(d, i) : table.rowClass; | |
} | |
let rowStyle = {}; | |
if (table.rowStyle) { | |
rowStyle = isFunction(table.rowStyle) ? table.rowStyle(d, i) : table.rowStyle; | |
} | |
return ( | |
<div | |
className={rowClass} | |
style={rowStyle} | |
key={`row-${i}`} | |
> | |
{columns && columns.map((c, j) => { | |
let cellClass = styles['table-cell']; | |
if (c.cellClass) { | |
cellClass = isFunction(c.cellClass) ? c.cellClass(d[c.field], c, j, d, i) : c.cellClass; | |
} | |
let cellStyle = {}; | |
if (c.cellStyle) { | |
cellStyle = isFunction(c.cellStyle) ? c.cellStyle(d[c.field], c, j, d, i) : {...c.cellStyle}; | |
} | |
if (autoPointer) { | |
cellStyle.cursor = c.onClick ? 'pointer' : 'default'; | |
} | |
return ( | |
<div | |
className={cellClass} | |
style={cellStyle} | |
key={`cell-${i}-${j}`} | |
onClick={(evt) => c.onClick && c.onClick(d[c.field], d, i, c, j, evt)} | |
> | |
{c.cellRenderer ? c.cellRenderer(d[c.field], d, i, c, j) : d[c.field]} | |
</div> | |
); | |
})} | |
</div> | |
); | |
})} | |
</div> | |
</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
// Render using local variable / function fragments | |
render() { | |
const header = (<div>I'm a header!</div>); | |
const renderContent = (subject) => ( | |
<div> | |
<h1>{`content for subject ${subject}`}</h1> | |
<div>{this.props.content[subject]}</div> | |
</div>); | |
return ( | |
<div className="container"> | |
<div className="header"> | |
{header} | |
</div> | |
<div className="content"> | |
{renderContent('foo')} | |
{renderContent('bar')} | |
{renderContent('baz')} | |
</div> | |
</div> | |
) | |
} | |
// Render using local stateless components | |
render() { | |
const Header = (<div>I'm a header!</div>); | |
const Content = (subject) => ( | |
<div> | |
<h1>{`content for subject ${subject}`}</h1> | |
<div>{this.props.content[subject]}</div> | |
</div>); | |
return ( | |
<div className="container"> | |
<div className="header"> | |
<Header /> | |
</div> | |
<div className="content"> | |
<Content subject="foo" /> | |
<Content subject="bar" /> | |
<Content subject="baz" /> | |
</div> | |
</div> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment