Added Input errors support. Merged LabeledInput into Input

This commit is contained in:
SleepWalker 2016-05-02 08:51:47 +03:00
parent 256d2322c6
commit d19e7e5c4f
5 changed files with 67 additions and 76 deletions

View File

@ -4,7 +4,7 @@ import { FormattedMessage as Message } from 'react-intl';
import { Link } from 'react-router'; import { Link } from 'react-router';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import { LabeledInput, Button, Checkbox } from 'components/ui/Form'; import { Input, Button, Checkbox } from 'components/ui/Form';
import FormModel from 'models/Form'; import FormModel from 'models/Form';
import { Form } from 'components/ui/Form'; import { Form } from 'components/ui/Form';
@ -50,7 +50,7 @@ export default class ChangePassword extends Component {
</div> </div>
<div className={styles.formRow}> <div className={styles.formRow}>
<LabeledInput {...form.bindField('newPassword')} <Input {...form.bindField('newPassword')}
type="password" type="password"
required required
skin="light" skin="light"
@ -65,7 +65,7 @@ export default class ChangePassword extends Component {
</div> </div>
<div className={styles.formRow}> <div className={styles.formRow}>
<LabeledInput {...form.bindField('newRePassword')} <Input {...form.bindField('newRePassword')}
type="password" type="password"
required required
skin="light" skin="light"

View File

@ -3,6 +3,8 @@ import React, { Component, PropTypes } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { intlShape } from 'react-intl'; import { intlShape } from 'react-intl';
import { uniqueId } from 'functions';
import icons from './icons.scss'; import icons from './icons.scss';
import styles from './form.scss'; import styles from './form.scss';
import buttons from './buttons.scss'; import buttons from './buttons.scss';
@ -17,6 +19,13 @@ export class Input extends Component {
}), }),
PropTypes.string PropTypes.string
]), ]),
label: PropTypes.oneOfType([
PropTypes.shape({
id: PropTypes.string
}),
PropTypes.string
]).isRequired,
error: PropTypes.string,
icon: PropTypes.string, icon: PropTypes.string,
skin: PropTypes.oneOf(['dark', 'light']), skin: PropTypes.oneOf(['dark', 'light']),
color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue']) color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue'])
@ -27,13 +36,29 @@ export class Input extends Component {
}; };
render() { render() {
let { icon, color = 'green', skin = 'dark' } = this.props; let { icon, color = 'green', skin = 'dark', error, label } = this.props;
const props = { const props = {
type: 'text', type: 'text',
...this.props ...this.props
}; };
if (label) {
if (!props.id) {
props.id = uniqueId('input');
}
if (label.id) {
label = this.context.intl.formatMessage(label);
}
label = (
<label className={styles.textFieldLabel} htmlFor={props.id}>
{label}
</label>
);
}
if (props.placeholder && props.placeholder.id) { if (props.placeholder && props.placeholder.id) {
props.placeholder = this.context.intl.formatMessage(props.placeholder); props.placeholder = this.context.intl.formatMessage(props.placeholder);
} }
@ -46,13 +71,25 @@ export class Input extends Component {
); );
} }
if (error) {
error = (
<div className={styles.fieldError}>
error
</div>
);
}
return ( return (
<div className={baseClass}> <div className={baseClass}>
<input ref={this.setEl} className={classNames( {label}
styles[`${skin}TextField`], <div className={styles.textFieldContainer}>
styles[`${color}TextField`] <input ref={this.setEl} className={classNames(
)} {...props} /> styles[`${skin}TextField`],
{icon} styles[`${color}TextField`]
)} {...props} />
{icon}
</div>
{error}
</div> </div>
); );
} }
@ -71,62 +108,6 @@ export class Input extends Component {
} }
} }
export class LabeledInput extends Component {
static displayName = 'LabeledInput';
static propTypes = {
label: PropTypes.oneOfType([
PropTypes.shape({
id: PropTypes.string
}),
PropTypes.string
]).isRequired,
id: PropTypes.string,
icon: PropTypes.string,
skin: PropTypes.oneOf(['dark', 'light']),
color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue'])
};
static contextTypes = {
intl: intlShape.isRequired
};
render() {
let { label } = this.props;
let props = Object.assign({}, this.props);
if (!props.id) {
props.id = uniqueId('input');
}
if (label && label.id) {
label = this.context.intl.formatMessage(label);
}
return (
<div className={styles.formLabeledRow}>
<label className={styles.textFieldLabel} htmlFor={props.id}>
{label}
</label>
<Input ref={this.setEl} {...props} />
</div>
);
}
setEl = (el) => {
this.el = el;
};
getValue() {
return this.el.getValue();
}
focus() {
this.el.focus();
}
}
export class Checkbox extends Component { export class Checkbox extends Component {
static displayName = 'Checkbox'; static displayName = 'Checkbox';
@ -297,9 +278,3 @@ export class Form extends Component {
} }
}; };
} }
let lastId = 0;
function uniqueId(prefix = 'id') {
return `${prefix}${++lastId}`;
}

View File

@ -30,9 +30,6 @@
} }
.formRow { .formRow {
position: relative;
height: 50px;
max-width: 100%;
margin: 10px 0; margin: 10px 0;
} }
@ -44,6 +41,12 @@
} }
} }
.textFieldContainer {
position: relative;
height: 50px;
max-width: 100%;
}
.textField { .textField {
box-sizing: border-box; box-sizing: border-box;
position: absolute; position: absolute;
@ -120,11 +123,20 @@
} }
.textFieldLabel { .textFieldLabel {
margin: 10px 0;
display: block;
font-family: $font-family-title; font-family: $font-family-title;
color: #666; color: #666;
font-size: 18px; font-size: 18px;
} }
.fieldError {
color: $red;
font-size: 12px;
margin: 3px 0;
}
@include input-theme('green', $green); @include input-theme('green', $green);
@include input-theme('blue', $blue); @include input-theme('blue', $blue);
@include input-theme('red', $red); @include input-theme('red', $red);

4
src/functions.js Normal file
View File

@ -0,0 +1,4 @@
let lastId = 0;
export function uniqueId(prefix = 'id') {
return `${prefix}${++lastId}`;
}

View File

@ -5,10 +5,10 @@ import { shallow } from 'enzyme';
import ChangePassword from 'components/profile/changePassword/ChangePassword'; import ChangePassword from 'components/profile/changePassword/ChangePassword';
describe('<ChangePassword />', () => { describe('<ChangePassword />', () => {
it('renders two <LabeledInput /> components', () => { it('renders two <Input /> components', () => {
const component = shallow(<ChangePassword onSubmit={() => {}} />); const component = shallow(<ChangePassword onSubmit={() => {}} />);
expect(component.find('LabeledInput')).to.have.length(2); expect(component.find('Input')).to.have.length(2);
}); });