Skip to content

Commit

Permalink
Merge pull request #156 from appfolio/formRowStyle
Browse files Browse the repository at this point in the history
Form row style
  • Loading branch information
aaronpanch authored Mar 7, 2017
2 parents 0a9f033 + 002e00b commit 48d360e
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 19 deletions.
45 changes: 30 additions & 15 deletions src/components/FormRow.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { FormGroup, Input, Label, Col, FormFeedback, FormText } from 'reactstrap';
import { FormGroup, Input, Label, Col, Row, FormFeedback, FormText } from 'reactstrap';

import CheckboxInput from './CheckboxInput';
import RadioInput from './RadioInput';
Expand Down Expand Up @@ -38,6 +38,8 @@ const FormRow = props => {
type,
children,
inline,
stacked,
width,
...attributes
} = props;

Expand All @@ -46,22 +48,31 @@ const FormRow = props => {
const [baseFeedback, childFeedback] = parseFeedback(feedback);
const rowColor = color || state || (baseFeedback && 'danger');

const labelWidth = stacked ? 12 : 3;
const labelAlignment = stacked ? '' : 'text-sm-right';

const inputContainerWidth = stacked ? 12 : 9;

return (
<FormGroup row color={rowColor}>
<Label for={id} sm={3} size={size}>
<Label for={id} sm={labelWidth} size={size} className={labelAlignment}>
{label}
{required && label ? <span className="text-danger"> *</span> : null}
{required && label ? <span className="text-danger">&nbsp;*</span> : null}
</Label>
<Col sm={9}>
<InputElement
id={id}
size={size}
state={rowColor}
type={type}
children={React.Children.map(children, child => React.cloneElement(child, { type }))}
{...attributes}
{...childFeedback}
/>
<Col sm={inputContainerWidth}>
<Row>
<Col {...width} >
<InputElement
id={id}
size={size}
state={rowColor}
type={type}
children={React.Children.map(children, child => React.cloneElement(child, { type }))}
{...attributes}
{...childFeedback}
/>
</Col>
</Row>
{hint ? <FormText color="muted" children={hint} /> : null}
{baseFeedback ? <FormFeedback children={baseFeedback} /> : null}
</Col>
Expand All @@ -82,7 +93,9 @@ FormRow.propTypes = {
React.PropTypes.element,
React.PropTypes.func
]),
inline: React.PropTypes.bool
inline: React.PropTypes.bool,
stacked: React.PropTypes.bool,
width: React.PropTypes.object
};

FormRow.defaultProps = {
Expand All @@ -91,7 +104,9 @@ FormRow.defaultProps = {
feedback: '',
required: false,
type: 'text',
inline: false
inline: false,
stacked: false,
width: { xs: 12 }
};

export default FormRow;
14 changes: 14 additions & 0 deletions stories/Forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const formData = {
}
};

const colKnobOptions = {
range: true,
min: 0,
max: 12
};

storiesOf('Forms', module)
.addWithInfo('Live example', () => (
<div>
Expand All @@ -23,6 +29,14 @@ storiesOf('Forms', module)
label={text('label', 'Select a Movie')}
color={select('color', ['', 'success', 'warning', 'danger'], 'danger')}
feedback={text('feedback', 'You must select a movie')}
stacked={boolean('stacked', false)}
width={{
xs: number('xs width', 12, colKnobOptions),
sm: number('sm width', 12, colKnobOptions),
md: number('md width', 12, colKnobOptions),
lg: number('lg width', 12, colKnobOptions),
xl: number('xl width', 12, colKnobOptions )
}}
name="live-input"
>
<FormChoice />
Expand Down
45 changes: 41 additions & 4 deletions test/components/FormRow.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ describe('<FormRow />', () => {
assert.equal(label.prop('for'), 'someID');
assert.equal(label.prop('size'), 'sm');
assert.equal(label.prop('sm'), 3);
assert.equal(label.prop('className'), 'text-sm-right');
assert.equal(label.render().text(), 'First Name');
});

it('should wrap the input in a column', () => {
const col = component.find(Col);
assert.equal(col.length, 1);
const col = component.find(Col).at(0);
assert.equal(col.prop('sm'), 9);
});

Expand Down Expand Up @@ -56,6 +56,11 @@ describe('<FormRow />', () => {
assert.equal(component.prop('color'), 'warning');
assert.equal(component.find(Input).prop('state'), 'warning');
});

it('should have an inner column width of 12', () => {
const col = component.find(Col).at(1); // inner column
assert.equal(col.prop('xs'), 12);
});
});

describe('when required', () => {
Expand All @@ -65,8 +70,10 @@ describe('<FormRow />', () => {

it('should show a star', () => {
const label = component.find(Label);
assert.equal(label.render().text(), 'First Name *');
assert.equal(label.find('span').hasClass('text-danger'), true);
const star = label.find('span');

assert.equal(star.hasClass('text-danger'), true);
assert.equal(star.text(), ' *');
});
});

Expand Down Expand Up @@ -168,4 +175,34 @@ describe('<FormRow />', () => {
assert.equal(component.find(Custom).length, 1);
});
});

describe('stacked', () => {
const component = shallow(
<FormRow label="First Name" stacked />
);

it('should have a full-width label', () => {
const label = component.find(Label);
assert.equal(label.prop('sm'), 12);
assert.equal(label.render().text(), 'First Name');
assert.equal(label.prop('className'), '');
});

it('should make input full-width', () => {
const col = component.find(Col).at(0);
assert.equal(col.prop('sm'), 12);
});
});

describe('with custom width', () => {
const component = shallow(
<FormRow label="First Name" width={{ xs: 6, sm: 7 }} />
);

it('should set the inner column width', () => {
const col = component.find(Col).at(1); // inner column
assert.equal(col.prop('xs'), 6);
assert.equal(col.prop('sm'), 7);
});
});
});

0 comments on commit 48d360e

Please sign in to comment.