From bfb3e6c02cd80488c4a41962d4fc61eb6ec5afdd Mon Sep 17 00:00:00 2001
From: Matthew Smith
Date: Fri, 27 Mar 2015 11:36:08 -0600
Subject: [PATCH] [added] `standalone` prop to Input, which will not render the
`form-group` class
In some cases you may not want the `form-group` class applied to form
input wrapper divs. To achieve this simply apply the `standalone` prop.
Fixes #205
---
docs/src/ComponentsPage.js | 2 +-
src/FormGroup.js | 33 +++++++++++++++
src/Input.js | 44 +++++++------------
test/FormGroupSpec.js | 86 ++++++++++++++++++++++++++++++++++++++
test/InputSpec.js | 24 +++++++++++
5 files changed, 159 insertions(+), 30 deletions(-)
create mode 100644 src/FormGroup.js
create mode 100644 test/FormGroupSpec.js
diff --git a/docs/src/ComponentsPage.js b/docs/src/ComponentsPage.js
index ed47b8ad17..3eadb5e979 100644
--- a/docs/src/ComponentsPage.js
+++ b/docs/src/ComponentsPage.js
@@ -548,7 +548,7 @@ const ComponentsPage = React.createClass({
Renders an input in bootstrap wrappers. Supports label, help, text input add-ons, validation and use as wrapper.
Use getValue()
or getChecked()
to get the current state.
- The helper method getInputDOMNode()
returns the internal input element.
+ The helper method getInputDOMNode()
returns the internal input element. If you don't want the form-group
class applied apply the prop named standalone
.
Supports select
, textarea
, static
as well as standard HTML input types. getValue()
returns an array for multiple select.
diff --git a/src/FormGroup.js b/src/FormGroup.js
new file mode 100644
index 0000000000..0bde453978
--- /dev/null
+++ b/src/FormGroup.js
@@ -0,0 +1,33 @@
+import React from 'react';
+import classSet from 'classnames';
+
+class FormGroup extends React.Component {
+ render() {
+ let classes = {
+ 'form-group': !this.props.standalone,
+ 'has-feedback': this.props.hasFeedback,
+ 'has-success': this.props.bsStyle === 'success',
+ 'has-warning': this.props.bsStyle === 'warning',
+ 'has-error': this.props.bsStyle === 'error'
+ };
+
+ return (
+
+ {this.props.children}
+
+ );
+ }
+}
+
+FormGroup.defaultProps = {
+ standalone: false
+};
+
+FormGroup.propTypes = {
+ standalone: React.PropTypes.bool,
+ hasFeedback: React.PropTypes.bool,
+ bsStyle: React.PropTypes.oneOf(['success', 'warning', 'error']),
+ groupClassName: React.PropTypes.string
+};
+
+export default FormGroup;
diff --git a/src/Input.js b/src/Input.js
index 412630a3d2..24d7b2e168 100644
--- a/src/Input.js
+++ b/src/Input.js
@@ -1,6 +1,7 @@
import React from 'react';
import classSet from 'classnames';
import Button from './Button';
+import FormGroup from './FormGroup';
const Input = React.createClass({
@@ -215,38 +216,21 @@ const Input = React.createClass({
) : children;
},
- renderFormGroup(children) {
- let classes = {
- 'form-group': true,
- 'has-feedback': this.props.hasFeedback,
- 'has-success': this.props.bsStyle === 'success',
- 'has-warning': this.props.bsStyle === 'warning',
- 'has-error': this.props.bsStyle === 'error'
- };
- classes[this.props.groupClassName] = this.props.groupClassName;
-
- return (
-
- {children}
-
- );
- },
-
render() {
+ let children;
+
if (this.isCheckboxOrRadio()) {
- return this.renderFormGroup(
- this.renderWrapper([
- this.renderCheckboxandRadioWrapper(
- this.renderLabel(
- this.renderInput()
- )
- ),
- this.renderHelp()
- ])
- );
+ children = this.renderWrapper([
+ this.renderCheckboxandRadioWrapper(
+ this.renderLabel(
+ this.renderInput()
+ )
+ ),
+ this.renderHelp()
+ ]);
}
else {
- return this.renderFormGroup([
+ children = [
this.renderLabel(),
this.renderWrapper([
this.renderInputGroup(
@@ -255,8 +239,10 @@ const Input = React.createClass({
this.renderIcon(),
this.renderHelp()
])
- ]);
+ ];
}
+
+ return {children} ;
}
});
diff --git a/test/FormGroupSpec.js b/test/FormGroupSpec.js
new file mode 100644
index 0000000000..c174fd5a29
--- /dev/null
+++ b/test/FormGroupSpec.js
@@ -0,0 +1,86 @@
+import React from 'react';
+import ReactTestUtils from 'react/lib/ReactTestUtils';
+import FormGroup from '../src/FormGroup';
+
+describe('FormGroup', function() {
+ beforeEach(function() {
+ sinon.spy(console, 'warn');
+ });
+
+ afterEach(function() {
+ if (typeof console.warn.restore === 'function') {
+ console.warn.called.should.be.false;
+ console.warn.restore();
+ }
+ });
+
+ it('renders children', function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+
+
+
+ );
+
+ assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'child1'));
+ assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'child2'));
+ });
+
+ it('renders with form-group class', function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+
+
+ );
+
+ assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'form-group'));
+ });
+
+ it('renders no form-group class when standalone', function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+
+
+ );
+
+ assert.equal(ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'form-group').length, 0);
+ });
+
+ [{
+ className: 'has-feedback',
+ props: { hasFeedback: true }
+ }, {
+ className: 'has-success',
+ props: { bsStyle: 'success' }
+ }, {
+ className: 'has-warning',
+ props: { bsStyle: 'warning' }
+ }, {
+ className: 'has-error',
+ props: { bsStyle: 'error' }
+ }, {
+ className: 'custom-group',
+ props: { groupClassName: 'custom-group' }
+ }
+ ].forEach(function(testCase) {
+ it(`does not render ${testCase.className} class`, function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+
+
+ );
+
+ assert.equal(ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, testCase.className).length, 0);
+ });
+
+ it(`renders with ${testCase.className} class`, function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+
+
+ );
+
+ assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, testCase.className));
+ });
+ });
+});
diff --git a/test/InputSpec.js b/test/InputSpec.js
index 9b45b247ec..3c3c973f87 100644
--- a/test/InputSpec.js
+++ b/test/InputSpec.js
@@ -167,6 +167,30 @@ describe('Input', function () {
assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'help-block'));
});
+ it('renders form-group class', function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+ );
+
+ assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'form-group'));
+ });
+
+ it('renders no form-group class', function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+ );
+
+ assert.equal(ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'form-group').length, 0);
+ });
+
+ it('renders custom-form-group class', function() {
+ let instance = ReactTestUtils.renderIntoDocument(
+
+ );
+
+ assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'custom-form-class'));
+ });
+
it('renders feedback icon', function () {
let instance = ReactTestUtils.renderIntoDocument(