Skip to content

Commit 18a2ef7

Browse files
TheSharpieOneeddywashere
authored andcommitted
feat(inputGroup): add InputGroup components (#99)
Resolves #74 Add InputGroup with size prop Add InputGroupAddon Change Input to add addon prop for radio/checkbox to not `add form-check-input` class Add InputGroupButton with convinence shorthand when only a single string is passed Add tests for all of the above Add documention
1 parent ccc56f4 commit 18a2ef7

18 files changed

Lines changed: 580 additions & 1 deletion
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
2+
import React from 'react';
3+
import { PrismCode } from 'react-prism';
4+
import Helmet from 'react-helmet';
5+
import OverviewExample from '../examples/InputGroupOverview';
6+
const OverviewExampleSource = require('!!raw!../examples/InputGroupOverview.jsx');
7+
import AddonExample from '../examples/InputGroupAddon';
8+
const AddonExampleSource = require('!!raw!../examples/InputGroupAddon.jsx');
9+
import AddonSizingExample from '../examples/InputGroupSizing';
10+
const AddonSizingExampleSource = require('!!raw!../examples/InputGroupSizing.jsx');
11+
import ButtonExample from '../examples/InputGroupButton';
12+
const ButtonExampleSource = require('!!raw!../examples/InputGroupButton.jsx');
13+
import ButtonShorthandExample from '../examples/InputGroupButtonShorthand';
14+
const ButtonShorthandExampleSource = require('!!raw!../examples/InputGroupButtonShorthand.jsx');
15+
16+
export default class InputGroupPage extends React.Component {
17+
constructor(props) {
18+
super(props);
19+
20+
this.toggle = this.toggle.bind(this);
21+
this.state = {
22+
dropdownOpen: false
23+
};
24+
}
25+
26+
toggle() {
27+
this.setState({
28+
dropdownOpen: !this.state.dropdownOpen
29+
});
30+
}
31+
32+
render() {
33+
return (
34+
<div>
35+
<Helmet title="Input Group" />
36+
<h3>Input Group</h3>
37+
<div className="docs-example">
38+
<OverviewExample />
39+
</div>
40+
<pre>
41+
<PrismCode className="language-jsx">
42+
{OverviewExampleSource}
43+
</PrismCode>
44+
</pre>
45+
<h4>Properties</h4>
46+
<pre>
47+
<PrismCode className="language-jsx">
48+
{`InputGroup.propTypes = {
49+
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
50+
size: PropTypes.string,
51+
className: PropTypes.any
52+
};
53+
54+
InputGroupAddOn.propTypes = {
55+
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
56+
className: PropTypes.any
57+
};
58+
59+
InputGroupButton.propTypes = {
60+
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
61+
children: PropTypes.node,
62+
groupClassName: PropTypes.any, // only used in shorthand
63+
groupAttributes: PropTypes.object, // only used in shorthand
64+
className: PropTypes.any
65+
};`}
66+
</PrismCode>
67+
</pre>
68+
<h3>Addons</h3>
69+
<div className="docs-example">
70+
<div>
71+
<AddonExample />
72+
</div>
73+
</div>
74+
<pre>
75+
<PrismCode className="language-jsx">
76+
{AddonExampleSource}
77+
</PrismCode>
78+
</pre>
79+
80+
<h3>Addon Sizing</h3>
81+
<div className="docs-example">
82+
<div>
83+
<AddonSizingExample />
84+
</div>
85+
</div>
86+
<pre>
87+
<PrismCode className="language-jsx">
88+
{AddonSizingExampleSource}
89+
</PrismCode>
90+
</pre>
91+
92+
<h3>Buttons / Dropdowns</h3>
93+
<div className="docs-example">
94+
<div>
95+
<ButtonExample />
96+
</div>
97+
</div>
98+
<pre>
99+
<PrismCode className="language-jsx">
100+
{ButtonExampleSource}
101+
</PrismCode>
102+
</pre>
103+
104+
<h3>Button Shorthand</h3>
105+
<p>
106+
Button shorthand is a convenience method for adding just a button. It is triggered when only a single string
107+
is the child. A Button will be created and all of the props will be passed to it with the exception of
108+
<code>groupClassName</code> and <code>groupAttributes</code>, which are used to added classes and attributes
109+
to the wrapping container. This means you can add your <code>onClick</code> and other handlers directly to
110+
<code>InputGroupButton</code>. If you want your string to not be wrapped in a button, then you really want to
111+
use <code>InputGroupAddon</code> (see Addons above for that).
112+
</p>
113+
<div className="docs-example">
114+
<div>
115+
<ButtonShorthandExample />
116+
</div>
117+
</div>
118+
<pre>
119+
<PrismCode className="language-jsx">
120+
{ButtonShorthandExampleSource}
121+
</PrismCode>
122+
</pre>
123+
</div>
124+
);
125+
}
126+
}

docs/lib/Components/index.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class Components extends React.Component {
3939
name: 'Form',
4040
to: '/components/form/'
4141
},
42+
{
43+
name: 'Input Group',
44+
to: '/components/input-group/'
45+
},
4246
{
4347
name: 'Breadscrumbs',
4448
to: '/components/breadcrumbs/'
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import { InputGroup, InputGroupAddon, Input } from 'reactstrap';
3+
4+
const Example = (props) => {
5+
return (
6+
<div>
7+
<InputGroup>
8+
<InputGroupAddon>To the Left!</InputGroupAddon>
9+
<Input />
10+
</InputGroup>
11+
<br />
12+
<InputGroup>
13+
<Input />
14+
<InputGroupAddon>To the Right!</InputGroupAddon>
15+
</InputGroup>
16+
<br />
17+
<InputGroup>
18+
<InputGroupAddon>To the Left!</InputGroupAddon>
19+
<Input placeholder="and..." />
20+
<InputGroupAddon>To the Right!</InputGroupAddon>
21+
</InputGroup>
22+
</div>
23+
);
24+
};
25+
26+
export default Example;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { InputGroup, InputGroupButton, Input, Button } from 'reactstrap';
3+
import ButtonDropdownExample from './ButtonDropdown';
4+
5+
const Example = (props) => {
6+
return (
7+
<div>
8+
<InputGroup>
9+
<InputGroupButton><Button>I'm a button</Button></InputGroupButton>
10+
<Input />
11+
</InputGroup>
12+
<br />
13+
<InputGroup>
14+
<Input />
15+
<InputGroupButton><ButtonDropdownExample /></InputGroupButton>
16+
</InputGroup>
17+
<br />
18+
<InputGroup>
19+
<InputGroupButton><ButtonDropdownExample /></InputGroupButton>
20+
<Input placeholder="and..." />
21+
<InputGroupButton><Button color="secondary">I'm a button</Button></InputGroupButton>
22+
</InputGroup>
23+
</div>
24+
);
25+
};
26+
27+
export default Example;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import { InputGroup, InputGroupButton, Input } from 'reactstrap';
3+
4+
const Example = (props) => {
5+
return (
6+
<div>
7+
<InputGroup>
8+
<InputGroupButton>To the Left!</InputGroupButton>
9+
<Input />
10+
</InputGroup>
11+
<br />
12+
<InputGroup>
13+
<Input />
14+
<InputGroupButton color="secondary">To the Right!</InputGroupButton>
15+
</InputGroup>
16+
<br />
17+
<InputGroup>
18+
<InputGroupButton color="danger">To the Left!</InputGroupButton>
19+
<Input placeholder="and..." />
20+
<InputGroupButton color="success">To the Right!</InputGroupButton>
21+
</InputGroup>
22+
</div>
23+
);
24+
};
25+
26+
export default Example;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import { InputGroup, InputGroupAddon, Input } from 'reactstrap';
3+
4+
const Example = (props) => {
5+
return (
6+
<div>
7+
<InputGroup>
8+
<InputGroupAddon>@</InputGroupAddon>
9+
<Input placeholder="username" />
10+
</InputGroup>
11+
<br />
12+
<InputGroup>
13+
<InputGroupAddon>
14+
<Input addon type="checkbox" aria-label="Checkbox for following text input" />
15+
</InputGroupAddon>
16+
<Input placeholder="Check it out" />
17+
</InputGroup>
18+
<br />
19+
<InputGroup>
20+
<Input placeholder="username" />
21+
<InputGroupAddon>@example.com</InputGroupAddon>
22+
</InputGroup>
23+
<br />
24+
<InputGroup>
25+
<InputGroupAddon>$</InputGroupAddon>
26+
<InputGroupAddon>$</InputGroupAddon>
27+
<Input placeholder="Dolla dolla billz yo!" />
28+
<InputGroupAddon>$</InputGroupAddon>
29+
<InputGroupAddon>$</InputGroupAddon>
30+
</InputGroup>
31+
<br />
32+
<InputGroup>
33+
<InputGroupAddon>$</InputGroupAddon>
34+
<Input placeholder="Amount" type="number" step="1" />
35+
<InputGroupAddon>.00</InputGroupAddon>
36+
</InputGroup>
37+
</div>
38+
);
39+
};
40+
41+
export default Example;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import { InputGroup, InputGroupAddon, Input } from 'reactstrap';
3+
4+
const Example = (props) => {
5+
return (
6+
<div>
7+
<InputGroup size="lg">
8+
<InputGroupAddon>@lg</InputGroupAddon>
9+
<Input />
10+
</InputGroup>
11+
<br />
12+
<InputGroup>
13+
<InputGroupAddon>@normal</InputGroupAddon>
14+
<Input />
15+
</InputGroup>
16+
<br />
17+
<InputGroup size="sm">
18+
<InputGroupAddon>@sm</InputGroupAddon>
19+
<Input />
20+
</InputGroup>
21+
</div>
22+
);
23+
};
24+
25+
export default Example;

docs/lib/routes.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import ButtonGroupPage from './Components/ButtonGroupPage';
1010
import ButtonDropdownPage from './Components/ButtonDropdownPage';
1111
import DropdownsPage from './Components/DropdownsPage';
1212
import FormPage from './Components/FormPage';
13+
import InputGroupPage from './Components/InputGroupPage';
1314
import PopoversPage from './Components/PopoversPage';
1415
import TooltipsPage from './Components/TooltipsPage';
1516
import TagsPage from './Components/TagsPage';
@@ -31,6 +32,7 @@ const routes = (
3132
<Route path="button-dropdown/" component={ButtonDropdownPage} />
3233
<Route path="dropdowns/" component={DropdownsPage} />
3334
<Route path="form/" component={FormPage} />
35+
<Route path="input-group/" component={InputGroupPage} />
3436
<Route path="popovers/" component={PopoversPage} />
3537
<Route path="tooltips/" component={TooltipsPage} />
3638
<Route path="tags/" component={TagsPage} />

src/Input.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const propTypes = {
88
state: PropTypes.string,
99
tag: PropTypes.string,
1010
static: PropTypes.bool,
11+
addon: PropTypes.bool,
1112
className: PropTypes.string,
1213
};
1314

@@ -23,6 +24,7 @@ const Input = (props) => {
2324
size,
2425
state,
2526
tag,
27+
addon,
2628
static: staticInput,
2729
...attributes,
2830
} = props;
@@ -42,7 +44,11 @@ const Input = (props) => {
4244
} else if (fileInput) {
4345
formControlClass = `${formControlClass}-file`;
4446
} else if (checkInput) {
45-
formControlClass = 'form-check-input';
47+
if (addon) {
48+
formControlClass = null;
49+
} else {
50+
formControlClass = 'form-check-input';
51+
}
4652
}
4753

4854
const classes = classNames(

src/InputGroup.jsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { PropTypes } from 'react';
2+
import classNames from 'classnames';
3+
4+
const propTypes = {
5+
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
6+
size: PropTypes.string,
7+
className: PropTypes.any
8+
};
9+
10+
const defaultProps = {
11+
tag: 'div'
12+
};
13+
14+
const InputGroup = (props) => {
15+
const {
16+
className,
17+
tag: Tag,
18+
size,
19+
...attributes
20+
} = props;
21+
const classes = classNames(
22+
className,
23+
'input-group',
24+
size ? `input-group-${size}` : null
25+
);
26+
27+
return (
28+
<Tag {...attributes} className={classes} />
29+
);
30+
};
31+
32+
InputGroup.propTypes = propTypes;
33+
InputGroup.defaultProps = defaultProps;
34+
35+
export default InputGroup;

0 commit comments

Comments
 (0)