diff --git a/package.json b/package.json index 1f37722..7c48a1f 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "dependencies": { "classnames": "^2.2.3", "object-assign": "*", - "react": "^0.14.0" + "react": "^0.14.0", + "recompose": "^0.15.0" } } diff --git a/src/column.js b/src/column.js index 8a31bcf..546e2eb 100644 --- a/src/column.js +++ b/src/column.js @@ -1,89 +1,65 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import classnames from 'classnames'; +import { compose, shouldUpdate, getContext, mapProps } from 'recompose'; -import { getStyleProperties } from './utils/styleHelper'; +const Column = compose( + //Only update if forceUpdate is true or the values don't match + shouldUpdate(({ value }, nextProps) => (nextProps.value !== value || nextProps.forceUpdate === true )), -class Column extends React.Component { - constructor(props, context) { - super(props, context); - } + //We are using the following contexts: + getContext({ utils: PropTypes.object }), - shouldComponentUpdate(nextProps) { - if(this.props.forceUpdate) { return true; } - if(this.props.value === nextProps.value) { - return false; - } + //Build new props in addition to the ones that are passed in + mapProps(props => ({ + classNames: classnames(props.utils.getStyleProperties(props, 'column'), props.cssClassName), - return true; - } - - render() { - //TODO: this is temporary -- we'll need to merge styles or something - // why not use the getStyle from defaultStyles? - const styles = this._getStyles(); - - const { className } = getStyleProperties(this.props, 'column'); - const classNames = classnames(className, this.props.cssClassName); - - return ( - - {this.props.hasOwnProperty('customComponent') ? - : - this.props.value} - - ); - } - - //TODO: Figure out a way to get this hooked up with the normal styles methods - //maybe a merge styles property or something along those lines - _getStyles = () => { - const style = this.props.styles.getStyle({ - styles: this.props.styles.inlineStyles, + //This is the inline styles object to use + columnStyles: props.styles.getStyle({ + styles: props.styles.inlineStyles, styleName: 'column', - //todo: make this nicer mergeStyles: { - ...((this.props.width || this.props.alignment || this.props.styles) ? - Object.assign({ width: this.props.width || null, textAlign: this.props.alignment }) : {}), - ...this.props.style + ...((props.width || props.alignment || props.styles) ? + Object.assign({ width: props.width || null, + textAlign: props.alignment }) : {}) } - }); + }), - return style; - } + //Click callback + handleClick: (e) => { + if (props.onClick) { props.onClick(e) }; - _handleClick = (e) => { - if (this.props.onClick) this.props.onClick(e); + props.events.columnClick(props.dataKey, props.value, props.rowIndex, props.rowData); + }, - this.props.events.columnClick(this.props.dataKey, this.props.value, this.props.rowIndex, this.props.rowData); - } + //hover callback + handleHover: (e) => { + props.events.columnHover(props.dataKey, props.value, props.rowIndex, props.rowData); + }, - _handleHover = (e) => { - this.props.events.columnHover(this.props.dataKey, this.props.value, this.props.rowIndex, this.props.rowData); - } -} + columnValue: (props.hasOwnProperty('customComponent') ? + : + props.value), -Column.defaultProps = { - columnProperties: { - cssClassName: '' - } -}; + //Return all the props + ...props + })) +)(({ columnValue, handleHover, handleClick, classNames, columnStyles, dataKey, rowIndex }) => ( + + {columnValue} + -Column.propTypes = { - alignment: React.PropTypes.oneOf(['left', 'right', 'center']), - columnHover: React.PropTypes.func, - columnClick: React.PropTypes.func -}; +)) export default Column; diff --git a/src/defaultSettings.js b/src/defaultSettings.js index 25a32d4..0dac162 100644 --- a/src/defaultSettings.js +++ b/src/defaultSettings.js @@ -2,5 +2,6 @@ export default { useGriddleStyles: true, useGriddleClassNames: false, useFixedTable: true, - pageSize: 10 + pageSize: 10, + filterPlaceholderText: "Filter" } diff --git a/src/filter.js b/src/filter.js index dfe1587..ce2d61b 100644 --- a/src/filter.js +++ b/src/filter.js @@ -1,36 +1,41 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import { getStyleProperties } from './utils/styleHelper'; -class Filter extends React.Component { - constructor(props, context) { - super(props, context); - - this._handleChange = this._handleChange.bind(this); - } - - shouldComponentUpdate(props) { - return false; - } - - render() { - const {style, className } = getStyleProperties(this.props, 'filter'); - - return ( - - ); - } - - _handleChange = (e) => { - //TODO: debounce this - this.props.events.setFilter(e.target.value); - } -} +import { compose, shouldUpdate, getContext, mapProps } from 'recompose'; + +const Filter = compose( + //this should not update + shouldUpdate(() => (false)), + + //we are using the utils object from context + getContext({ utils: PropTypes.object }), + + //Get styleProperties for the next mapProps + mapProps((props) => ({ + styleProperties: props.utils.getStyleProperties(props, 'filter'), + + ...props + })), + + mapProps((props) => ({ + handleChange: ((e) => { props.events.setFilter(e.target.value) }), + + style: props.styleProperties.style, + + className: props.styleProperties.className, + + placeholder: props.settings.filterPlaceholderText || "Filter", + })) +)(({className, style, handleChange, placeholder}) => ( + +)); Filter.propTypes = { setFilter: React.PropTypes.func diff --git a/src/griddle.js b/src/griddle.js index 18b4d16..51517a1 100644 --- a/src/griddle.js +++ b/src/griddle.js @@ -5,8 +5,14 @@ import * as defaultModules from './defaultModules'; import { getAssignedStyles } from './defaultStyles'; import * as defaultSettings from './defaultSettings'; import { arraysEqual } from './utils/arrayHelper'; +import { getStyleProperties } from './utils/styleHelper'; +import ColumnHelper from './utils/column-helper'; export default class Griddle extends React.Component { + static childContextTypes = { + utils: React.PropTypes.object + } + constructor(props, context) { super(props, context); @@ -14,6 +20,24 @@ export default class Griddle extends React.Component { this.state = { showSettings: false }; } + getChildContext() { + return { + utils: { + getStyleProperties, + isColumnVisible: ColumnHelper.isColumnVisible, + getColumnPropertyObject: ColumnHelper.getColumnPropertyObject, + arraysEqual: arraysEqual, + getOriginalRowData: (rowIndex) => { + return this.props.state.data[rowIndex] + }, + getMetadata: (rowIndex) => { + const row = this.props.data[rowIndex]; + return row ? row.__metadata : {} + } + } + }; + } + wireUpSettings = (props) => { this.settings = Object.assign({}, defaultSettings, props.settings); this.components = Object.assign({}, defaultModules, props.components); @@ -50,6 +74,7 @@ export default class Griddle extends React.Component { const events = this.getEvents(); const components = this.getComponents(); const { styles, settings } = this; + return (
{/*TODO: Lets not duplicate these prop defs all over (events/components) */} diff --git a/src/loading.js b/src/loading.js index 98a2710..9f6b0ea 100644 --- a/src/loading.js +++ b/src/loading.js @@ -1,20 +1,28 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import {getStyleProperties} from './utils/styleHelper'; -class Loading extends React.Component { - render() { - const { style, className } = getStyleProperties(this.props, 'loading'); +import { compose, getContext, mapProps } from 'recompose'; - return ( - - -
-

Loading...

-
- - - ); - } -} +const Loading = compose( + getContext({ utils: PropTypes.object }), + + mapProps(props => ({ + styleProperties: props.utils.getStyleProperties(props, 'loading'), + ...props + })), + + mapProps(props => ({ + style: props.styleProperties.style, + className: props.styleProperties.className + })) +)(({ style, className }) => ( + + +
+

Loading...

+
+ + +)) export default Loading; diff --git a/src/no-results.js b/src/no-results.js index 7d7eb8d..ac294a1 100644 --- a/src/no-results.js +++ b/src/no-results.js @@ -1,16 +1,24 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import {getStyleProperties} from './utils/styleHelper'; -class NoResults extends React.Component { - render() { - const { style, className } = getStyleProperties(this.props, 'noResults'); +import { compose, getContext, mapProps } from 'recompose'; - return ( -
-

No results found.

-
- ) - } -} +const NoResults = compose( + getContext({ utils: PropTypes.object }), + + mapProps(props => ({ + styleProperties: props.utils.getStyleProperties(props, 'noResults'), + ...props + })), + + mapProps(props => ({ + style: props.styleProperties.style, + className: props.styleProperties.className + })) +)(({ style, className }) => ( +
+

No results found.

+
+)) export default NoResults; diff --git a/src/pagination.js b/src/pagination.js index d8cb2cb..f9149bd 100644 --- a/src/pagination.js +++ b/src/pagination.js @@ -1,38 +1,47 @@ -import React from 'react' +import React, { PropTypes } from 'react' import { getStyleProperties } from './utils/styleHelper'; -class Pagination extends React.Component { - constructor(props, context) { - super(props, context); +import { compose, getContext, mapProps } from 'recompose'; - this._handleChange = this._handleChange.bind(this); - } - - render() { - const {style, className } = getStyleProperties(this.props, 'pagination'); +function getPageNumberDropdown(props) { + if(!props.pageProperties || !props.pageProperties.maxPage ) { return; } - return (
- {this.props.hasPrevious ? : null } - {this._getSelect()} - {this.props.hasNext ? : null } -
); - } + //Make this nicer + var options = []; - _handleChange(e) { - this.props.events.getPage(parseInt(e.target.value)); + for(var i = 1; i <= props.pageProperties.maxPage; i++) { + options.push() } - _getSelect() { - if( !this.props.pageProperties || !this.props.pageProperties.maxPage ) { return; } - //Make this nicer - var options = []; - - for(var i = 1; i <= this.props.pageProperties.maxPage; i++) { - options.push() - } - - return - } + return ( + + ); } +const Pagination = compose( + getContext({ utils: PropTypes.object }), + + mapProps(props => ({ + styleProperties: props.utils.getStyleProperties(props, 'pagination'), + handleChange: (e) => props.events.getPage(parseInt(e.target.value)), + ...props + })), + + mapProps(props => ({ + pageNumberDropdown: getPageNumberDropdown(props), + style: props.styleProperties.style, + className: props.styleProperties.className, + ...props + })) +)(({ style, className, pageNumberDropdown, handleChange, hasNext, hasPrevious, events }) => ( +
+ { hasPrevious ? : null } + {pageNumberDropdown} + { hasNext ? : null } +
+)) + export default Pagination; diff --git a/src/row.js b/src/row.js index 4e10dd6..18803ba 100644 --- a/src/row.js +++ b/src/row.js @@ -1,71 +1,56 @@ -import React from 'react'; -import ColumnHelper from './utils/column-helper'; -import { getStyleProperties } from './utils/styleHelper'; - -class Row extends React.Component { - constructor(props, context) { - super(props, context); - } - - render() { - //TODO: Refactor this -- the logic to show / hide columns is kind of rough - // Also, it seems that if we moved this operation to a store, it could be a bit faster - let columns = []; - const { columnProperties, - ignoredColumns, - tableProperties, - rowData, - events, - originalRowData, - rowIndex, - absoluteRowIndex } = this.props; - const { griddleKey } = rowData.__metadata; - - //render just the columns that are contained in the metdata - for (var column in rowData) { - //get the additional properties defined in the creation of the object - let columnProperty = ColumnHelper.getColumnPropertyObject(columnProperties, column); - //render the column if there are no properties, there are properties and the column is in the collection OR there are properties and no column properties. - if(ColumnHelper.isColumnVisible(column, {columnProperties, ignoredColumns: ignoredColumns || []})) { - columns.push( ({ + styleProperties: props.utils.getStyleProperties(props, 'row'), + + ...props + })), + + mapProps(props => ({ + onClick: () => { props.events.rowClick(props.rowData, props.originalRowData); }, + + //this is the set of columns to render. we need to determine if there are + //any columns that should be treated as metadata and ignore them. + columns: (Object.keys(props.rowData) + .filter(column => (props.utils.isColumnVisible(column, + {columnProperties: props.columnProperties, ignoredColumns: props.ignoredColumns || []} + ))) + .map(column => { + //get the additional column properties + const columnProperty = props.utils.getColumnPropertyObject(props.columnProperties, column) + return ( + ); - } - } - - const { style, className } = getStyleProperties(this.props, 'row'); - return ( + /> + ); + })), + style: props.styleProperties.style, + className: props.styleProperties.className, + ...props + })) +)(({ className, style, onClick, columns, griddleKey }) => ( {columns} - ); - } - - //TODO: this can go -- double confirm that nothing is using it - _handleHover = (e) => { - this.props.events.rowHover(this.props.rowIndex, this.props.rowData); - } - - //TODO: this can go -- double confirm that nothing is using it - _handleSelect = (e) => { - this.props.events.rowSelect(this.props.rowIndex, this.props.rowData); - } - _onClick = () => { - this.props.events.rowClick(this.props.rowData, this.props.originalRowData) - } -} +)); export default Row; diff --git a/src/settings-toggle.js b/src/settings-toggle.js index ecb55bb..7f2bfa5 100644 --- a/src/settings-toggle.js +++ b/src/settings-toggle.js @@ -1,34 +1,33 @@ -import React from 'react'; -import { getStyleProperties } from './utils/styleHelper'; +import React, { PropTypes } from 'react'; import classnames from 'classnames'; +import { compose, shouldUpdate, getContext, mapProps, withState } from 'recompose'; -class SettingsToggle extends React.Component { - constructor() { - super(); - this.state = {}; - this.state.toggled = false; +const SettingsToggle = compose( + getContext({ utils: PropTypes.object }), - this._handleButton = this._handleButton.bind(this); - } + shouldUpdate(() => (false)), - shouldComponentUpdate() { - return false; - } + withState('toggled', 'setToggled', false), - render() { - const { style, className } = getStyleProperties(this.props, 'settingsToggle'); - const toggleClass = classnames(this.state.toggled ? 'toggled' : 'not-toggled', className); + mapProps(props => ({ + styleProperties: props.utils.getStyleProperties(props, 'settingsToggle'), + ...props + })), - return ; - } - - //this should keep track locally if it's toggled - //and just send whether or not settings should be shown - _handleButton() { - const toggled = !this.state.toggled; - this.props.showSettings(toggled); - this.setState({toggled: toggled}); - } -} + mapProps(props => ({ + toggleSettings: () => { + const showSettings = !props.toggled; + props.setToggled(showSettings); + props.showSettings(showSettings); + }, + style: props.styleProperties.style, + className: classnames(props.toggled ? 'toggled' : 'not-toggled', props.styleProperties.className), + ...props + })) +)(( { style, toggleSettings, className }) => ( + +)) export default SettingsToggle; diff --git a/src/settings.js b/src/settings.js index 1ab2f47..a5985f6 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1,87 +1,78 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import { getStyleProperties } from './utils/styleHelper'; -class CheckItem extends React.Component { - render() { - return ( - ); - } - - _handleClick = () => { - this.props.toggleColumn(this.props.name); - } -} +import { compose, getContext, mapProps, shouldUpdate } from 'recompose'; -CheckItem.propTypes = { - toggleColumn: React.PropTypes.func.isRequired, - name: React.PropTypes.string.isRequired, - checked: React.PropTypes.bool, - value: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.Number - ]), - text: React.PropTypes.string -}; +function getColumnDisplayName(props, column) { + const { renderProperties } = props; -class PageSize extends React.Component { - render() { - return ( - - ); + if(renderProperties.columnProperties.hasOwnProperty(column)) { + return renderProperties.columnProperties[column].hasOwnProperty('displayName') ? + renderProperties.columnProperties[column].displayName : + column + } else if (renderProperties.hiddenColumnProperties.hasOwnProperty(column)) { + return renderProperties.hiddenColumnProperties[column].hasOwnProperty('displayName') ? + renderProperties.hiddenColumnProperties[column].displayName : + column } - _handleChange = (e) => { - this.props.setPageSize(parseInt(e.target.value)); - } + return column; } -PageSize.defaultProps = { - sizes: [5, 10, 20, 30, 50, 100] -} -class Settings extends React.Component { - render() { - const keys = Object.keys(this.props.renderProperties.columnProperties); - const { style, className } = getStyleProperties(this.props, 'settings'); +const CheckItem = mapProps(props => ({ + shouldUpdate: (() => false), - var columns = this.props.allColumns.map(column => - -1} />); + handleClick: () => props.toggleColumn(props.name), + ...props +}))(({ name, checked, value, text, handleClick}) => ( + +)) - return ( -
- {columns} - -
- ); - } +const PageSize = compose( + mapProps(props => ({ + defaultSizes: [5, 10, 20, 30, 50, 100], + handleChange: (e) => { props.setPageSize(parseInt(e.target.value)) }, + ...props + })), + mapProps(props => ({ + options: props.defaultSizes.map(size => ), + ...props + })) +)(({ handleChange, options }) => ( + +)); - _getDisplayName = (column) => { - const { renderProperties } = this.props; - if(renderProperties.columnProperties.hasOwnProperty(column)) { - return renderProperties.columnProperties[column].hasOwnProperty('displayName') ? - renderProperties.columnProperties[column].displayName : - column - } else if (renderProperties.hiddenColumnProperties.hasOwnProperty(column)) { - return renderProperties.hiddenColumnProperties[column].hasOwnProperty('displayName') ? - renderProperties.hiddenColumnProperties[column].displayName : - column - } +const Settings = compose( + getContext({ utils: PropTypes.object }), - return column; - } -} + mapProps(props => ({ + styleProperties: props.utils.getStyleProperties(props, 'settings'), + keys: Object.keys(props.renderProperties.columnProperties), + ...props + })), -Settings.propTypes = { - allColumns: React.PropTypes.arrayOf(React.PropTypes.string), - visibleColumns: React.PropTypes.arrayOf(React.PropTypes.node) -}; + mapProps(props => ({ + style: props.styleProperties.style, + className: props.styleProperties.className, + columns: props.renderableColumns.map(column => + -1} /> + ), + setPageSize: props.events.setPageSize + })) +)(({ style, className, columns, setPageSize}) => ( +
+ {columns} + +
+)); export default Settings; diff --git a/src/table-body.js b/src/table-body.js index 6d64992..1e8fb4b 100644 --- a/src/table-body.js +++ b/src/table-body.js @@ -1,46 +1,61 @@ -import React from 'react'; -import { getStyleProperties } from './utils/styleHelper'; - -class TableBody extends React.Component { - constructor(props, context) { - super(props, context); - } - - shouldComponentUpdate(nextProps) { - return this.props.data !== nextProps.data; - } - - render() { - const { data, loading, components, styles, settings, events, renderProperties, tableProperties } = this.props; - - const rows = loading ? - : data - .filter(data => data.visible === undefined || data.visible === true) - .map((data, index) => - - ); - - const { style, className } = getStyleProperties(this.props, 'tableBody'); - - return ( - - {rows} - - ); - } +import React, { PropTypes } from 'react'; +import { compose, shouldUpdate, mapProps, getContext } from 'recompose'; + +export function getRowsData(props, utils) { + const { data, loading, components, styles, settings, events, renderProperties, tableProperties } = props; + + + return loading ? + : + data + .filter(data => data.visible === undefined || data.visible === true) + .map((data, index) => { + const metadata = props.metadata[index]; + const currentPageData = props.currentPageData[index]; + + return + }); } +const TableBody = compose( + getContext({ + utils: PropTypes.object, + }), + + shouldUpdate((props, nextProps) => ( props.data !== nextProps.data )), + + mapProps(props => ({ + styleProperties: props.utils.getStyleProperties(props, 'tableBody'), + ...props + })), + + mapProps(props => ({ + rows: getRowsData(props, props.utils), + style: props.styleProperties.style, + className: props.styleProperties.className + })) +)(({ style, className, rows }) => ( + + {rows} + +)); + export default TableBody; diff --git a/src/table-heading-cell.js b/src/table-heading-cell.js index 3f8bf5d..da2692f 100644 --- a/src/table-heading-cell.js +++ b/src/table-heading-cell.js @@ -1,80 +1,65 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import classnames from 'classnames'; -import { getStyleProperties } from './utils/styleHelper'; -class TableHeadingCell extends React.Component { - constructor(props, context) { - super(props, context); +import { compose, getContext, mapProps } from 'recompose'; - this._handleClick = this._handleClick.bind(this); - this._handleHover = this._handleHover.bind(this); - } +function isSortable(props) { + const { column, renderProperties } = props; + const columnProperties = renderProperties.columnProperties[column]; - getSortIcon() { - const { sorted, sortAscending, icons } = this.props; + if(columnProperties && + columnProperties.hasOwnProperty('sortable') && + columnProperties.sortable === false) { - if (sorted) { - return sortAscending ? icons.sortAscending : icons.sortDescending; - } + return false; } - isSortable() { - const { column, renderProperties } = this.props; - const columnProperties = renderProperties.columnProperties[column]; + return true; +} - if(columnProperties && columnProperties.hasOwnProperty('sortable') && columnProperties.sortable === false) { - return false; - } +const TableHeadingCell = compose( + getContext({ utils: PropTypes.object }), - return true; - } + mapProps(props => ({ + sortable: isSortable(props), + ...props + })), + mapProps(props => ({ + handleClick: (props.sortable ? (() => props.headingClick(props.column)) : null), - render() { - const style = this.props.styles.getStyle({ - styles: this.props.styles.inlineStyles, + handleHover: props.events.headingHover(props.column), + + sortIcon: props.sorted ? + (props.sortAscending ? props.icons.sortAscending : props.icons.sortDescending) : + null, + + style: props.styles.getStyle({ + styles: props.styles.inlineStyles, styleName: 'columnTitle', mergeStyles: { - width: this.props.columnProperty.width, - ...(this.props.alignment || this.props.headerAlignment ? {textAlign: this.props.headerAlignment || this.props.alignment} : {}), - ...this.props.style + width: props.columnProperty.width, + ...(props.alignment || props.headerAlignment ? {textAlign: props.headerAlignment || props.alignment} : {}), + ...props.style } - }); - - const { className } = getStyleProperties(this.props, 'tableHeadingCell'); - const classNames = classnames(className, this.props.columnProperty ? this.props.columnProperty.headerCssClassName : null) - const { sorted } = this.props; - const clickEvent = this.isSortable() ? this._handleClick : null; + }), - return ( - - {this.props.title} { this.getSortIcon() } - ); - } - - _handleHover() { - this.props.headingHover(this.props.column); - } - - _handleClick() { - this.props.headingClick(this.props.column); - } -} + className: classnames( + props.utils.getStyleProperties(props, 'tableHeadingCell'), + props.columnProperty ? props.columnProperty.headerCssClassName : null), -TableHeadingCell.propTypes = { - headingHover: React.PropTypes.func, - headingClick: React.PropTypes.func, - column: React.PropTypes.string, - headerAlignment: React.PropTypes.oneOf(['left', 'right', 'center']), - alignment: React.PropTypes.oneOf(['left', 'right', 'center']), - sortAscending: React.PropTypes.bool, - sorted: React.PropTypes.bool -}; + ...props + })) +)(({ column, style, handleHover, handleClick, title, sortIcon, className}) => ( + + { title } { sortIcon } + +)) export default TableHeadingCell; diff --git a/src/table-heading.js b/src/table-heading.js index ae31386..e866d43 100644 --- a/src/table-heading.js +++ b/src/table-heading.js @@ -1,76 +1,80 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import ColumnHelper from './utils/column-helper'; import { getStyleProperties } from './utils/styleHelper'; -import { arraysEqual } from './utils/arrayHelper';; - class TableHeading extends React.Component { - constructor(props, context) { - super(props, context); +import { compose, getContext, mapProps, shouldUpdate } from 'recompose'; - this.state = {}; - } +function getColumnTitle(column, props) { + const initial = props.columnTitles[column] ? + props.columnTitles[column] : + column; - shouldComponentUpdate(nextProps) { - //TODO: Make this nicer - shouldn't be reminiscent of clojure level paran usage - return (!arraysEqual(this.props.columns, nextProps.columns) || - ((this.props.pageProperties && nextProps.pageProperties) && - (!arraysEqual(this.props.pageProperties.sortColumns, nextProps.pageProperties.sortColumns) || - this.props.pageProperties.sortAscending !== nextProps.pageProperties.sortAscending) + return props.renderProperties.columnProperties[column] && + props.renderProperties.columnProperties[column].hasOwnProperty('displayName') ? + props.renderProperties.columnProperties[column].displayName : + initial +} + +const TableHeading = compose( + getContext({ utils: PropTypes.object }), + + shouldUpdate((props, nextProps) => ( + (!props.utils.arraysEqual(props.columns, nextProps.columns) || + ((props.pageProperties && nextProps.pageProperties) && + (!props.utils.arraysEqual(props.pageProperties.sortColumns, nextProps.pageProperties.sortColumns) || + props.pageProperties.sortAscending !== nextProps.pageProperties.sortAscending) ) - ); - } + ) + )), - getColumnTitle(column) { - const initial = this.props.columnTitles[column] ? - this.props.columnTitles[column] : - column; + mapProps((props) => ({ + styleProperties: props.utils.getStyleProperties(props, 'tableHeading'), + headingClick: props.events.headingClick, + headingHover: props.events.headingHover, + ...props + })), - return this.props.renderProperties.columnProperties[column] && this.props.renderProperties.columnProperties[column].hasOwnProperty('displayName') ? - this.props.renderProperties.columnProperties[column].displayName : - initial - } + mapProps(props => ({ + headings: props.columns + .filter(column => (props.utils.isColumnVisible(column, + { columnProperties: props.renderProperties.columnProperties, + ignoredColumns: props.renderProperties.ignoredColumns + }))) + .map(column => { + let columnProperty = props.utils.getColumnPropertyObject(props.renderProperties.columnProperties, column); + const sortAscending = props.pageProperties && props.pageProperties.sortAscending; + const sorted = props.pageProperties && props.pageProperties.sortColumns.indexOf(column) > -1; - render() { - let { headingClick, headingHover } = this.props.events; - const { renderProperties } = this.props; - const { style, className } = getStyleProperties(this.props, 'tableHeading'); + const title = getColumnTitle(column, props); + return { - let columnProperty = ColumnHelper.getColumnPropertyObject(renderProperties.columnProperties, column); - const showColumn = ColumnHelper.isColumnVisible(column, { columnProperties: renderProperties.columnProperties, ignoredColumns: renderProperties.ignoredColumns }); - const sortAscending = this.props.pageProperties && this.props.pageProperties.sortAscending; - const sorted = this.props.pageProperties && this.props.pageProperties.sortColumns.indexOf(column) > -1 + columnProperty={columnProperty} + {...columnProperty} - const title = this.getColumnTitle(column); - let component = null; - if(showColumn) { - component = (); - } + {...props} + /> + }), - return component; - }); + style: props.styleProperties.style, - return this.props.columns.length > 0 ? ( - - - {headings} - - - ) : null; - } -} + className: props.styleProperties.className + })) +)(({ style, className, headings, ...props }) => ( + + + {headings} + + +)); - export default TableHeading; +export default TableHeading; diff --git a/src/table.js b/src/table.js index 5380b2c..7b4ab82 100644 --- a/src/table.js +++ b/src/table.js @@ -1,47 +1,40 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import RowDefinition from './row-definition'; -import { getStyleProperties } from './utils/styleHelper'; +import { compose, getContext, mapProps } from 'recompose'; -class Table extends React.Component { - constructor(props, context) { - super(props, context); +const Table = compose( + getContext({ utils: PropTypes.object }), - this.state = {}; - } - - render() { - const { settings, styles } = this.props; - const style = styles.getStyle({ - styles: styles.inlineStyles, + mapProps(props => ({ + style: props.styles.getStyle({ + styles: props.styles.inlineStyles, styleName: 'table', - mergeStyles: settings.useFixedTable && styles.getStyle({ - styles: styles.inlineStyles, + mergeStyles: props.settings.useFixedTable && props.styles.getStyle({ + styles: props.styles.inlineStyles, styleName: 'fixedTable', }) - }); + }), - const { className } = getStyleProperties(this.props, 'table'); - //translate the definition object to props for Heading / Body - return this.props.data.length > 0 ? - ( - - - -
- ) : null; - } -} + className: props.utils.getStyleProperties(props, 'table').className, -//TODO: enabled the propTypes again -/* -Table.propTypes = { - children: React.PropTypes.oneOfType([ - React.PropTypes.instanceOf(RowDefinition) - // React.PropTypes.arrayOf(React.PropTypes.instanceOf(ColumnDefinition)) - ]) -}; */ + useFixedTable: props.settings.useFixedTable, + columns: props.data.length > 0 ? Object.keys(props.data[0]) : [], + TableHeading: props.components.TableHeading, + TableBody: props.components.TableBody, + data: props.data, + props: props, + })) +)(({data, className, style, columns, props, TableHeading, TableBody }) => ( + data.length > 0 ? + ( + + + +
+ ) : +)) export default Table;