lbry-desktop/ui/js/component/form.js

175 lines
5 KiB
JavaScript
Raw Normal View History

2016-11-22 21:19:08 +01:00
import React from 'react';
2017-01-18 04:36:48 +01:00
import {Icon} from './common.js';
2016-11-22 21:19:08 +01:00
2017-04-10 14:32:40 +02:00
var formFieldCounter = 0,
formFieldNestedLabelTypes = ['radio', 'checkbox'];
2016-11-22 21:19:08 +01:00
2017-04-10 14:32:40 +02:00
function formFieldId() {
return "form-field-" + (++formFieldCounter);
}
2017-04-09 17:06:23 +02:00
2017-05-17 10:10:25 +02:00
export class FormField extends React.Component {
static propTypes = {
type: React.PropTypes.string.isRequired,
2017-04-12 16:55:19 +02:00
prefix: React.PropTypes.string,
postfix: React.PropTypes.string,
2017-04-10 14:32:40 +02:00
hasError: React.PropTypes.bool
2017-05-17 10:10:25 +02:00
}
constructor(props) {
super(props);
this._fieldRequiredText = 'This field is required';
this._type = null;
this._element = null;
this.state = {
2017-04-10 14:32:40 +02:00
isError: null,
errorMessage: null,
2017-05-17 10:10:25 +02:00
};
}
componentWillMount() {
2017-04-10 14:32:40 +02:00
if (['text', 'number', 'radio', 'checkbox', 'file'].includes(this.props.type)) {
this._element = 'input';
this._type = this.props.type;
} else if (this.props.type == 'text-number') {
this._element = 'input';
this._type = 'text';
} else {
// Non <input> field, e.g. <select>, <textarea>
this._element = this.props.type;
}
2017-05-17 10:10:25 +02:00
}
showError(text) {
this.setState({
2017-04-10 14:32:40 +02:00
isError: true,
errorMessage: text,
});
2017-05-17 10:10:25 +02:00
}
focus() {
this.refs.field.focus();
2017-05-17 10:10:25 +02:00
}
getValue() {
if (this.props.type == 'checkbox') {
return this.refs.field.checked;
} else if (this.props.type == 'file') {
2017-04-12 18:59:43 +02:00
return this.refs.field.files.length && this.refs.field.files[0].path ?
this.refs.field.files[0].path : null;
} else {
return this.refs.field.value;
}
2017-05-17 10:10:25 +02:00
}
getSelectedElement() {
2016-09-20 12:38:46 +02:00
return this.refs.field.options[this.refs.field.selectedIndex];
2017-05-17 10:10:25 +02:00
}
render() {
// Pass all unhandled props to the field element
2017-04-09 17:06:23 +02:00
const otherProps = Object.assign({}, this.props),
2017-04-10 14:32:40 +02:00
isError = this.state.isError !== null ? this.state.isError : this.props.hasError,
elementId = this.props.id ? this.props.id : formFieldId(),
renderElementInsideLabel = this.props.label && formFieldNestedLabelTypes.includes(this.props.type);
delete otherProps.type;
2017-04-09 17:06:23 +02:00
delete otherProps.label;
2017-04-10 14:32:40 +02:00
delete otherProps.hasError;
2017-04-12 16:55:19 +02:00
delete otherProps.className;
delete otherProps.postfix;
delete otherProps.prefix;
2017-04-10 14:32:40 +02:00
const element = <this._element id={elementId} type={this._type} name={this.props.name} ref="field" placeholder={this.props.placeholder}
className={'form-field__input form-field__input-' + this.props.type + ' ' + (this.props.className || '') + (isError ? 'form-field__input--error' : '')}
{...otherProps}>
{this.props.children}
</this._element>;
2017-04-09 17:06:23 +02:00
2017-04-10 14:32:40 +02:00
return <div className="form-field">
2017-04-12 16:55:19 +02:00
{ this.props.prefix ? <span className="form-field__prefix">{this.props.prefix}</span> : '' }
2017-04-10 14:32:40 +02:00
{ renderElementInsideLabel ?
<label htmlFor={elementId} className={"form-field__label " + (isError ? 'form-field__label--error' : '')}>
{element}
{this.props.label}
2017-04-12 16:55:19 +02:00
</label> :
element }
{ this.props.postfix ? <span className="form-field__postfix">{this.props.postfix}</span> : '' }
{ isError && this.state.errorMessage ? <div className="form-field__error">{this.state.errorMessage}</div> : '' }
2017-04-09 17:06:23 +02:00
</div>
}
2017-05-17 10:10:25 +02:00
}
2016-11-22 21:19:08 +01:00
2017-05-17 10:10:25 +02:00
export class FormRow extends React.Component {
static propTypes = {
label: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element]),
2017-04-10 14:32:40 +02:00
// helper: React.PropTypes.html,
2017-05-17 10:10:25 +02:00
}
constructor(props) {
super(props);
this._fieldRequiredText = 'This field is required';
this.state = {
2017-04-10 14:32:40 +02:00
isError: false,
errorMessage: null,
2017-05-17 10:10:25 +02:00
};
}
showError(text) {
2017-04-10 14:32:40 +02:00
this.setState({
isError: true,
errorMessage: text,
});
2017-05-17 10:10:25 +02:00
}
showRequiredError() {
2017-04-12 16:55:19 +02:00
this.showError(this._fieldRequiredText);
2017-05-17 10:10:25 +02:00
}
clearError(text) {
2017-04-12 16:55:19 +02:00
this.setState({
isError: false,
errorMessage: ''
});
2017-05-17 10:10:25 +02:00
}
getValue() {
2017-04-10 14:32:40 +02:00
return this.refs.field.getValue();
2017-05-17 10:10:25 +02:00
}
getSelectedElement() {
2017-04-10 20:12:07 +02:00
return this.refs.field.getSelectedElement();
2017-05-17 10:10:25 +02:00
}
focus() {
2017-04-12 16:55:19 +02:00
this.refs.field.focus();
2017-05-17 10:10:25 +02:00
}
render() {
2017-04-10 14:32:40 +02:00
const fieldProps = Object.assign({}, this.props),
elementId = formFieldId(),
renderLabelInFormField = formFieldNestedLabelTypes.includes(this.props.type);
if (!renderLabelInFormField) {
delete fieldProps.label;
}
delete fieldProps.helper;
return <div className="form-row">
{ this.props.label && !renderLabelInFormField ?
<div className={"form-row__label-row " + (this.props.labelPrefix ? "form-row__label-row--prefix" : "") }>
<label htmlFor={elementId} className={"form-field__label " + (this.state.isError ? 'form-field__label--error' : '')}>
{this.props.label}
</label>
</div> : '' }
<FormField ref="field" hasError={this.state.isError} {...fieldProps} />
{ !this.state.isError && this.props.helper ? <div className="form-field__helper">{this.props.helper}</div> : '' }
{ this.state.isError ? <div className="form-field__error">{this.state.errorMessage}</div> : '' }
</div>
}
2017-05-17 10:10:25 +02:00
}