introduces HOC for fieldType, greatly simplifying field type components

This commit is contained in:
James
2018-12-07 12:20:10 -08:00
parent b2313e7783
commit ae5170aca3
9 changed files with 210 additions and 262 deletions

View File

@@ -8,6 +8,7 @@ export { default as withArchiveData } from './components/data/archive';
export { default as withEditData } from './components/data/edit';
// Field Types
export { default as fieldType } from './components/field-types/fieldType';
export { default as Group } from './components/field-types/Group';
export { default as Input } from './components/field-types/Input';
export { default as Textarea } from './components/field-types/Textarea';

View File

@@ -1,140 +1,50 @@
import React, { Component } from 'react';
import { Tooltip, FormContext } from 'payload/components';
import React from 'react';
import { fieldType } from 'payload/components';
import './index.scss';
class Input extends Component {
constructor() {
super();
const errors = {
text: 'Please fill in the field',
email: 'Please enter a valid email',
password: 'Please enter a password'
};
this.errors = {
text: 'Please fill in the field',
email: 'Please enter a valid email',
password: 'Please enter a password'
};
const validate = (value, type) => {
let emailTest = /\S+@\S+\.\S+/;
this.state = {
init: false
};
switch (type) {
case 'text':
return value.length > 0;
this.validate = this.validate.bind(this);
this.sendField = this.sendField.bind(this);
}
case 'password':
return value.length > 0;
validate(value) {
let emailTest = /\S+@\S+\.\S+/;
case 'email':
return emailTest.test(value);
switch (this.props.type) {
case 'text':
return value.length > 0;
case 'hidden':
return true;
case 'password':
return value.length > 0;
case 'email':
return emailTest.test(value);
case 'hidden':
return true;
default:
return false;
}
}
sendField(value) {
this.props.context.setValue({
name: this.props.name,
value: value,
valid: this.props.required
? this.validate(value)
: true
})
}
componentDidMount() {
this.sendField(
this.props.value ? this.props.value : ''
);
this.setState({
init: true
});
}
componentDidUpdate(prevProps) {
if (prevProps.valueOverride !== this.props.valueOverride) {
this.sendField(this.props.valueOverride);
}
if (prevProps.initialValue !== this.props.initialValue) {
this.sendField(this.props.initialValue);
}
}
render() {
const valid = this.props.context.fields[this.props.name]
? this.props.context.fields[this.props.name].valid
: true;
const showError = valid === false && this.props.context.submitted;
const Required = this.props.required
? () => <span className="required">*</span>
: () => null;
const Error = showError
? () => <Tooltip className="error-message">{this.errors[this.props.type]}</Tooltip>
: () => null;
const Label = this.props.label
? () => <label htmlFor={this.props.id ? this.props.id : this.props.name}>{this.props.label}<Required /></label>
: () => null;
let className = `interact ${this.props.type}`;
className = !showError ? className : `${className} error`;
const initialValue = this.props.initialValue
? this.props.initialValue
: '';
const contextValue = (this.props.context.fields[this.props.name] && this.props.context.fields[this.props.name].value)
? this.props.context.fields[this.props.name].value
: initialValue;
const value = this.props.valueOverride
? this.props.valueOverride
: contextValue;
return (
<div className={className} style={this.props.style}>
<Error />
<Label />
<input
value={value}
onChange={
e => {
this.sendField(e.target.value);
this.props.onChange && this.props.onChange(e);
}
}
disabled={this.props.disabled}
placeholder={this.props.placeholder}
type={this.props.type}
id={this.props.id ? this.props.id : this.props.name}
name={this.props.name} />
</div>
);
default:
return false;
}
}
const ContextInput = props => {
const Input = props => {
return (
<FormContext.Consumer>
{context => <Input {...props} context={context} />}
</FormContext.Consumer>
<div className={props.className} style={props.style}>
{props.error}
{props.label}
<input
value={props.value}
onChange={props.onChange}
disabled={props.disabled}
placeholder={props.placeholder}
type={props.type}
id={props.id ? props.id : props.name}
name={props.name} />
</div>
);
};
}
export default ContextInput;
export default fieldType(Input, 'input', validate, errors);

View File

@@ -1,8 +1,6 @@
@import '~payload/scss/styles';
.interact.text,
.interact.email,
.interact.password {
.field-type.input {
margin-bottom: rem(.5);
position: relative;

View File

@@ -1,136 +1,30 @@
import React, { Component } from 'react';
import { FormContext, Tooltip } from 'payload/components';
import React from 'react';
import { fieldType } from 'payload/components';
import './index.scss';
class Textarea extends Component {
constructor() {
super();
this.errors = {
text: 'Please fill in the field'
};
this.state = {
init: false
};
this.validate = this.validate.bind(this);
this.sendField = this.sendField.bind(this);
}
validate(value) {
switch (this.props.type) {
case 'honeypot':
return value.length === 0;
default:
return value.length > 0;
}
}
sendField(value) {
this.props.context.setValue({
name: this.props.name,
value: value,
valid: this.props.required
? this.validate(value)
: true
});
}
componentDidMount() {
this.sendField(
this.props.value ? this.props.value : ''
)
this.setState({
init: true
});
}
componentDidUpdate(prevProps) {
if (prevProps.valueOverride !== this.props.valueOverride) {
this.sendField(this.props.valueOverride);
}
if (prevProps.initialValue !== this.props.initialValue) {
this.sendField(this.props.initialValue);
}
}
render() {
const valid = this.props.context.fields[this.props.name]
? this.props.context.fields[this.props.name].valid
: true;
const showError = valid === false && this.props.context.submitted;
const Required = this.props.required
? () => <span className="required">*</span>
: () => null;
let Error = showError
? () => <Tooltip className="error-message">{this.errors.text}</Tooltip>
: () => null;
const Label = this.props.label
? () => <label htmlFor={this.props.id ? this.props.id : this.props.name}>{this.props.label}<Required /></label>
: () => null;
let className = 'interact textarea';
className = !showError ? className : `${className} error`;
let style = this.props.style
? this.props.style
: null;
if (this.props.type === 'honeypot') {
style = { position: 'fixed', left: '10000px', top: '-100px' };
Error = () => null;
className = 'interact';
}
const initialValue = this.props.initialValue
? this.props.initialValue
: '';
const contextValue = (this.props.context.fields[this.props.name] && this.props.context.fields[this.props.name].value)
? this.props.context.fields[this.props.name].value
: initialValue;
const value = this.props.valueOverride
? this.props.valueOverride
: contextValue;
return (
<div className={className} style={style}>
<Error />
<Label />
<textarea
value={ value }
onChange={
e => {
this.sendField(e.target.value);
this.props.onChange && this.props.onChange(e);
}
}
disabled={this.props.disabled}
placeholder={this.props.placeholder}
type={this.props.type}
id={this.props.id ? this.props.id : this.props.name}
name={this.props.name}>
</textarea>
</div>
);
}
}
const ContextTextarea = props => {
return (
<FormContext.Consumer>
{context => <Textarea {...props} context={context} />}
</FormContext.Consumer>
);
const errors = {
text: 'Please fill in the field'
};
export default ContextTextarea;
const validate = value => value.length > 0;
const Textarea = props => {
return (
<div className={props.className} style={props.style}>
{props.error}
{props.label}
<textarea
value={ props.value }
onChange={props.onChange}
disabled={props.disabled}
placeholder={props.placeholder}
type={props.type}
id={props.id ? props.id : props.name}
name={props.name}>
</textarea>
</div>
);
}
export default fieldType(Textarea, 'textarea', validate, errors);

View File

@@ -1,6 +1,6 @@
@import '~payload/scss/styles';
.interact.textarea {
.field-type.textarea {
margin-bottom: rem(.5);
position: relative;

View File

@@ -0,0 +1,120 @@
import React, { Component } from 'react';
import { FormContext, Tooltip } from 'payload/components';
const fieldType = (PassedComponent, slug, validate, errors) => {
class FieldType extends Component {
constructor(props) {
super(props);
this.state = {
init: false
};
}
sendField(value) {
this.props.context.setValue({
name: this.props.name,
value: value,
valid: this.props.required
? validate(value, this.props.type)
: true
});
}
componentDidMount() {
this.sendField(
this.props.value ? this.props.value : ''
)
this.setState({
init: true
});
}
componentDidUpdate(prevProps) {
if (prevProps.valueOverride !== this.props.valueOverride) {
this.sendField(this.props.valueOverride);
}
if (prevProps.initialValue !== this.props.initialValue) {
this.sendField(this.props.initialValue);
}
}
render() {
const valid = this.props.context.fields[this.props.name]
? this.props.context.fields[this.props.name].valid
: true;
const showError = valid === false && this.props.context.submitted;
let className = `field-type ${slug}${showError ? ' error' : ''}`;
const initialValue = this.props.initialValue
? this.props.initialValue
: '';
const contextValue = (this.props.context.fields[this.props.name] && this.props.context.fields[this.props.name].value)
? this.props.context.fields[this.props.name].value
: initialValue;
const value = this.props.valueOverride
? this.props.valueOverride
: contextValue;
return (
<PassedComponent {...this.props}
className={className}
value={value}
onChange={e => {
this.sendField(e.target.value);
this.props.onChange && this.props.onChange(e);
}}
Label={<Label {...this.props} />}
Error={<Error showError={showError} />}
/>
)
}
}
const Label = props => {
if (props.label) {
return (
<label htmlFor={props.id ? props.id : props.name}>
{props.label}
{props.required &&
<span className="required">*</span>
}
</label>
)
}
return null;
}
const Error = props => {
if (props.showError) {
return (
<Tooltip className="error-message">
{errors[this.props.type]}
</Tooltip>
)
}
return null;
}
const FieldTypeWithContext = props => {
return (
<FormContext.Consumer>
{context => <FieldType {...props} context={context} />}
</FormContext.Consumer>
);
};
return FieldTypeWithContext;
}
export default fieldType;