Skip to content

Commit 8b2386f

Browse files
committed
feat(validation): add/update form validation
Added/updated test Added/updated docs deprecation: the state prop on input has now become the valid prop which accepts a boolean breaking change: The color prop has been removed from FromGroup, see the valid prop on Input.
1 parent 9b80d11 commit 8b2386f

10 files changed

Lines changed: 73 additions & 32 deletions

File tree

docs/lib/Components/FormPage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default class FormPage extends React.Component {
6262
</PrismCode>
6363
</pre>
6464

65-
<h3>Form Feedback</h3>
65+
<h3>Form Validation</h3>
6666
<div className="docs-example">
6767
<FormFeedbackExample />
6868
</div>

docs/lib/examples/FormFeedback.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,23 @@ export default class Example extends React.Component {
55
render() {
66
return (
77
<Form>
8-
<FormGroup color="success">
8+
<FormGroup>
99
<Label for="exampleEmail">Input with success</Label>
10-
<Input state="success" />
11-
<FormFeedback>Success! You did it!</FormFeedback>
12-
<FormText color="muted">Example help text that remains unchanged.</FormText>
10+
<Input valid />
11+
<FormFeedback>
12+
<a href="https://github.com/twbs/bootstrap/issues/23372">A bug</a> fixed in (the currently
13+
unreleased) (
14+
<a href="https://github.com/twbs/bootstrap/pull/23377">PR</a>
15+
) bootstrap <a href="https://github.com/twbs/bootstrap/issues/23278">v4 beta-2</a> shows invalid-feedback
16+
with is-valid inputs.
17+
</FormFeedback>
18+
<FormText>Example help text that remains unchanged.</FormText>
1319
</FormGroup>
14-
<FormGroup color="warning">
15-
<Label for="examplePassword">Input with warning</Label>
16-
<Input state="warning" />
17-
<FormFeedback>Whoops, check your formatting and try again.</FormFeedback>
18-
<FormText color="muted">Example help text that remains unchanged.</FormText>
19-
</FormGroup>
20-
<FormGroup color="danger">
20+
<FormGroup>
2121
<Label for="examplePassword">Input with danger</Label>
22-
<Input state="danger" />
22+
<Input valid={false} />
2323
<FormFeedback>Oh noes! that name is already taken</FormFeedback>
24-
<FormText color="muted">Example help text that remains unchanged.</FormText>
24+
<FormText>Example help text that remains unchanged.</FormText>
2525
</FormGroup>
2626
</Form>
2727
);

src/FormFeedback.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const FormFeedback = (props) => {
2424

2525
const classes = mapToCssModules(classNames(
2626
className,
27-
'form-control-feedback'
27+
'invalid-feedback'
2828
), cssModule);
2929

3030
return (

src/FormGroup.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const propTypes = {
99
check: PropTypes.bool,
1010
disabled: PropTypes.bool,
1111
tag: PropTypes.string,
12-
color: PropTypes.string,
1312
className: PropTypes.string,
1413
cssModule: PropTypes.object,
1514
};
@@ -24,15 +23,13 @@ const FormGroup = (props) => {
2423
cssModule,
2524
row,
2625
disabled,
27-
color,
2826
check,
2927
tag: Tag,
3028
...attributes
3129
} = props;
3230

3331
const classes = mapToCssModules(classNames(
3432
className,
35-
color ? `has-${color}` : false,
3633
row ? 'row' : false,
3734
check ? 'form-check' : 'form-group',
3835
check && disabled ? 'disabled' : false

src/FormText.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const propTypes = {
1414

1515
const defaultProps = {
1616
tag: 'small',
17+
color: 'muted',
1718
};
1819

1920
const FormText = (props) => {

src/Input.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import React from 'react';
44
import PropTypes from 'prop-types';
55
import classNames from 'classnames';
6-
import { mapToCssModules } from './utils';
6+
import { mapToCssModules, deprecated } from './utils';
77

88
const propTypes = {
99
children: PropTypes.node,
1010
type: PropTypes.string,
1111
size: PropTypes.string,
12-
state: PropTypes.string,
12+
state: deprecated(PropTypes.string, 'Please use the prop "valid"'),
13+
valid: PropTypes.bool,
1314
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
1415
innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
1516
static: PropTypes.bool,
@@ -25,12 +26,13 @@ const defaultProps = {
2526

2627
class Input extends React.Component {
2728
render() {
28-
const {
29+
let {
2930
className,
3031
cssModule,
3132
type,
3233
size,
3334
state,
35+
valid,
3436
tag,
3537
addon,
3638
static: staticInput,
@@ -60,9 +62,18 @@ class Input extends React.Component {
6062
}
6163
}
6264

65+
if (state && typeof valid === 'undefined') {
66+
if (state === 'danger') {
67+
valid = false;
68+
} else if (state === 'success') {
69+
valid = true;
70+
}
71+
}
72+
6373
const classes = mapToCssModules(classNames(
6474
className,
65-
state ? `form-control-${state}` : false,
75+
valid === false && 'is-invalid',
76+
valid && 'is-valid',
6677
size ? `form-control-${size}` : false,
6778
formControlClass
6879
), cssModule);

src/__tests__/FormFeedback.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ describe('FormFeedback', () => {
1515
expect(wrapper.text()).toBe('Yo!');
1616
});
1717

18-
it('should render with "form-control-feedback" class', () => {
18+
it('should render with "invalid-feedback" class', () => {
1919
const wrapper = shallow(<FormFeedback>Yo!</FormFeedback>);
2020

21-
expect(wrapper.hasClass('form-control-feedback')).toBe(true);
21+
expect(wrapper.hasClass('invalid-feedback')).toBe(true);
2222
});
2323

2424
it('should render additional classes', () => {

src/__tests__/FormGroup.spec.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,6 @@ describe('FormGroup', () => {
6464
expect(wrapper.hasClass('row')).toBe(false);
6565
});
6666

67-
it('should render with "has-${color}" class when color prop is provided', () => {
68-
const wrapper = shallow(<FormGroup color="yoyo">Yo!</FormGroup>);
69-
70-
expect(wrapper.hasClass('has-yoyo')).toBe(true);
71-
});
72-
7367
it('should render additional classes', () => {
7468
const wrapper = shallow(<FormGroup className="other">Yo!</FormGroup>);
7569

src/__tests__/FormText.spec.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ describe('FormText', () => {
2727
expect(wrapper.hasClass('form-text')).toBe(false);
2828
});
2929

30+
it('should render with "text-muted" class by default', () => {
31+
const wrapper = shallow(<FormText>Yo!</FormText>);
32+
33+
expect(wrapper.hasClass('text-muted')).toBe(true);
34+
});
35+
36+
it('should render without "text-*" class when color is and empty string', () => {
37+
const wrapper = shallow(<FormText color="">Yo!</FormText>);
38+
39+
expect(wrapper.hasClass('text-muted')).toBe(false);
40+
expect(wrapper.hasClass('text-')).toBe(false);
41+
});
42+
3043
it('should render with "text-${color}" class when color is provided', () => {
3144
const wrapper = shallow(<FormText color="yoyo">Yo!</FormText>);
3245

src/__tests__/Input.spec.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,35 @@ describe('Input', () => {
6363
expect(wrapper.text()).toBe('Yo!');
6464
});
6565

66-
it('should render with "form-control-${state}" class when state is provided', () => {
66+
it('should render with "is-invalid" class when state is "danger" [DEPRECATED]', () => {
6767
const wrapper = shallow(<Input state="danger" />);
6868

69-
expect(wrapper.hasClass('form-control-danger')).toBe(true);
69+
expect(wrapper.hasClass('is-invalid')).toBe(true);
70+
});
71+
72+
it('should render with "is-valid" class when state is "success" [DEPRECATED]', () => {
73+
const wrapper = shallow(<Input state="success" />);
74+
75+
expect(wrapper.hasClass('is-valid')).toBe(true);
76+
});
77+
78+
it('should not render with "is-valid" nor "is-invalid" class when state is "warning" [DEPRECATED]', () => {
79+
const wrapper = shallow(<Input state="warning" />);
80+
81+
expect(wrapper.hasClass('is-valid')).toBe(false);
82+
expect(wrapper.hasClass('is-invalid')).toBe(false);
83+
});
84+
85+
it('should render with "is-invalid" class when valid is false', () => {
86+
const wrapper = shallow(<Input valid={false} />);
87+
88+
expect(wrapper.hasClass('is-invalid')).toBe(true);
89+
});
90+
91+
it('should render with "is-valid" class when valid is true', () => {
92+
const wrapper = shallow(<Input valid />);
93+
94+
expect(wrapper.hasClass('is-valid')).toBe(true);
7095
});
7196

7297
it('should render with "form-control-${size}" class when size is provided', () => {

0 commit comments

Comments
 (0)