Commit aac268d6 authored by Mickaël Bourgier's avatar Mickaël Bourgier
Browse files

Use Box component inside ListItem

parent fce14d5b
Pipeline #1003 passed with stage
in 1 minute and 47 seconds
......@@ -4,8 +4,10 @@ import classNames from 'classnames';
import warning from 'warning';
import { isObject } from '@webalt/utils';
import Box from '../Box';
import { withListContext } from '../List/List.context';
import { withStyles } from '../styles';
import multiplyUnit from '../utils/multiplyUnit';
import styles from './ListItem.styles';
......@@ -18,15 +20,25 @@ import styles from './ListItem.styles';
* - [ListItemText](/components/list-item-text) pour afficher du texte.
*/
class ListItem extends Component {
handleClick = (...args) => {
const { disabled, muted, onClick } = this.props;
if (onClick && !disabled && !muted) {
onClick(...args);
}
};
render() {
const {
children,
classes,
className,
clickable,
component: Component,
component = 'li',
listContext,
onClick,
theme,
variant = 'text',
color = variant !== 'text' ? 'primary' : undefined,
...otherProps
} = this.props;
......@@ -35,32 +47,41 @@ class ListItem extends Component {
`Le composant "ListItem" doit être utilisé à l'intérieur d'un composant "List"`
);
if (variant === 'gradient') {
// Add the paddingLeft here because JSS can't use props in nested style
if (!('style' in otherProps)) {
otherProps.style = {};
}
otherProps.style.paddingLeft = `calc(${multiplyUnit(
theme.components.ListItem.horizontalPadding,
listContext.depth + 1
)} + 1px)`;
}
return (
<Component
<Box
className={classNames(
classes.root,
{ [classes.clickable]: clickable },
{
[classes.clickable]: clickable,
[classes.gradientVariant]: variant === 'gradient',
[classes.noColor]: !color
},
className
)}
onClick={onClick}
color={color}
component={component}
onClick={clickable && onClick ? this.handleClick : undefined}
interactive={clickable}
variant={variant}
{...otherProps}
>
{children}
</Component>
/>
);
}
}
ListItem.propTypes = {
/**
* Composant à utiliser en tant que composant racine
*/
component: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.object
]),
/**
* Contenu du composant
*/
......@@ -81,13 +102,60 @@ ListItem.propTypes = {
*/
clickable: PropTypes.bool,
/**
* Couleur de l'élément, par défaut `'primary'` uniquement si la valeur de
* `variant` est différente de `'text'`
*/
color: PropTypes.oneOfType([
PropTypes.oneOf([
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark'
]),
PropTypes.string
]),
/**
* Composant à utiliser en tant que composant racine
*/
component: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.object
]),
/**
* Désactive l'élément : il perd sa couleur et devient gris en plus d'étre non
* cliquable (plus fort que `muted`)
*/
disabled: PropTypes.bool,
/** @ignore */
listContext: PropTypes.object,
/**
* Rend l'élément muet : il garde sa couleur mais devient peu visible et non
* cliquable (moins fort que `disabled`)
*/
muted: PropTypes.bool,
/** @ignore */
theme: PropTypes.object,
/**
* Fonction appelée lorsque l'élément est cliqué
*/
onClick: PropTypes.func
onClick: PropTypes.func,
/**
* Variante de l'élément
*/
variant: PropTypes.oneOf(['text', 'outline', 'plain', 'gradient'])
};
ListItem.defaultProps = {
......@@ -96,4 +164,6 @@ ListItem.defaultProps = {
onClick: () => {}
};
export default withListContext(withStyles(styles)(ListItem));
export default withListContext(
withStyles(styles, { withTheme: true })(ListItem)
);
......@@ -3,12 +3,15 @@ import formatUnit from '../utils/formatUnit';
export default theme => ({
root: {
alignItems: 'center',
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
textDecoration: 'none !important',
padding: `${formatUnit(
theme.components.ListItem.verticalPadding
)} ${formatUnit(theme.components.ListItem.horizontalPadding)}`,
paddingLeft: props =>
multiplyUnit(
theme.components.ListItem.horizontalPadding,
......@@ -24,14 +27,28 @@ export default theme => ({
theme.components.ListItem.verticalPadding,
1 / 2
)
},
'&$gradientVariant': {
padding: `calc(${formatUnit(
theme.components.ListItem.verticalPadding
)} + 1px) calc(${formatUnit(
theme.components.ListItem.horizontalPadding
)} + 1px)`
// Due to a JSS bug, paddingLeft is in `style` prop
}
},
clickable: {
cursor: 'pointer',
userSelect: 'none',
'&:hover': {
'&$noColor:hover': {
backgroundColor: theme.colors.background.hover
}
}
},
gradientVariant: {},
noColor: {}
});
import React from 'react';
import renderer from 'react-test-renderer';
import { SheetsRegistry } from 'react-jss';
import { createTheme } from '../styles';
import wrapToTest from '../utils/wrapToTest';
import List from '../List';
import ListItem from './ListItem';
describe('<ListItem />', () => {
let componentToTest;
let sheets;
let theme;
beforeEach(() => {
componentToTest = null;
sheets = null;
theme = null;
});
afterEach(() => {
if (componentToTest !== null) {
const options = {
...(sheets !== null ? { sheets } : {}),
...(theme !== null ? { theme } : {})
};
const component = renderer.create(wrapToTest(options)(componentToTest));
expect(component.toJSON()).toMatchSnapshot();
if (sheets !== null) {
expect(sheets.toString()).toMatchSnapshot();
}
}
});
test('Render without props', () => {
componentToTest = (
<List>
<ListItem />
</List>
);
sheets = new SheetsRegistry();
});
test('Could render a custom component', () => {
componentToTest = (
<List>
<ListItem component='p' />
</List>
);
});
test('Render with children', () => {
componentToTest = (
<List>
<ListItem>
Hello <strong>you</strong>
</ListItem>
</List>
);
});
test('Should include className and other props', () => {
componentToTest = (
<List>
<ListItem className='my-custom-class' myCustomProp='value' />
</List>
);
});
test('Render with clickable prop', () => {
componentToTest = (
<List>
<ListItem clickable />
</List>
);
});
test('Render with onClick prop', () => {
componentToTest = (
<List>
<ListItem onClick={() => {}} />
</List>
);
});
test('Render with custom paddings in theme', () => {
componentToTest = (
<List>
<ListItem />
</List>
);
sheets = new SheetsRegistry();
theme = createTheme({
components: {
ListItem: {
horizontalPadding: 100,
verticalPadding: 42
}
}
});
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<ListItem /> Could render a custom component 1`] = `
<ul
className="List-root-0-1-1"
>
<p
className="ListItem-root-0-1-2 ListItem-root-0-1-4"
onClick={[Function]}
/>
</ul>
`;
exports[`<ListItem /> Render with children 1`] = `
<ul
className="List-root-0-1-1"
>
<li
className="ListItem-root-0-1-2 ListItem-root-0-1-4"
onClick={[Function]}
>
Hello
<strong>
you
</strong>
</li>
</ul>
`;
exports[`<ListItem /> Render with clickable prop 1`] = `
<ul
className="List-root-0-1-1"
>
<li
className="ListItem-root-0-1-2 ListItem-root-0-1-4 ListItem-clickable-0-1-3"
onClick={[Function]}
/>
</ul>
`;
exports[`<ListItem /> Render with custom paddings in theme 1`] = `
<ul
className="List-root-0-1-1"
>
<li
className="ListItem-root-0-1-2 ListItem-root-0-1-4"
onClick={[Function]}
/>
</ul>
`;
exports[`<ListItem /> Render with custom paddings in theme 2`] = `
".List-root-0-1-1 {
margin: 0;
padding: 0;
list-style: none;
}
.ListItem-root-0-1-2 {
display: flex;
padding: 42px 100px;
align-items: center;
justify-content: flex-start;
}
.ListItem-root-0-1-2 > *:not(:first-child) {
margin-left: 21px;
}
.ListItem-root-0-1-2 > *:not(:last-child) {
margin-right: 21px;
}
.ListItem-clickable-0-1-3 {
cursor: pointer;
}
.ListItem-clickable-0-1-3:hover {
background-color: rgba(0, 0, 0, 0.08);
}
.ListItem-root-0-1-4 {
padding-left: 100px;
}"
`;
exports[`<ListItem /> Render with onClick prop 1`] = `
<ul
className="List-root-0-1-1"
>
<li
className="ListItem-root-0-1-2 ListItem-root-0-1-4"
onClick={[Function]}
/>
</ul>
`;
exports[`<ListItem /> Render without props 1`] = `
<ul
className="List-root-0-1-1"
>
<li
className="ListItem-root-0-1-2 ListItem-root-0-1-4"
onClick={[Function]}
/>
</ul>
`;
exports[`<ListItem /> Render without props 2`] = `
".List-root-0-1-1 {
margin: 0;
padding: 0;
list-style: none;
}
.ListItem-root-0-1-2 {
display: flex;
padding: 0.75rem 1.25rem;
align-items: center;
justify-content: flex-start;
}
.ListItem-root-0-1-2 > *:not(:first-child) {
margin-left: 0.375rem;
}
.ListItem-root-0-1-2 > *:not(:last-child) {
margin-right: 0.375rem;
}
.ListItem-clickable-0-1-3 {
cursor: pointer;
}
.ListItem-clickable-0-1-3:hover {
background-color: rgba(0, 0, 0, 0.08);
}
.ListItem-root-0-1-4 {
padding-left: 1.25rem;
}"
`;
exports[`<ListItem /> Should include className and other props 1`] = `
<ul
className="List-root-0-1-1"
>
<li
className="ListItem-root-0-1-2 ListItem-root-0-1-4 my-custom-class"
myCustomProp="value"
onClick={[Function]}
/>
</ul>
`;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment