Skip to content

Commit 69ada73

Browse files
committed
feat(Layout): Add Container, Row, Col components
1 parent 0e741b9 commit 69ada73

7 files changed

Lines changed: 258 additions & 0 deletions

File tree

lib/Col.jsx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React, { PropTypes } from 'react';
2+
import classNames from 'classnames';
3+
4+
const colSizes = ['xs', 'sm', 'md', 'lg', 'xl'];
5+
const stringOrNumberProp = PropTypes.oneOfType([PropTypes.number, PropTypes.string]);
6+
7+
const columnProps = PropTypes.oneOfType([
8+
PropTypes.string,
9+
PropTypes.number,
10+
PropTypes.shape({
11+
size: stringOrNumberProp,
12+
push: stringOrNumberProp,
13+
pull: stringOrNumberProp,
14+
offset: stringOrNumberProp
15+
})
16+
]);
17+
18+
const propTypes = {
19+
xs: columnProps,
20+
sm: columnProps,
21+
md: columnProps,
22+
lg: columnProps,
23+
xl: columnProps
24+
};
25+
26+
const defaultProps = {
27+
xs: 12
28+
};
29+
30+
class Col extends React.Component {
31+
constructor(props) {
32+
super(props);
33+
}
34+
35+
getColumnClasses() {
36+
let classes = [];
37+
38+
colSizes.forEach(colSize => {
39+
let columnProp = this.props[colSize];
40+
41+
if (!columnProp) {
42+
return;
43+
} else if (columnProp.size) {
44+
classes.push(classNames({
45+
[`col-${colSize}-${columnProp.size}`]: columnProp.size,
46+
[`col-${colSize}-push-${columnProp.push}`]: columnProp.push,
47+
[`col-${colSize}-pull-${columnProp.pull}`]: columnProp.pull,
48+
[`col-${colSize}-offset-${columnProp.offset}`]: columnProp.offset
49+
}));
50+
} else {
51+
classes.push(`col-${colSize}-${columnProp}`);
52+
}
53+
});
54+
55+
return classes;
56+
}
57+
58+
render() {
59+
const {
60+
className,
61+
...attributes
62+
} = this.props;
63+
64+
const classes = classNames(
65+
className,
66+
this.getColumnClasses()
67+
);
68+
69+
return (
70+
<div {...attributes} className={classes}/>
71+
);
72+
}
73+
}
74+
75+
Col.propTypes = propTypes;
76+
Col.defaultProps = defaultProps;
77+
78+
export default Col;

lib/Container.jsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React, { PropTypes } from 'react';
2+
import classNames from 'classnames';
3+
4+
const propTypes = {
5+
fluid: PropTypes.bool
6+
};
7+
8+
const defaultProps = {};
9+
10+
class Container extends React.Component {
11+
constructor(props) {
12+
super(props);
13+
}
14+
15+
render() {
16+
const {
17+
className,
18+
fluid,
19+
...attributes
20+
} = this.props;
21+
22+
const classes = classNames(
23+
className,
24+
fluid ? 'container-fluid' : 'container'
25+
);
26+
27+
return (
28+
<div {...attributes} className={classes}/>
29+
);
30+
}
31+
}
32+
33+
Container.propTypes = propTypes;
34+
Container.defaultProps = defaultProps;
35+
36+
export default Container;

lib/Row.jsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import classNames from 'classnames';
3+
4+
const propTypes = {};
5+
6+
const defaultProps = {};
7+
8+
class Row extends React.Component {
9+
constructor(props) {
10+
super(props);
11+
}
12+
13+
render() {
14+
const {
15+
className,
16+
...attributes
17+
} = this.props;
18+
19+
const classes = classNames(
20+
className,
21+
'row'
22+
);
23+
24+
return (
25+
<div {...attributes} className={classes}/>
26+
);
27+
}
28+
}
29+
30+
Row.propTypes = propTypes;
31+
Row.defaultProps = defaultProps;
32+
33+
export default Row;

lib/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import Container from './Container';
2+
import Row from './Row';
3+
import Col from './Col';
14
import Button from './Button';
25
import ButtonDropdown from './ButtonDropdown';
36
import ButtonGroup from './ButtonGroup';
@@ -19,6 +22,9 @@ import TetherContent from './TetherContent';
1922
import Tooltip from './Tooltip';
2023

2124
export {
25+
Container,
26+
Row,
27+
Col,
2228
Button,
2329
ButtonDropdown,
2430
ButtonGroup,

test/Col.spec.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
2+
import React from 'react';
3+
import { shallow } from 'enzyme';
4+
import { Col } from 'reactstrap';;
5+
6+
describe('Col', () => {
7+
it('should render default .col-* markup', () => {
8+
const wrapper = shallow(<Col/>);
9+
10+
expect(wrapper.html()).toBe('<div class="col-xs-12"></div>');
11+
});
12+
13+
it('should render children', () => {
14+
const wrapper = shallow(<Col>Children</Col>);
15+
16+
expect(wrapper.text()).toBe('Children');
17+
});
18+
19+
it('should pass additional classNames', () => {
20+
const wrapper = shallow(<Col className="extra"/>);
21+
22+
expect(wrapper.hasClass('extra')).toBe(true);
23+
expect(wrapper.hasClass('col-xs-12')).toBe(true);
24+
});
25+
26+
it('should pass col size specific classes as Strings', () => {
27+
const wrapper = shallow(<Col sm="6"/>);
28+
29+
expect(wrapper.hasClass('col-sm-6')).toBe(true);
30+
expect(wrapper.hasClass('col-xs-12')).toBe(true);
31+
});
32+
33+
it('should pass col size specific classes as Numbers', () => {
34+
const wrapper = shallow(<Col sm={6}/>);
35+
36+
expect(wrapper.hasClass('col-sm-6')).toBe(true);
37+
expect(wrapper.hasClass('col-xs-12')).toBe(true);
38+
});
39+
40+
it('should pass col size specific classes via Objects', () => {
41+
const wrapper = shallow(<Col sm={{ size: 6, push: 2, pull: 2, offset: 2 }}/>);
42+
43+
expect(wrapper.hasClass('col-sm-6')).toBe(true);
44+
expect(wrapper.hasClass('col-xs-12')).toBe(true);
45+
expect(wrapper.hasClass('col-sm-push-2')).toBe(true);
46+
expect(wrapper.hasClass('col-sm-pull-2')).toBe(true);
47+
expect(wrapper.hasClass('col-sm-offset-2')).toBe(true);
48+
});
49+
});

test/Container.spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
2+
import React from 'react';
3+
import { shallow } from 'enzyme';
4+
import { Container } from 'reactstrap';;
5+
6+
describe('Container', () => {
7+
it('should render .container markup', () => {
8+
const wrapper = shallow(<Container/>);
9+
10+
expect(wrapper.html()).toBe('<div class="container"></div>');
11+
});
12+
13+
it('should render .container-fluid markup', () => {
14+
const wrapper = shallow(<Container fluid/>);
15+
16+
expect(wrapper.html()).toBe('<div class="container-fluid"></div>');
17+
});
18+
19+
it('should render children', () => {
20+
const wrapper = shallow(<Container>Children</Container>);
21+
22+
expect(wrapper.html()).toBe('<div class="container">Children</div>');
23+
});
24+
25+
it('should pass additional classNames', () => {
26+
const wrapper = shallow(<Container className="extra"/>);
27+
28+
expect(wrapper.hasClass('extra')).toBe(true);
29+
expect(wrapper.hasClass('container')).toBe(true);
30+
});
31+
});

test/Row.spec.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
2+
import React from 'react';
3+
import { shallow } from 'enzyme';
4+
import { Row } from 'reactstrap';;
5+
6+
describe('Row', () => {
7+
it('should render .row markup', () => {
8+
const wrapper = shallow(<Row/>);
9+
10+
expect(wrapper.html()).toBe('<div class="row"></div>');
11+
});
12+
13+
it('should render children', () => {
14+
const wrapper = shallow(<Row>Children</Row>);
15+
16+
expect(wrapper.html()).toBe('<div class="row">Children</div>');
17+
});
18+
19+
it('should pass additional classNames', () => {
20+
const wrapper = shallow(<Row className="extra"/>);
21+
22+
expect(wrapper.hasClass('extra')).toBe(true);
23+
expect(wrapper.hasClass('row')).toBe(true);
24+
});
25+
});

0 commit comments

Comments
 (0)