Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement table component #444

Merged
merged 9 commits into from
Dec 22, 2018
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import CarouselImage from './CarouselImage';
import Chart from './Chart';
import CheckboxGroup from './CheckboxGroup';
import CheckboxToggle from './CheckboxToggle';
import Column from './Column';
import Dataset from './Dataset';
import GMap from './GMap';
import Input from './Input';
Expand All @@ -34,6 +35,7 @@ import Slider from './Slider';
import Spinner from './Spinner';
import Tab from './Tab';
import Tabset from './Tabset';
import Table from './Table';
import Textarea from './Textarea';
import VerticalItem from './VerticalItem';
import VerticalNavigation from './VerticalNavigation';
Expand All @@ -54,6 +56,7 @@ export {
CarouselCard,
CarouselImage,
Chart,
Column,
CheckboxGroup,
CheckboxToggle,
Dataset,
Expand All @@ -77,6 +80,7 @@ export {
Spinner,
Tab,
Tabset,
Table,
Textarea,
VerticalItem,
VerticalNavigation,
Expand Down
24 changes: 24 additions & 0 deletions src/components/Column/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* eslint-disable react/no-unused-prop-types */
import React from 'react';
import PropTypes from 'prop-types';

export default function Column() {
return <div />;
}

Column.propTypes = {
/* The header of the column */
header: PropTypes.oneOfType([
PropTypes.node,
PropTypes.string,
]),
/** The component with wich to render the content of each cell */
component: PropTypes.func,
/** The field to display */
field: PropTypes.string.isRequired,
};

Column.defaultProps = {
header: undefined,
component: undefined,
};
42 changes: 42 additions & 0 deletions src/components/Column/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#### simple Column

const { FontAwesomeIcon } = require('@fortawesome/react-fontawesome');
const {
faCog,
faPencilAlt,
faStore,
faPlus,
faBell,
faEllipsisV,
} = require('@fortawesome/free-solid-svg-icons');

const tableData = [
{
name: 'A',
company: 'Google',
email: 'a@gmail.com',
},
{
name: 'B',
company: 'Facebook',
email: 'b@gmail.com',
}
];

const CellComponent = ({ value }) => <Badge label={value} variant="inverse" />;

const tableStyles = { paddingBottom: '46px' };

<div className="rainbow-p-bottom_xx-large">
<GlobalHeader className="rainbow-m-bottom_xx-large" src="images/user/user3.jpg">
<ButtonGroup className="rainbow-m-right_medium">
<ButtonIcon variant="border-filled" disabled icon={<FontAwesomeIcon icon={faCog} />} />
<ButtonIcon variant="border-filled" disabled icon={<FontAwesomeIcon icon={faEllipsisV} />} />
</ButtonGroup>
</GlobalHeader>
<Table data={tableData} style={tableStyles}>
<Column header="Name" field="name" />
<Column header="Company" field="company" />
<Column header="email" field="email" component={CellComponent} />
</Table>
</div>
18 changes: 18 additions & 0 deletions src/components/Table/__test__/resolve-columns.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import Column from '../../Column';
import resolveColumns from '../resolve-columns';

describe('resolveColumns', () => {
it('should return an array with the columns props', () => {
const children = [
<Column field="a" header="header" component={<span />} />,
];

const columns = resolveColumns(children);
expect(columns).toEqual([{
field: 'a',
header: 'header',
component: <span />,
}]);
});
});
58 changes: 58 additions & 0 deletions src/components/Table/__test__/table.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { mount } from 'enzyme';
import Table from '../index';
import Column from '../../Column';

const data = [
{
name: 'a',
number: 23,
},
];

const CellComponent = ({ value }) => <span>{value}</span>;

describe('<Table />', () => {
it('should return a table with one column', () => {
const component = mount(
<Table data={data}>
<Column field="name" header="Name" />
</Table>,
);

const header = component.find('th');
const cell = component.find('td');

expect(header.text()).toBe('Name');
expect(cell.text()).toBe('a');
});
it('should render the component passed to the column', () => {
const component = mount(
<Table data={data}>
<Column field="name" header="Name" component={CellComponent} />
</Table>,
);

expect(component.find(CellComponent).exists()).toBe(true);
});
it('should add a column', () => {
const component = mount(
<Table data={data}>
<Column field="name" header="Name" />
</Table>,
);

expect(component.find('td').text()).toBe('a');
component.setProps({
children: [
<Column field="name" header="Name" />,
<Column field="number" />,
],
});
component.update();

expect(component.find('td').at(0).text()).toBe('a');
expect(component.find('td').at(1).text()).toBe('23');
});
});
48 changes: 48 additions & 0 deletions src/components/Table/body/__test__/body.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { mount } from 'enzyme';
import Body from '../';

const columns = [{
component: undefined,
field: 'name',
}];

const data = [
{
name: 'a',
},
{
name: 'b',
},
];

describe('<Rowx />', () => {
it('should return an empty component if no data and columns are passed', () => {
const component = mount(<Body />);
expect(component.children().length).toBe(0);
});

it('should return an empty component if data or columns are not arrays', () => {
const component = mount(<Body columns={{}} data={[]} />);
expect(component.children().length).toBe(0);
});

it('should return an array of Row components', () => {
const component = mount(<Body data={data} columns={columns} />);
const rows = component.find('Row');

expect(rows.length).toBe(2);
expect(rows.get(0).props).toEqual({
data: {
name: 'a',
},
columns,
});
expect(rows.get(1).props).toEqual({
data: {
name: 'b',
},
columns,
});
});
});
19 changes: 19 additions & 0 deletions src/components/Table/body/__test__/cell.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { mount } from 'enzyme';
import Cell from '../cell';

const CellComponent = ({ value }) => <h1>{value}</h1>;

describe('<Cell />', () => {
it('should render a td component with text "cell-1" ', () => {
const component = mount(<Cell value="cell-1" />);
const td = component.find('td');
expect(td.text()).toBe('cell-1');
});
it('should render a td with a component to display de value', () => {
const component = mount(<Cell value="cell-2" component={CellComponent} />);
const td = component.find('td');
expect(td.find('h1').text()).toBe('cell-2');
});
});
38 changes: 38 additions & 0 deletions src/components/Table/body/__test__/row.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import { mount } from 'enzyme';
import Row from '../row';

const data = { name: 'a', number: 26 };

const columns = [
{
component: undefined,
field: 'name',
},
{
component: undefined,
field: 'number',
},
];

describe('<Row />', () => {
it('should return a tr element with no children when columns is not passed', () => {
const component = mount(<Row data={data} columns={undefined} />);
expect(component.find('tr').children().length).toBe(0);
});
it('should return the amount of Cell components that correspond with the columns', () => {
const component = mount(<Row data={data} columns={columns} />);
const trElement = component.find('tr');
const cell = trElement.find('Cell');

expect(cell.length).toBe(2);
expect(cell.get(0).props).toEqual({
component: undefined,
value: 'a',
});
expect(cell.get(1).props).toEqual({
component: undefined,
value: 26,
});
});
});
37 changes: 37 additions & 0 deletions src/components/Table/body/cell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';

function CellValue({ component: CellComponent, value }) {
if (CellComponent) {
return <CellComponent value={value} />;
}
return <span>{value}</span>;
}

CellValue.propTypes = {
component: PropTypes.func,
value: PropTypes.any,
};

CellValue.defaultProps = {
component: undefined,
value: undefined,
};

export default function Cell({ component, value }) {
return (
<td className="rainbow-table_cell">
<CellValue component={component} value={value} />
</td>
);
}

Cell.propTypes = {
component: PropTypes.func,
value: PropTypes.any,
};

Cell.defaultProps = {
component: undefined,
value: undefined,
};
24 changes: 24 additions & 0 deletions src/components/Table/body/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import Row from './row';
import { uniqueId } from '../../../libs/utils';

export default function Body(props) {
const { data, columns } = props;
if (Array.isArray(data) && Array.isArray(columns)) {
return data.map(item => (
<Row key={uniqueId('row')} data={item} columns={columns} />
));
}
return null;
}

Body.propTypes = {
data: PropTypes.array,
columns: PropTypes.array,
};

Body.defaultProps = {
data: [],
columns: [],
};
26 changes: 26 additions & 0 deletions src/components/Table/body/row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import PropTypes from 'prop-types';
import { uniqueId } from '../../../libs/utils';
import Cell from './cell';

export default function Row(props) {
const { data, columns } = props;
const cells = columns.map(({ component, field }) => (
<Cell key={uniqueId('cell')} component={component} value={data[field]} />
));
return (
<tr className="rainbow-table_body-row">
{cells}
</tr>
);
}

Row.propTypes = {
data: PropTypes.object,
columns: PropTypes.array,
};

Row.defaultProps = {
data: [],
columns: [],
};
22 changes: 22 additions & 0 deletions src/components/Table/head/__test__/head.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { mount } from 'enzyme';
import Head from '../';

describe('<Head />', () => {
it('should return an array of th elements', () => {
const columns = [
{ header: 'header' },
{ header: 'header-2' },
];
const component = mount(<Head columns={columns} />);
const head = component.find('th');

expect(head.length).toBe(2);
expect(head.get(0).props.children).toBe('header');
expect(head.get(1).props.children).toBe('header-2');
});
it('should return null if no columns is passed', () => {
const component = mount(<Head />);
expect(component.children().length).toBe(0);
});
});
Loading