introduces HOC for fieldType, greatly simplifying field type components
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
@import '~payload/scss/styles';
|
||||
|
||||
.interact.text,
|
||||
.interact.email,
|
||||
.interact.password {
|
||||
.field-type.input {
|
||||
margin-bottom: rem(.5);
|
||||
position: relative;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@import '~payload/scss/styles';
|
||||
|
||||
.interact.textarea {
|
||||
.field-type.textarea {
|
||||
margin-bottom: rem(.5);
|
||||
position: relative;
|
||||
|
||||
|
||||
120
src/components/field-types/fieldType/index.js
Normal file
120
src/components/field-types/fieldType/index.js
Normal 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;
|
||||
Reference in New Issue
Block a user