Skip to content

Commit

Permalink
feat(Table): Table shorthand (#565)
Browse files Browse the repository at this point in the history
* TableCell shorthand
* TableRow shorthand
* Table shorthand
* Add example to test table shorthand
  • Loading branch information
jeffcarbs committed Sep 29, 2016
1 parent 25fd1e7 commit 7858c7f
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import { Icon, Table } from 'stardust'

const headerRow = [
'Name',
'Status',
'Notes',
]

const bodyRow = ({ name, status, notes }) => ({
warning: !!(status && status.match('Requires Action')),
items: [
name || 'No name specified',
status
? { icon: 'attention', content: status }
: 'Unknown',
notes
? { icon: 'attention', content: notes, warning: true }
: 'None',
]
})

const tableData = [
{ name: undefined, status: undefined, notes: undefined },
{ name: 'Jimmy', status: 'Requires Action', notes: undefined },
{ name: 'Jamie', status: undefined, notes: 'Hostile' },
{ name: 'Jill', status: undefined, notes: undefined },
]

const TableWarningShorthand = () => {
return (
<Table celled headerRow={headerRow} bodyRow={bodyRow} tableData={tableData} />
)
}

export default TableWarningShorthand
5 changes: 5 additions & 0 deletions docs/app/Examples/collections/Table/States/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ const States = () => {
description='A cell or row may warn a user'
examplePath='collections/Table/States/TableWarning'
/>
<ComponentExample
title='Warning Shorthand'
description='Same as warning example but configured via shorthand'
examplePath='collections/Table/States/TableWarningShorthand'
/>
<ComponentExample
title='Active'
description='A cell or row can be active or selected by a user'
Expand Down
48 changes: 46 additions & 2 deletions src/collections/Table/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import TableRow from './TableRow'
function Table(props) {
const {
basic,
bodyRow,
celled,
children,
className,
Expand All @@ -34,6 +35,8 @@ function Table(props) {
compact,
definition,
fixed,
footerRow,
headerRow,
inverted,
padded,
selectable,
Expand All @@ -42,6 +45,7 @@ function Table(props) {
stackable,
striped,
structured,
tableData,
unstackable,
} = props
const classes = cx(
Expand Down Expand Up @@ -70,7 +74,17 @@ function Table(props) {
const ElementType = getElementType(Table, props)
const rest = getUnhandledProps(Table, props)

return <ElementType {...rest} className={classes}>{children}</ElementType>
if (children) {
return <ElementType {...rest} className={classes}>{children}</ElementType>
}

return (
<ElementType {...rest} className={classes}>
{headerRow && <TableHeader>{TableRow.create(headerRow, { itemAs: 'th' })}</TableHeader>}
{<TableBody>{tableData.map((item, index) => TableRow.create(bodyRow(item, index)))}</TableBody>}
{footerRow && <TableFooter>{TableRow.create(footerRow)}</TableFooter>}
</ElementType>
)
}

Table._meta = {
Expand Down Expand Up @@ -100,11 +114,23 @@ Table.propTypes = {
PropTypes.oneOf(Table._meta.props.basic),
]),

/**
* A function that takes (data, index) and returns shorthand for a TableRow
* to be placed within Table.Body.
*/
bodyRow: customPropTypes.every([
customPropTypes.demand(['bodyRow']),
PropTypes.func,
]),

/** A table may be divided each row into separate cells. */
celled: PropTypes.bool,

/** Primary content of the Table. */
children: PropTypes.node,
children: customPropTypes.every([
customPropTypes.disallow(['headerRow', 'bodyRow', 'footerRow', 'tableData']),
PropTypes.node,
]),

/** Classes that will be added to the Table className. */
className: PropTypes.string,
Expand Down Expand Up @@ -132,6 +158,18 @@ Table.propTypes = {
* */
fixed: PropTypes.bool,

/** Shorthand for a TableRow to be placed within Table.Footer. */
footerRow: PropTypes.oneOfType([
PropTypes.array,
PropTypes.element,
]),

/** Shorthand for a TableRow to be placed within Table.Header. */
headerRow: PropTypes.oneOfType([
PropTypes.array,
PropTypes.element,
]),

/** A table's colors can be inverted. */
inverted: PropTypes.bool,

Expand Down Expand Up @@ -159,6 +197,12 @@ Table.propTypes = {
/** A table can be formatted to display complex structured data. */
structured: PropTypes.bool,

/** Data to be passed to the bodyRow function. */
tableData: customPropTypes.every([
customPropTypes.demand(['bodyRow']),
PropTypes.array,
]),

/** A table can specify how it stacks table content responsively. */
unstackable: PropTypes.bool,
}
Expand Down
38 changes: 36 additions & 2 deletions src/collections/Table/TableCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import cx from 'classnames'
import React, { PropTypes } from 'react'

import {
createShorthandFactory,
customPropTypes,
getElementType,
getUnhandledProps,
Expand All @@ -12,15 +13,18 @@ import {
useVerticalAlignProp,
useWidthProp,
} from '../../lib'
import { Icon } from '../../elements'

function TableCell(props) {
const {
active,
children,
className,
collapsing,
content,
disabled,
error,
icon,
negative,
positive,
singleLine,
Expand All @@ -47,7 +51,16 @@ function TableCell(props) {
const ElementType = getElementType(TableCell, props)
const rest = getUnhandledProps(TableCell, props)

return <ElementType {...rest} className={classes}>{children}</ElementType>
if (children) {
return <ElementType {...rest} className={classes}>{children}</ElementType>
}

return (
<ElementType {...rest} className={classes}>
{Icon.create(icon)}
{content}
</ElementType>
)
}

TableCell._meta = {
Expand All @@ -73,20 +86,39 @@ TableCell.propTypes = {
active: PropTypes.bool,

/** Primary content of the TableCell. */
children: PropTypes.node,
children: customPropTypes.every([
customPropTypes.disallow(['content', 'icon']),
PropTypes.node,
]),

/** Classes that will be added to the TableCell className. */
className: PropTypes.string,

/** A cell can be collapsing so that it only uses as much space as required. */
collapsing: PropTypes.bool,

/** Shorthand for primary content of the TableCell. Mutually exclusive with the children. */
content: customPropTypes.every([
customPropTypes.disallow(['children']),
PropTypes.string,
]),

/** A cell can be disabled. */
disabled: PropTypes.bool,

/** A cell may call attention to an error or a negative value. */
error: PropTypes.bool,

/** Add an Icon by name, props object, or pass an <Icon /> */
icon: customPropTypes.every([
customPropTypes.disallow(['children']),
PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.element,
]),
]),

/** A cell may let a user know whether a value is bad. */
negative: PropTypes.bool,

Expand All @@ -109,4 +141,6 @@ TableCell.propTypes = {
width: PropTypes.oneOf(TableCell._meta.props.width),
}

TableCell.create = createShorthandFactory(TableCell, content => ({ content }))

export default TableCell
36 changes: 34 additions & 2 deletions src/collections/Table/TableRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import cx from 'classnames'
import React, { PropTypes } from 'react'

import {
createShorthandFactory,
customPropTypes,
getElementType,
getUnhandledProps,
Expand All @@ -11,6 +12,7 @@ import {
useTextAlignProp,
useVerticalAlignProp,
} from '../../lib'
import TableCell from './TableCell'

function TableRow(props) {
const {
Expand All @@ -19,6 +21,8 @@ function TableRow(props) {
className,
disabled,
error,
itemAs,
items,
negative,
positive,
textAlign,
Expand All @@ -40,7 +44,15 @@ function TableRow(props) {
const ElementType = getElementType(TableRow, props)
const rest = getUnhandledProps(TableRow, props)

return <ElementType {...rest} className={classes}>{children}</ElementType>
if (children) {
return <ElementType {...rest} className={classes}>{children}</ElementType>
}

return (
<ElementType {...rest} className={classes}>
{items.map((item) => TableCell.create(item, { as: itemAs }))}
</ElementType>
)
}

TableRow._meta = {
Expand All @@ -55,6 +67,7 @@ TableRow._meta = {

TableRow.defaultProps = {
as: 'tr',
itemAs: 'td',
}

TableRow.propTypes = {
Expand All @@ -65,7 +78,10 @@ TableRow.propTypes = {
active: PropTypes.bool,

/** Primary content of the TableRow. */
children: PropTypes.node,
children: customPropTypes.every([
customPropTypes.disallow(['content', 'icon']),
PropTypes.node,
]),

/** Classes that will be added to the TableRow className. */
className: PropTypes.string,
Expand All @@ -76,6 +92,20 @@ TableRow.propTypes = {
/** A row may call attention to an error or a negative value. */
error: PropTypes.bool,

/** An element type to render as (string or function). */
itemAs: customPropTypes.as,

/** Shorthand array of props for TableCell. Mutually exclusive with children. */
items: customPropTypes.every([
customPropTypes.disallow(['children']),
// Array of shorthands for MenuItem
PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.string,
PropTypes.element,
PropTypes.object,
])),
]),

/** A row may let a user know whether a value is bad. */
negative: PropTypes.bool,

Expand All @@ -92,4 +122,6 @@ TableRow.propTypes = {
warning: PropTypes.bool,
}

TableRow.create = createShorthandFactory(TableRow, items => ({ items }))

export default TableRow
2 changes: 1 addition & 1 deletion src/lib/factories.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function createShorthand(Component, mapValueToProps, val, defaultProps =
} else if (_.isPlainObject(val)) {
type = 'props'
usersProps = val
} else if (_.isString(val) || _.isNumber(val)) {
} else if (_.isString(val) || _.isNumber(val) || _.isArray(val)) {
type = 'literal'
usersProps = mapValueToProps(val)
}
Expand Down

0 comments on commit 7858c7f

Please sign in to comment.