diff --git a/docs/app/Examples/views/Statistic/Content/StatisticLabelExample.js b/docs/app/Examples/views/Statistic/Content/StatisticLabelExample.js new file mode 100644 index 0000000000..a43cdb4233 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Content/StatisticLabelExample.js @@ -0,0 +1,17 @@ +import React from 'react' +import { Statistic } from 'stardust' + +const { Label, Value } = Statistic + +const StatisticLabelExample = () => ( +
+ + 2,204 + + + + +
+) + +export default StatisticLabelExample diff --git a/docs/app/Examples/views/Statistic/Content/StatisticValueExample.js b/docs/app/Examples/views/Statistic/Content/StatisticValueExample.js new file mode 100644 index 0000000000..bb104bad1c --- /dev/null +++ b/docs/app/Examples/views/Statistic/Content/StatisticValueExample.js @@ -0,0 +1,42 @@ +import React from 'react' +import { Icon, Image, Statistic } from 'stardust' + +const { Group, Label, Value } = Statistic + +// TODO: Update usage after will be updated to v1 API +// TODO: Update usage after will be updated to v1 API + +const StatisticValueExample = () => ( + + + 22 + + + + + + Three
+ Thousand +
+ +
+ + + + + 5 + + + + + + + + 42 + + + +
+) + +export default StatisticValueExample diff --git a/docs/app/Examples/views/Statistic/Content/StatisticValuePropsExample.js b/docs/app/Examples/views/Statistic/Content/StatisticValuePropsExample.js new file mode 100644 index 0000000000..cb6b86f627 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Content/StatisticValuePropsExample.js @@ -0,0 +1,36 @@ +import React from 'react' +import { Icon, Image, Statistic } from 'stardust' + +// TODO: Update usage after will be updated to v1 API +// TODO: Update usage after will be updated to v1 API + +const iconValue = (
5
) +const imageValue = ( +
+ + 42 +
+) +const textValue = (
Three
Thousand
) + +const items = [ + { label: 'Saves', value: 22 }, + { label: 'Signups', text: true, value: textValue }, + { label: 'Flights', value: iconValue }, + { label: 'Team Members', value: imageValue }, +] + +const StatisticValuePropsExample = () => ( +
+ + + + + + + + +
+) + +export default StatisticValuePropsExample diff --git a/docs/app/Examples/views/Statistic/StatisticExamples.js b/docs/app/Examples/views/Statistic/StatisticExamples.js index f54a375f52..13b90ceb03 100644 --- a/docs/app/Examples/views/Statistic/StatisticExamples.js +++ b/docs/app/Examples/views/Statistic/StatisticExamples.js @@ -1,12 +1,79 @@ -import React, { Component } from 'react' -import StatisticTypesExamples from './Types/StatisticTypesExamples' - -export default class StatisticExamples extends Component { - render() { - return ( -
- -
- ) - } -} +import React from 'react' +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' + +const StatisticExamples = () => ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+) + +export default StatisticExamples diff --git a/docs/app/Examples/views/Statistic/Types/StatisticBottomLabelExample.js b/docs/app/Examples/views/Statistic/Types/StatisticBottomLabelExample.js index 2d3d84d4be..095f888966 100644 --- a/docs/app/Examples/views/Statistic/Types/StatisticBottomLabelExample.js +++ b/docs/app/Examples/views/Statistic/Types/StatisticBottomLabelExample.js @@ -1,13 +1,15 @@ -import React, { Component } from 'react' +import React from 'react' import { Statistic } from 'stardust' -export default class StatisticBottomLabelExample extends Component { - render() { - return ( - - 5,550 - Downloads - - ) - } -} +const StatisticBottomLabelExample = () => ( +
+ + 5,550 + Downloads + + + +
+) + +export default StatisticBottomLabelExample diff --git a/docs/app/Examples/views/Statistic/Types/StatisticGroupExample.js b/docs/app/Examples/views/Statistic/Types/StatisticGroupExample.js index fb7b696ca7..be186c2b2e 100644 --- a/docs/app/Examples/views/Statistic/Types/StatisticGroupExample.js +++ b/docs/app/Examples/views/Statistic/Types/StatisticGroupExample.js @@ -1,24 +1,29 @@ -import React, { Component } from 'react' +import React from 'react' import { Statistic } from 'stardust' -const { Statistics, Label, Value } = Statistic -export default class StatisticGroupExample extends Component { - render() { - return ( - - - 22 - - - - 31,200 - - - - 22 - - - - ) - } -} +const { Group, Label, Value } = Statistic +const items = [ + { label: 'Faves', value: 22 }, + { label: 'Views', value: '31,200' }, + { label: 'Members', value: 22 }, +] + +const StatisticGroupExample = () => ( +
+ + + 22 + + + + 31,200 + + + + + + +
+) + +export default StatisticGroupExample diff --git a/docs/app/Examples/views/Statistic/Types/StatisticTopLabelExample.js b/docs/app/Examples/views/Statistic/Types/StatisticTopLabelExample.js index 04b5086279..cea613ba81 100644 --- a/docs/app/Examples/views/Statistic/Types/StatisticTopLabelExample.js +++ b/docs/app/Examples/views/Statistic/Types/StatisticTopLabelExample.js @@ -1,13 +1,13 @@ -import React, { Component } from 'react' +import React from 'react' import { Statistic } from 'stardust' -export default class StatisticTopLabelExample extends Component { - render() { - return ( - - Views - 40,509 - - ) - } -} +const StatisticTopLabelExample = () => ( +
+ + Views + 40,509 + +
+) + +export default StatisticTopLabelExample diff --git a/docs/app/Examples/views/Statistic/Types/StatisticTypesExamples.js b/docs/app/Examples/views/Statistic/Types/StatisticTypesExamples.js deleted file mode 100644 index c74c919c9b..0000000000 --- a/docs/app/Examples/views/Statistic/Types/StatisticTypesExamples.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { Component } from 'react' -import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' -import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' - -export default class StatisticTypesExamples extends Component { - render() { - return ( - - - - - - ) - } -} diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticColoredExample.js b/docs/app/Examples/views/Statistic/Variations/StatisticColoredExample.js new file mode 100644 index 0000000000..ad3c38ba34 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticColoredExample.js @@ -0,0 +1,21 @@ +import React from 'react' +import { Statistic } from 'stardust' + +const StatisticColoredExample = () => ( + + + + + + + + + + + + + + +) + +export default StatisticColoredExample diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticEvenlyDividedExample.js b/docs/app/Examples/views/Statistic/Variations/StatisticEvenlyDividedExample.js new file mode 100644 index 0000000000..aee3323581 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticEvenlyDividedExample.js @@ -0,0 +1,30 @@ +import React from 'react' +import { Icon, Image, Statistic } from 'stardust' + +// TODO: Update usage after will be updated to v1 API +// TODO: Update usage after will be updated to v1 API + +const iconValue = (
5
) +const imageValue = ( +
+ + 42 +
+) +const textValue = (
Three
Thousand
) + +const items = [ + { label: 'Saves', value: 22 }, + { label: 'Signups', text: true, value: textValue }, + { label: 'Flights', value: iconValue }, + { label: 'Team Members', value: imageValue }, +] + +const StatisticEvenlyDividedExample = () => ( +
+ + +
+) + +export default StatisticEvenlyDividedExample diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticFloatedExample.js b/docs/app/Examples/views/Statistic/Variations/StatisticFloatedExample.js new file mode 100644 index 0000000000..098c9e2ff3 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticFloatedExample.js @@ -0,0 +1,35 @@ +import React from 'react' +import { Segment, Statistic } from 'stardust' + +const StatisticFloatedExample = () => ( + + + +

+ Te eum doming eirmod, nominati pertinacia argumentum ad his. Ex eam alia facete scriptorem, est autem aliquip + detraxit at. Usu ocurreret referrentur at, cu epicurei appellantur vix. Cum ea laoreet recteque electram, eos + choro alterum definiebas in. Vim dolorum definiebas an. Mei ex natum rebum iisque. +

+ +

+ Audiam quaerendum eu sea, pro omittam definiebas ex. Te est latine definitiones. Quot wisi nulla ex duo. Vis sint + solet expetenda ne, his te phaedrum referrentur consectetuer. Id vix fabulas oporteat, ei quo vide phaedrum, vim + vivendum maiestatis in. +

+ + + +

+ Eu quo homero blandit intellegebat. Incorrupte consequuntur mei id. Mei ut facer dolores adolescens, no illum + aperiri quo, usu odio brute at. Qui te porro electram, ea dico facete utroque quo. Populo quodsi te eam, wisi + everti eos ex, eum elitr altera utamur at. Quodsi convenire mnesarchum eu per, quas minimum postulant per id. +

+

+ Audiam quaerendum eu sea, pro omittam definiebas ex. Te est latine definitiones. Quot wisi nulla ex duo. Vis sint + solet expetenda ne, his te phaedrum referrentur consectetuer. Id vix fabulas oporteat, ei quo vide phaedrum, vim + vivendum maiestatis in. +

+
+) + +export default StatisticFloatedExample diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticGroupHorizontalExample.js b/docs/app/Examples/views/Statistic/Variations/StatisticGroupHorizontalExample.js new file mode 100644 index 0000000000..956ec73244 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticGroupHorizontalExample.js @@ -0,0 +1,12 @@ +import React from 'react' +import { Statistic } from 'stardust' + +const items = [ + { label: 'Views', value: '2,204' }, + { label: 'Downloads', value: '3,322' }, + { label: 'Tasks', value: 22 }, +] + +const StatisticGroupHorizontalExample = () => + +export default StatisticGroupHorizontalExample diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticHorizontalExample.js b/docs/app/Examples/views/Statistic/Variations/StatisticHorizontalExample.js new file mode 100644 index 0000000000..07aecc72dd --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticHorizontalExample.js @@ -0,0 +1,6 @@ +import React from 'react' +import { Statistic } from 'stardust' + +const StatisticHorizontalExample = () => + +export default StatisticHorizontalExample diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticInvertedExample.js b/docs/app/Examples/views/Statistic/Variations/StatisticInvertedExample.js new file mode 100644 index 0000000000..9746b9c7b0 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticInvertedExample.js @@ -0,0 +1,24 @@ +import React from 'react' +import { Segment, Statistic } from 'stardust' + +// TODO: Update usage after will be updated to v1 API + +const StatisticInvertedExample = () => ( + + + + + + + + + + + + + + + +) + +export default StatisticInvertedExample diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticSizeDividedExamples.js b/docs/app/Examples/views/Statistic/Variations/StatisticSizeDividedExamples.js new file mode 100644 index 0000000000..f77e138903 --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticSizeDividedExamples.js @@ -0,0 +1,25 @@ +import React from 'react' +import { Divider, Statistic } from 'stardust' + +const StatisticSizeDividedExamples = () => ( +
+ + + + + + + + + + + + + + + + +
+) + +export default StatisticSizeDividedExamples diff --git a/docs/app/Examples/views/Statistic/Variations/StatisticSizeExamples.js b/docs/app/Examples/views/Statistic/Variations/StatisticSizeExamples.js new file mode 100644 index 0000000000..cedbe70e8b --- /dev/null +++ b/docs/app/Examples/views/Statistic/Variations/StatisticSizeExamples.js @@ -0,0 +1,15 @@ +import React from 'react' +import { Statistic } from 'stardust' + +const StatisticSizeExamples = () => ( +
+ + + + + + +
+) + +export default StatisticSizeExamples diff --git a/src/utils/numberToWord.js b/src/utils/numberToWord.js index 99c4d18b84..a92e204dec 100644 --- a/src/utils/numberToWord.js +++ b/src/utils/numberToWord.js @@ -1,22 +1,22 @@ -export default function numberToWord(number) { - const map = { - 1: 'one', - 2: 'two', - 3: 'three', - 4: 'four', - 5: 'five', - 6: 'six', - 7: 'seven', - 8: 'eight', - 9: 'nine', - 10: 'ten', - 11: 'eleven', - 12: 'twelve', - 13: 'thirteen', - 14: 'fourteen', - 15: 'fifteen', - 16: 'sixteen', - } +export const numberToWordMap = { + 1: 'one', + 2: 'two', + 3: 'three', + 4: 'four', + 5: 'five', + 6: 'six', + 7: 'seven', + 8: 'eight', + 9: 'nine', + 10: 'ten', + 11: 'eleven', + 12: 'twelve', + 13: 'thirteen', + 14: 'fourteen', + 15: 'fifteen', + 16: 'sixteen', +} - return map[number] +export default function numberToWord(number) { + return numberToWordMap[number] || number } diff --git a/src/utils/semanticUtils.js b/src/utils/semanticUtils.js index b7b9544efd..b3c922169e 100644 --- a/src/utils/semanticUtils.js +++ b/src/utils/semanticUtils.js @@ -1,3 +1,6 @@ +import _ from 'lodash' +import { numberToWordMap } from './numberToWord' + export const colors = [ 'red', 'orange', @@ -16,3 +19,8 @@ export const colors = [ export const sizes = ['mini', 'tiny', 'small', 'medium', 'large', 'big', 'huge', 'massive'] export const textAlignments = ['left', 'center', 'right', 'justified'] export const floats = ['left', 'right'] +export const widths = [ + ..._.keys(numberToWordMap), + ..._.keys(numberToWordMap).map(Number), + ..._.values(numberToWordMap), +] diff --git a/src/views/Statistic/Statistic.js b/src/views/Statistic/Statistic.js index 600952e070..db8d7b8cde 100644 --- a/src/views/Statistic/Statistic.js +++ b/src/views/Statistic/Statistic.js @@ -1,42 +1,97 @@ -import classNames from 'classnames' -import React, { Component, PropTypes } from 'react' +import _ from 'lodash' +import cx from 'classnames' +import React, { PropTypes } from 'react' -import { getUnhandledProps } from '../../utils/propUtils' +import { customPropTypes, getUnhandledProps, useKeyOnly, useValueAndKey } from '../../utils/propUtils' +import * as sui from '../../utils/semanticUtils' import META from '../../utils/Meta' - -import StatisticStatistics from './StatisticStatistics' +import StatisticGroup from './StatisticGroup' import StatisticLabel from './StatisticLabel' import StatisticValue from './StatisticValue' -export default class Statistic extends Component { - static propTypes = { - children: PropTypes.node, - className: PropTypes.string, - } +function Statistic(props) { + const { children, className, color, floated, horizontal, inverted, label, size, text, value } = props + const classes = cx( + 'ui', + color, + useValueAndKey(floated, 'floated'), + useKeyOnly(horizontal, 'horizontal'), + useKeyOnly(inverted, 'inverted'), + size, + className, + 'statistic', + ) + const rest = getUnhandledProps(Statistic, props) - static _meta = { - library: META.library.semanticUI, - name: 'Statistic', - type: META.type.view, + if (children) { + return
{children}
} - static Statistics = StatisticStatistics - static Label = StatisticLabel - static Value = StatisticValue + return ( +
+ {value} + {label} +
+ ) +} + +Statistic._meta = { + library: META.library.semanticUI, + name: 'Statistic', + type: META.type.view, + props: { + color: sui.colors, + floated: sui.floats, + size: _.without(sui.sizes, 'big', 'massive', 'medium'), + }, +} - render() { - const classes = classNames( - 'ui', - this.props.className, - 'statistic' - ) +Statistic.propTypes = { + /** Primary content of the Statistic. */ + children: customPropTypes.all([ + customPropTypes.mutuallyExclusive(['label', 'value']), + customPropTypes.ofComponentTypes([ + 'StatisticLabel', + 'StatisticValue', + ]), + ]), - const props = getUnhandledProps(Statistic, this.props) + /** Classes that will be added to the Statistic className. */ + className: PropTypes.string, - return ( -
- {this.props.children} -
- ) - } + /** A statistic can be formatted to be different colors. */ + color: PropTypes.oneOf(Statistic._meta.props.color), + + /** A statistic can sit to the left or right of other content. */ + floated: PropTypes.oneOf(Statistic._meta.props.floated), + + /** A statistic can present its measurement horizontally. */ + horizontal: PropTypes.bool, + + /** A statistic can be formatted to fit on a dark background. */ + inverted: PropTypes.bool, + + /** Label content of the Statistic. Mutually exclusive with the children prop. */ + label: customPropTypes.all([ + customPropTypes.mutuallyExclusive(['children']), + PropTypes.node, + ]), + + /** A statistic can vary in size. */ + size: PropTypes.oneOf(Statistic._meta.props.size), + + /** Format the StatisticValue with smaller font size to fit nicely beside number values. */ + text: PropTypes.bool, + + /** Value content of the Statistic. Mutually exclusive with the children prop. */ + value: customPropTypes.all([ + customPropTypes.mutuallyExclusive(['children']), + PropTypes.node, + ]), } + +Statistic.Group = StatisticGroup +Statistic.Label = StatisticLabel +Statistic.Value = StatisticValue + +export default Statistic diff --git a/src/views/Statistic/StatisticGroup.js b/src/views/Statistic/StatisticGroup.js new file mode 100644 index 0000000000..5673c2cf26 --- /dev/null +++ b/src/views/Statistic/StatisticGroup.js @@ -0,0 +1,68 @@ +import cx from 'classnames' +import React, { PropTypes } from 'react' + +import { customPropTypes, getUnhandledProps, useKeyOnly } from '../../utils/propUtils' +import * as sui from '../../utils/semanticUtils' +import numberToWord from '../../utils/numberToWord' +import META from '../../utils/Meta' +import Statistic from './Statistic' + +function StatisticGroup(props) { + const { children, className, horizontal, items, widths } = props + const classes = cx( + 'ui', + useKeyOnly(horizontal, 'horizontal'), + numberToWord(widths), + className, + 'statistics' + ) + const rest = getUnhandledProps(StatisticGroup, props) + + if (!items) { + return
{children}
+ } + + let itemsJSX = [] + + items.forEach((item, index) => { + const key = `${item.label}-${item.value}-${index}` + itemsJSX.push() + }) + + return
{itemsJSX}
+} + +StatisticGroup._meta = { + library: META.library.semanticUI, + name: 'StatisticGroup', + type: META.type.view, + parent: 'Statistic', + props: { + widths: sui.widths, + }, +} + +StatisticGroup.propTypes = { + /** Primary content of the StatisticGroup. */ + children: customPropTypes.all([ + customPropTypes.mutuallyExclusive(['content']), + PropTypes.node, + ]), + + /** Classes that will be added to the StatisticGroup className. */ + className: PropTypes.string, + + /** A statistic can present its measurement horizontally. */ + horizontal: PropTypes.bool, + + /** Array of props for Statistic. */ + items: customPropTypes.all([ + customPropTypes.mutuallyExclusive(['children']), + PropTypes.array, + ]), + + /** A statistic group can have its items divided evenly. */ + widths: PropTypes.oneOf(StatisticGroup._meta.props.widths), +} + +export default StatisticGroup diff --git a/src/views/Statistic/StatisticLabel.js b/src/views/Statistic/StatisticLabel.js index c0c6dda1ca..b24b24101f 100644 --- a/src/views/Statistic/StatisticLabel.js +++ b/src/views/Statistic/StatisticLabel.js @@ -1,33 +1,44 @@ -import React, { Component, PropTypes } from 'react' -import classNames from 'classnames' -import { getUnhandledProps } from '../../utils/propUtils' +import cx from 'classnames' +import React, { PropTypes } from 'react' + +import { customPropTypes, getUnhandledProps } from '../../utils/propUtils' import META from '../../utils/Meta' -export default class StatisticLabel extends Component { - static propTypes = { - children: PropTypes.node.isRequired, - className: PropTypes.string, - } - - static _meta = { - library: META.library.semanticUI, - name: 'StatisticLabel', - type: META.type.view, - parent: 'Statistic', - } - - render() { - const classes = classNames( - this.props.className, - 'label', - ) - - const props = getUnhandledProps(StatisticLabel, this.props) - - return ( -
- {this.props.children} -
- ) - } +// TODO: This file has disabled shorthand props +// @see /~https://github.com/TechnologyAdvice/stardust/pull/334 + +function StatisticLabel(props) { + // const { children, className, content } = props + const { children, className } = props + const classes = cx(className, 'label') + const rest = getUnhandledProps(StatisticLabel, props) + + // return
{children || content}
+ return
{children}
+} + +StatisticLabel._meta = { + library: META.library.semanticUI, + name: 'StatisticLabel', + parent: 'Statistic', + type: META.type.view, } + +StatisticLabel.propTypes = { + /** Primary content of the StatisticLabel. */ + children: customPropTypes.all([ + customPropTypes.mutuallyExclusive(['content']), + PropTypes.node, + ]), + + /** Classes that will be added to the StatisticLabel className. */ + className: PropTypes.string, + + // /** Primary content of the StatisticLabel. Mutually exclusive with the children prop. */ + // content: customPropTypes.all([ + // customPropTypes.mutuallyExclusive(['children']), + // PropTypes.node, + // ]), +} + +export default StatisticLabel diff --git a/src/views/Statistic/StatisticStatistics.js b/src/views/Statistic/StatisticStatistics.js deleted file mode 100644 index b2c29d6a75..0000000000 --- a/src/views/Statistic/StatisticStatistics.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, { Component, PropTypes } from 'react' -import classNames from 'classnames' -import META from '../../utils/Meta' - -export default class StatisticStatistics extends Component { - static propTypes = { - children: PropTypes.node, - className: PropTypes.string, - } - - static _meta = { - library: META.library.semanticUI, - name: 'StatisticStatistics', - type: META.type.view, - parent: 'Statistic', - } - - render() { - const classes = classNames( - 'ui', - this.props.className, - 'statistics' - ) - return ( -
- {this.props.children} -
- ) - } -} diff --git a/src/views/Statistic/StatisticValue.js b/src/views/Statistic/StatisticValue.js index 3693a148cb..0d4031aadb 100644 --- a/src/views/Statistic/StatisticValue.js +++ b/src/views/Statistic/StatisticValue.js @@ -1,34 +1,47 @@ -import React, { Component, PropTypes } from 'react' -import classNames from 'classnames' +import cx from 'classnames' +import React, { PropTypes } from 'react' -import { getUnhandledProps } from '../../utils/propUtils' +import { customPropTypes, getUnhandledProps, useKeyOnly } from '../../utils/propUtils' import META from '../../utils/Meta' -export default class StatisticValue extends Component { - static propTypes = { - children: PropTypes.node.isRequired, - className: PropTypes.string, - } - - static _meta = { - library: META.library.semanticUI, - name: 'StatisticValue', - type: META.type.view, - parent: 'Statistic', - } - - render() { - const classes = classNames( - this.props.className, - 'value', - ) - - const props = getUnhandledProps(StatisticValue, this.props) - - return ( -
- {this.props.children} -
- ) - } +// TODO: This file has disabled shorthand props +// @see /~https://github.com/TechnologyAdvice/stardust/pull/334 + +function StatisticValue(props) { + // const { children, className, content, text } = props + const { children, className, text } = props + const classes = cx(useKeyOnly(text, 'text'), className, 'value') + const rest = getUnhandledProps(StatisticValue, props) + + // return
{children || content}
+ return
{children}
+} + +StatisticValue._meta = { + library: META.library.semanticUI, + name: 'StatisticValue', + parent: 'Statistic', + type: META.type.view, +} + +StatisticValue.propTypes = { + /** Primary content of the StatisticValue. */ + children: customPropTypes.all([ + customPropTypes.mutuallyExclusive(['content']), + PropTypes.node, + ]), + + /** Classes that will be added to the StatisticValue className. */ + className: PropTypes.string, + + // /** Primary content of the StatisticValue. Mutually exclusive with the children prop. */ + // content: customPropTypes.all([ + // customPropTypes.mutuallyExclusive(['children']), + // PropTypes.node, + // ]), + + /** Format the value with smaller font size to fit nicely beside number values. */ + text: PropTypes.bool, } + +export default StatisticValue diff --git a/test/specs/commonTests.js b/test/specs/commonTests.js index d42e66ee89..3e6d677664 100644 --- a/test/specs/commonTests.js +++ b/test/specs/commonTests.js @@ -6,6 +6,8 @@ import ReactDOMServer from 'react-dom/server' import META from 'src/utils/Meta' import * as stardust from 'stardust' +import * as sui from 'src/utils/semanticUtils' +import numberToWord from 'src/utils/numberToWord' import * as consoleUtil from 'test/utils/consoleUtil' import sandbox from 'test/utils/Sandbox-util' import * as syntheticEvent from 'test/utils/syntheticEvent' @@ -379,7 +381,7 @@ const _noDefaultClassNameFromProp = (Component, propKey, requiredProps = {}) => // SUI classes ought to be built up using a declarative component API const propOptions = _.get(Component, `_meta.props[${propKey}]`) _.each(propOptions, propVal => { - wrapper.should.not.have.className(propVal) + wrapper.should.not.have.className(propVal.toString()) }) }) } @@ -398,7 +400,7 @@ const _noClassNameFromBoolProps = (Component, propKey, requiredProps) => { wrapper.should.not.have.className('false') _.each(Component._meta.props[propKey], propVal => { - wrapper.should.not.have.className(propVal) + wrapper.should.not.have.className(propVal.toString()) }) })) } @@ -501,6 +503,27 @@ export const implementsImageProp = (Component, requiredProps = {}) => { }) } +/** + * Assert that a Component correctly implements the "widths" prop. + * @param {React.Component|Function} Component The component to test. + * @param {string} Prop name. + * @param {Object} [requiredProps={}] Props required to render the component. + */ +export const implementsNumberToWordProp = (Component, propKey, requiredProps = {}) => { + describe(`${propKey} (common)`, () => { + _definesPropOptions(Component, propKey) + _noDefaultClassNameFromProp(Component, propKey, requiredProps) + _noClassNameFromBoolProps(Component, propKey, requiredProps) + + it('adds prop value to className', () => { + const propVal = _.sample(sui.widths) + + shallow(createElement(Component, { ...requiredProps, [propKey]: propVal })) + .should.have.className(numberToWord(propVal)) + }) + }) +} + /** * Assert that only a Component prop's name is converted to className. * @param {React.Component|Function} Component The component to test. diff --git a/test/specs/utils/numberToWord-test.js b/test/specs/utils/numberToWord-test.js index 2f41103f7a..5846606707 100644 --- a/test/specs/utils/numberToWord-test.js +++ b/test/specs/utils/numberToWord-test.js @@ -24,4 +24,8 @@ describe('numberToWord', () => { it('returns words for numbers 1-16', () => { _.times(16, n => numberToWord(n + 1).should.equal(words[n])) }) + + it('returns word if input is word', () => { + words.forEach((word) => numberToWord(word).should.equal(word)) + }) }) diff --git a/test/specs/views/Stastistic/Statistic-test.js b/test/specs/views/Stastistic/Statistic-test.js index 12183426ea..5a5372ed54 100644 --- a/test/specs/views/Stastistic/Statistic-test.js +++ b/test/specs/views/Stastistic/Statistic-test.js @@ -1,28 +1,56 @@ +import faker from 'faker' +import React from 'react' +import * as common from 'test/specs/commonTests' + import Statistic from 'src/views/Statistic/Statistic' +import StatisticGroup from 'src/views/Statistic/StatisticGroup' import StatisticLabel from 'src/views/Statistic/StatisticLabel' import StatisticValue from 'src/views/Statistic/StatisticValue' -import StatisticStatistics from 'src/views/Statistic/StatisticStatistics' -import * as common from 'test/specs/commonTests' describe('Statistic', () => { common.isConformant(Statistic) - common.hasUIClassName(StatisticStatistics) + common.hasUIClassName(Statistic) + common.hasSubComponents(Statistic, [StatisticGroup, StatisticLabel, StatisticValue]) common.rendersChildren(Statistic) - common.hasSubComponents(Statistic, [StatisticLabel, StatisticValue, StatisticStatistics]) -}) -describe('StatisticLabel', () => { - common.isConformant(Statistic) - common.rendersChildren(Statistic) -}) + common.propValueOnlyToClassName(Statistic, 'color') + common.propKeyAndValueToClassName(Statistic, 'floated') + common.propKeyOnlyToClassName(Statistic, 'horizontal') + common.propKeyOnlyToClassName(Statistic, 'inverted') + common.propValueOnlyToClassName(Statistic, 'size') -describe('StatisticValue', () => { - common.isConformant(Statistic) - common.rendersChildren(Statistic) -}) + it('renders an div element', () => { + shallow() + .should.have.tagName('div') + }) + + it('renders StatisticLabel component with `label` prop', () => { + const text = faker.hacker.phrase() + const wrapper = mount() + const label = wrapper.find('StatisticLabel').first() + + wrapper.should.have.exactly(1).descendants('StatisticLabel') + label.should.contain.text(text) + }) -describe('Statistics', () => { - common.isConformant(StatisticStatistics) - common.hasUIClassName(StatisticStatistics) - common.rendersChildren(StatisticStatistics) + it('renders StatisticValue component and passes `text` prop', () => { + const text = faker.hacker.phrase() + const wrapper = mount() + const value = wrapper.find('StatisticValue').first() + + wrapper.should.have.exactly(1).descendants('StatisticValue') + value.should.contain.text(text) + value.should.have.prop('text', true) + }) + + it('renders StatisticValue component', () => { + const text = faker.hacker.phrase() + const wrapper = mount() + const value = wrapper.find('StatisticValue').first() + + wrapper.should.have.exactly(1).descendants('StatisticValue') + value.should.contain.text(text) + value.should.not.have.prop('text') + }) }) + diff --git a/test/specs/views/Stastistic/StatisticGroup-test.js b/test/specs/views/Stastistic/StatisticGroup-test.js new file mode 100644 index 0000000000..e7a248adb7 --- /dev/null +++ b/test/specs/views/Stastistic/StatisticGroup-test.js @@ -0,0 +1,26 @@ +import React from 'react' +import * as common from 'test/specs/commonTests' +import StatisticGroup from 'src/views/Statistic/StatisticGroup' + +describe('StatisticGroup', () => { + common.isConformant(StatisticGroup) + common.implementsNumberToWordProp(StatisticGroup, 'widths') + common.hasUIClassName(StatisticGroup) + common.rendersChildren(StatisticGroup) + common.propKeyOnlyToClassName(StatisticGroup, 'horizontal') + + it('renders an div element', () => { + shallow() + .should.have.tagName('div') + }) + + it('renders children with `items` prop', () => { + const items = [ + { label: 'Faves', value: 22 }, + { label: 'Views', value: '31,200' }, + ] + + shallow() + .should.have.exactly(2).descendants('Statistic') + }) +}) diff --git a/test/specs/views/Stastistic/StatisticLabel-test.js b/test/specs/views/Stastistic/StatisticLabel-test.js new file mode 100644 index 0000000000..dfb9ac35c1 --- /dev/null +++ b/test/specs/views/Stastistic/StatisticLabel-test.js @@ -0,0 +1,30 @@ +import React from 'react' +import * as common from 'test/specs/commonTests' + +import StatisticLabel from 'src/views/Statistic/StatisticLabel' + +describe('StatisticLabel', () => { + common.isConformant(StatisticLabel) + common.rendersChildren(StatisticLabel) + + it('renders an div element', () => { + shallow() + .should.have.tagName('div') + }) + + // describe('content prop', () => { + // it('renders child text', () => { + // const text = faker.hacker.phrase() + // + // shallow() + // .should.contain.text(text) + // }) + // + // it('renders child components', () => { + // const child =
+ // + // shallow() + // .should.contain(child) + // }) + // }) +}) diff --git a/test/specs/views/Stastistic/StatisticValue-test.js b/test/specs/views/Stastistic/StatisticValue-test.js new file mode 100644 index 0000000000..3b8cb77385 --- /dev/null +++ b/test/specs/views/Stastistic/StatisticValue-test.js @@ -0,0 +1,32 @@ +import React from 'react' +import * as common from 'test/specs/commonTests' + +import StatisticValue from 'src/views/Statistic/StatisticValue' + +describe('Statistic', () => { + common.isConformant(StatisticValue) + common.rendersChildren(StatisticValue) + common.propKeyOnlyToClassName(StatisticValue, 'text') + + it('renders an div element', () => { + shallow() + .should.have.tagName('div') + }) + + // describe('content prop', () => { + // it('renders child text', () => { + // const text = faker.hacker.phrase() + // + // shallow() + // .should.contain.text(text) + // }) + // + // it('renders child components', () => { + // const child =
+ // + // shallow() + // .should.contain(child) + // }) + // }) +}) +