diff --git a/demo/Page/Page.controller.js b/demo/Page/Page.controller.js
index 3d6c368f73..965b6bdec6 100644
--- a/demo/Page/Page.controller.js
+++ b/demo/Page/Page.controller.js
@@ -1,7 +1,5 @@
-import config from './Page.config';
import Page from './Page.model';
import httpStatus from 'http-status';
-import toKebabCase from '../../src/lib/helpers/toKebabCase';
const pageController = {
query(req, res) {
diff --git a/package-lock.json b/package-lock.json
index 3dd8e797fc..ba01c30c6a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1822,6 +1822,32 @@
}
}
},
+ "babel-eslint": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz",
+ "integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.0.0",
+ "@babel/traverse": "^7.0.0",
+ "@babel/types": "^7.0.0",
+ "eslint-scope": "3.7.1",
+ "eslint-visitor-keys": "^1.0.0"
+ },
+ "dependencies": {
+ "eslint-scope": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ }
+ }
+ },
"babel-generator": {
"version": "6.26.1",
"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
diff --git a/package.json b/package.json
index a3c721e6a7..3477a00c86 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,7 @@
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.0.0",
"autoprefixer": "^9.0.1",
+ "babel-eslint": "^10.0.1",
"babel-loader": "^8.0.4",
"circular-dependency-plugin": "^5.0.2",
"css-loader": "^1.0.0",
diff --git a/src/components.js b/src/components.js
index 08b691a994..df42c04a9a 100644
--- a/src/components.js
+++ b/src/components.js
@@ -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';
diff --git a/src/components/field-types/Input/index.js b/src/components/field-types/Input/index.js
index 005df1aa1f..4ecd9f22ea 100644
--- a/src/components/field-types/Input/index.js
+++ b/src/components/field-types/Input/index.js
@@ -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
- ? () => *
- : () => null;
-
- const Error = showError
- ? () => {this.errors[this.props.type]}
- : () => null;
-
- const Label = this.props.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 (
-
-
-
- {
- 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} />
-
- );
+ default:
+ return false;
}
}
-const ContextInput = props => {
+const Input = props => {
return (
-
- {context => }
-
+
+ {props.error}
+ {props.label}
+
+
);
-};
+}
-export default ContextInput;
+export default fieldType(Input, 'input', validate, errors);
diff --git a/src/components/field-types/Input/index.scss b/src/components/field-types/Input/index.scss
index 6dbca9ac7d..7da51e7358 100644
--- a/src/components/field-types/Input/index.scss
+++ b/src/components/field-types/Input/index.scss
@@ -1,8 +1,6 @@
@import '~payload/scss/styles';
-.interact.text,
-.interact.email,
-.interact.password {
+.field-type.input {
margin-bottom: rem(.5);
position: relative;
diff --git a/src/components/field-types/Textarea/index.js b/src/components/field-types/Textarea/index.js
index 464b1f17bf..6e242a07f7 100644
--- a/src/components/field-types/Textarea/index.js
+++ b/src/components/field-types/Textarea/index.js
@@ -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
- ? () => *
- : () => null;
-
- let Error = showError
- ? () => {this.errors.text}
- : () => null;
-
- const Label = this.props.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 (
-
-
-
-
-
- );
- }
-}
-
-const ContextTextarea = props => {
- return (
-
- {context => }
-
- );
+const errors = {
+ text: 'Please fill in the field'
};
-export default ContextTextarea;
+const validate = value => value.length > 0;
+
+const Textarea = props => {
+ return (
+
+ {props.error}
+ {props.label}
+
+
+ );
+}
+
+export default fieldType(Textarea, 'textarea', validate, errors);
diff --git a/src/components/field-types/Textarea/index.scss b/src/components/field-types/Textarea/index.scss
index 89a969ed81..460a4f51d6 100644
--- a/src/components/field-types/Textarea/index.scss
+++ b/src/components/field-types/Textarea/index.scss
@@ -1,6 +1,6 @@
@import '~payload/scss/styles';
-.interact.textarea {
+.field-type.textarea {
margin-bottom: rem(.5);
position: relative;
diff --git a/src/components/field-types/fieldType/index.js b/src/components/field-types/fieldType/index.js
new file mode 100644
index 0000000000..78e7159e8f
--- /dev/null
+++ b/src/components/field-types/fieldType/index.js
@@ -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 (
+ {
+ this.sendField(e.target.value);
+ this.props.onChange && this.props.onChange(e);
+ }}
+ Label={}
+ Error={}
+ />
+ )
+ }
+ }
+
+ const Label = props => {
+ if (props.label) {
+ return (
+
+ )
+ }
+
+ return null;
+ }
+
+ const Error = props => {
+ if (props.showError) {
+ return (
+
+ {errors[this.props.type]}
+
+ )
+ }
+
+ return null;
+ }
+
+ const FieldTypeWithContext = props => {
+ return (
+
+ {context => }
+
+ );
+ };
+
+ return FieldTypeWithContext;
+}
+
+export default fieldType;