Skip to content

Instantly share code, notes, and snippets.

@febret
Last active May 14, 2018 15:44
Show Gist options
  • Save febret/1e4fc7cc0731e45ed6829ca7b2f07b96 to your computer and use it in GitHub Desktop.
Save febret/1e4fc7cc0731e45ed6829ca7b2f07b96 to your computer and use it in GitHub Desktop.
Blog snippets

This gist contains snippets of code used by my blog. 💭 ❤️

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>
);
}
}
// 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