-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1116 from cozy/figure-component
Figure component
- Loading branch information
Showing
10 changed files
with
705 additions
and
1 deletion.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import React from 'react' | ||
import Types from 'prop-types' | ||
import cx from 'classnames' | ||
import styles from './Figure.styl' | ||
|
||
/** | ||
* Shows a number, typically a balance or an important financial | ||
* number in a bold way. | ||
*/ | ||
const stylePositive = styles['Figure-content--positive'] | ||
const styleNegative = styles['Figure-content--negative'] | ||
const styleWarning = styles['Figure-content--warning'] | ||
const styleBig = styles['Figure--big'] | ||
const styleClickable = styles['Figure--clickable'] | ||
|
||
const Figure = props => { | ||
const { | ||
symbol, | ||
withCurrencySpacing = true, | ||
coloredPositive, | ||
coloredNegative, | ||
coloredWarning, | ||
warningLimit, | ||
signed, | ||
className, | ||
theme = 'default', | ||
total, | ||
totalClassName, | ||
currencyClassName, | ||
size, | ||
onClick, | ||
inline, | ||
blurred | ||
} = props | ||
|
||
let { decimalNumbers } = props | ||
decimalNumbers = isNaN(decimalNumbers) ? 2 : decimalNumbers | ||
|
||
const totalLocalized = | ||
typeof total === 'number' | ||
? total.toLocaleString('fr-FR', { | ||
minimumFractionDigits: decimalNumbers, | ||
maximumFractionDigits: decimalNumbers | ||
}) | ||
: total | ||
const isTotalPositive = total > 0 | ||
const isTotalInLimit = total > warningLimit | ||
const isWarning = !isTotalPositive && !isTotalInLimit && coloredWarning | ||
|
||
return ( | ||
<div | ||
className={cx( | ||
styles[theme], | ||
{ | ||
[stylePositive]: isTotalPositive && coloredPositive, | ||
[styleNegative]: | ||
total !== 0 && !isTotalPositive && !isWarning && coloredNegative, | ||
[styleWarning]: isWarning, | ||
[styleBig]: size == 'big', | ||
[styleClickable]: onClick, | ||
[styles.Figure_blur]: blurred, | ||
[styles['Figure--inline']]: inline | ||
}, | ||
className | ||
)} | ||
onClick={onClick} | ||
> | ||
<span className={cx(styles['Figure-total'], totalClassName)}> | ||
{isTotalPositive && signed && '+'} | ||
{totalLocalized} | ||
</span> | ||
{symbol && ( | ||
<span | ||
className={cx( | ||
styles['Figure-currency'], | ||
{ | ||
[styles['Figure__currency--withSpacing']]: withCurrencySpacing | ||
}, | ||
currencyClassName | ||
)} | ||
> | ||
{symbol} | ||
</span> | ||
)} | ||
</div> | ||
) | ||
} | ||
|
||
Figure.propTypes = { | ||
/** Number to display */ | ||
total: Types.oneOfType([Types.number, Types.string]).isRequired, | ||
/** Class name applied to the element wrapping the number */ | ||
totalClassName: Types.string, | ||
/** Currency to show */ | ||
symbol: Types.string, | ||
currencyClassName: Types.string, | ||
/** Colors positive numbers in green */ | ||
coloredPositive: Types.bool, | ||
/** Colors negative numbers in red */ | ||
coloredNegative: Types.bool, | ||
/** Displays the sign */ | ||
signed: Types.bool, | ||
/** Numbers of decimals to show (default=2) */ | ||
decimalNumbers: Types.number, | ||
/** Whether to add a specific class to show warning */ | ||
warningLimit: Types.number, | ||
/** Whether to add some spacing between the figure and the currency or not */ | ||
withCurrencySpacing: Types.bool, | ||
/** Blur the amount, useful for personal content (banking for example) */ | ||
blurred: Types.bool | ||
} | ||
|
||
export default Figure |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
```jsx | ||
<div> | ||
<Figure | ||
total={1000} | ||
symbol='€' | ||
coloredPositive coloredNegative signed /> | ||
|
||
<Figure | ||
total={-1000} | ||
symbol='€' | ||
coloredPositive coloredNegative signed /> | ||
|
||
<Figure | ||
total={-1000} | ||
symbol='€' | ||
signed /> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import React from 'react' | ||
import { shallow } from 'enzyme' | ||
import { flatten, merge } from 'lodash' | ||
import Figure from './Figure' | ||
|
||
const combine = (...iterables) => { | ||
if (iterables.length === 1) { | ||
return iterables[0].map(x => [x]) | ||
} else { | ||
const combinationsNMinus1 = combine.apply(null, iterables.slice(1)) | ||
return flatten( | ||
combinationsNMinus1.map(c => iterables[0].map(item => [item, ...c])) | ||
) | ||
} | ||
} | ||
|
||
const formatAttrs = attrs => { | ||
return Object.keys(attrs) | ||
.map(x => `${x}: ${attrs[x]}`) | ||
.join(', ') | ||
} | ||
|
||
describe('Figure', () => { | ||
const amounts = [-100, 100, 500, 4] | ||
|
||
const coloredAttributes = [ | ||
'coloredPositive', | ||
'coloredNegative', | ||
'coloredWarning' | ||
] | ||
|
||
const combinations = combine | ||
.apply(null, coloredAttributes.map(x => [{ [x]: true }, { [x]: false }])) | ||
.map(attrs => { | ||
return merge.apply(null, [{}, ...attrs]) | ||
}) | ||
|
||
for (let amount of amounts) { | ||
for (let attrs of combinations) { | ||
it(`should render correctly ${amount} ${formatAttrs(attrs)}`, () => { | ||
const el = shallow( | ||
<Figure warningLimit={110} total={amount} {...attrs} /> | ||
).getElement() | ||
expect(el).toMatchSnapshot() | ||
}) | ||
} | ||
} | ||
}) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
@require 'settings/breakpoints' | ||
|
||
.default | ||
&.Figure-currency | ||
color var(--coolGrey) | ||
|
||
&.Figure-content--positive | ||
color var(--emerald) | ||
|
||
.Figure-currency | ||
color var(--emerald) | ||
|
||
&.Figure-content--negative | ||
color var(--pomegranate) | ||
|
||
.Figure-currency | ||
color var(--pomegranate) | ||
|
||
&.Figure-content--warning | ||
color var(--texasRose) | ||
|
||
.Figure-currency | ||
color var(--texasRose) | ||
|
||
.primary | ||
color var(--white) | ||
|
||
.Figure-total | ||
font-weight 900 | ||
|
||
.Figure__currency--withSpacing | ||
margin-left .2em | ||
|
||
.Figure--big | ||
font-size 2rem | ||
line-height 2.625rem | ||
|
||
+small-screen() | ||
.Figure--big | ||
font-size 1.5rem | ||
line-height 1.75rem | ||
|
||
.Figure--clickable | ||
cursor pointer | ||
|
||
.Figure_blur | ||
filter blur(8px) | ||
|
||
.Figure--inline | ||
display inline |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import React from 'react' | ||
import Types from 'prop-types' | ||
import classNames from 'classnames' | ||
import Figure from './Figure' | ||
import styles from './FigureBlock.styl' | ||
import labelStyles from '../Label/styles.styl' | ||
|
||
const labelStyle = labelStyles['c-label'] | ||
|
||
/** | ||
* Shows a `Figure` with a label, useful for important numbers. | ||
* | ||
* A part from `className` and `label`, takes same properties | ||
* as `Figure`. | ||
*/ | ||
const FigureBlock = ({ | ||
className, | ||
label, | ||
total, | ||
symbol, | ||
coloredPositive, | ||
coloredNegative, | ||
signed, | ||
decimalNumbers = 0, | ||
figureClassName, | ||
withCurrencySpacing | ||
}) => ( | ||
<div className={classNames(styles['FigureBlock'], className)}> | ||
<div className={labelStyle}>{label}</div> | ||
<Figure | ||
size="big" | ||
className={classNames(styles['FigureBlock-figure'], figureClassName)} | ||
total={total} | ||
symbol={symbol} | ||
coloredPositive={coloredPositive} | ||
coloredNegative={coloredNegative} | ||
signed={signed} | ||
decimalNumbers={decimalNumbers} | ||
withCurrencySpacing={withCurrencySpacing} | ||
/> | ||
</div> | ||
) | ||
|
||
FigureBlock.propTypes = { | ||
/** Label of the figure */ | ||
label: Types.string.isRequired, | ||
/** Extra classname */ | ||
className: Types.string | ||
} | ||
|
||
export default FigureBlock |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
Pour montrer une KPI importante. | ||
|
||
```jsx | ||
<div> | ||
<FigureBlock | ||
label='Balance totale' | ||
total={1000} | ||
symbol='€' | ||
coloredPositive coloredNegative signed /> | ||
|
||
<FigureBlock | ||
label='Balance totale (negative number)' | ||
total={-1000} | ||
symbol='€' | ||
coloredPositive coloredNegative signed /> | ||
|
||
<FigureBlock | ||
label='Balance totale (no color)' | ||
total={-1000} | ||
symbol='€' | ||
signed /> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
@require 'settings/breakpoints' | ||
|
||
.FigureBlock | ||
color var(--charcoalGrey) | ||
|
||
.FigureBlock-figure | ||
font-size 2rem | ||
line-height 2.625rem | ||
|
||
+small-screen() | ||
.FigureBlock | ||
font-size .7em |
Oops, something went wrong.