Skip to content

Commit 1a6bed4

Browse files
Merge pull request #2 from billwatson017/react-form
simplify react-form so that base components and wrapper
2 parents a2cf9fd + 6ed9cbf commit 1a6bed4

8 files changed

Lines changed: 148 additions & 61 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"@fortawesome/fontawesome-svg-core": "^1.2.25",
77
"@fortawesome/free-solid-svg-icons": "^5.11.2",
88
"@fortawesome/react-fontawesome": "^0.1.8",
9+
"prop-types": "^15.7.2",
910
"react": "^16.12.0",
1011
"react-dom": "^16.12.0",
1112
"react-fontawesome": "^1.7.1",

src/components/input-container/index.js

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
import React from 'react';
2+
import PropTypes from 'prop-types';
23
import { useField, splitFormProps } from "react-form";
34
import "../input-container/input-container.css";
45
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
56
import { faExclamation } from '@fortawesome/free-solid-svg-icons'
67

78
// input-container contains form layout, style and validation for app
8-
export const InputContainer = React.forwardRef((props, ref) => {
9-
const { Input, Icon, label, ...passThru } = props;
9+
export const InputContainer = (props) => {
10+
const {Input, required, Icon, ...passThru} = props
11+
12+
let validate = props.validate;
13+
if (required) {
14+
validate = value => {
15+
if (!value) {
16+
return "Required";
17+
}
18+
if (props.validate) {
19+
return props.validate(value);
20+
}
21+
return false;
22+
};
23+
}
1024

1125
// get form-specific props
12-
const [field, fieldOptions] = splitFormProps(props);
26+
const [field, fieldOptions, rest] = splitFormProps({...passThru, validate});
1327

1428
// get field state
1529
const {
@@ -21,7 +35,7 @@ export const InputContainer = React.forwardRef((props, ref) => {
2135
<>
2236
<div className="input-container">
2337
<div className="input-label">
24-
{label}
38+
{props.label}
2539
<span className="required">*</span>
2640
</div>
2741
<div className="input-wrapper">
@@ -31,7 +45,7 @@ export const InputContainer = React.forwardRef((props, ref) => {
3145
</div>
3246
: null}
3347
<div className="element-wrapper">
34-
<Input {...{ref, ...passThru, getInputProps}} />
48+
<Input {...{getInputProps, rest}} />
3549
</div>
3650
{error ?
3751
<div className="icon-wrapper error">
@@ -51,10 +65,20 @@ export const InputContainer = React.forwardRef((props, ref) => {
5165
</div>
5266
</>
5367
);
54-
});
68+
};
5569

5670
InputContainer.defaultProps = {
57-
//default props
58-
}
71+
field: '',
72+
label: '',
73+
defaultValue: '',
74+
required: false
75+
};
76+
77+
InputContainer.propTypes = {
78+
field: PropTypes.string,
79+
label: PropTypes.string,
80+
defaultValue: PropTypes.string,
81+
required: PropTypes.bool
82+
};
5983

6084
export default InputContainer;

src/components/input-form/index.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import { useForm } from "react-form";
3+
import PropTypes from 'prop-types';
4+
5+
export const InputForm = (props) => {
6+
const { defaultValues, debugForm, validate, onSubmit} = props
7+
8+
const {
9+
Form,
10+
meta: { isSubmitting, isSubmitted, canSubmit, error }
11+
} = useForm({
12+
defaultValues,
13+
validate: values => validate ? validate(values) : null,
14+
onSubmit: async (values, instance) => onSubmit ? onSubmit(values, instance) : null,
15+
debugForm: debugForm
16+
});
17+
18+
return (
19+
<>
20+
<Form>
21+
<div style={{width: "500px", marginLeft: "auto", marginRight: "auto"}}>
22+
{props.children}
23+
24+
{isSubmitted ? <em>Thanks for submitting!</em> : null}
25+
26+
{error ? <strong>{error}</strong> : null}
27+
28+
{isSubmitting ? (
29+
"Submitting..."
30+
) : (
31+
<div>
32+
<button type="submit" disable={!canSubmit ? 1 : 0}>Submit</button>
33+
</div>
34+
)}
35+
</div>
36+
</Form>
37+
</>
38+
);
39+
};
40+
41+
InputForm.defaultProps = {
42+
defaultValues: {},
43+
debugForm: false,
44+
validate: null,
45+
onSubmit: null
46+
};
47+
48+
InputForm.propTypes = {
49+
defaultValues: PropTypes.object,
50+
debugForm: PropTypes.bool,
51+
validate: PropTypes.func,
52+
onSubmit: PropTypes.func
53+
};
54+
55+
export default InputForm;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
import "../numeric/numeric.css";
3+
4+
const InputText = React.forwardRef((props, ref) => {
5+
const { getInputProps, passThru} = props;
6+
return (
7+
<>
8+
<input type="number" className="input-numeric" autoComplete="off" {...passThru} { ...getInputProps({ ref })} />
9+
</>
10+
);
11+
});
12+
13+
export default InputText;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.input-numeric {
2+
background-color: transparent !important;
3+
border: 0 !important;
4+
color: #000 !important;
5+
font-size: 12pt;
6+
height: 48px !important;
7+
outline: 0 !important;
8+
padding: 0 8px !important;
9+
width: 100%;
10+
}

src/components/input/text/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import React from 'react';
22
import "../text/text.css";
33

4-
const InputText = React.forwardRef(({getInputProps, ...passThro}, ref) => {
4+
const InputText = (props) => {
5+
const { getInputProps, rest} = props;
56
return (
67
<>
7-
<input type="text" className="input-text" autocomplete="off" {...passThro} {...getInputProps({ ref })} />
8+
<input type="text" className="input-text" autoComplete="off" {...getInputProps(rest)} />
89
</>
910
);
10-
});
11+
};
1112

1213
export default InputText;

src/index.js

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,46 @@
11
import React from "react";
22
import ReactDOM from "react-dom";
3-
import InputContainer from "../src/components/input-container";
4-
import InputText from "../src/components/input/text";
5-
import { useForm } from "react-form";
6-
import { isRequired, isEmail } from "../src/libs/validation";
3+
import InputForm from "./components/input-form";
4+
import InputContainer from "./components/input-container";
5+
import InputText from "./components/input/text";
76
import { faEnvelope } from '@fortawesome/free-solid-svg-icons'
87

9-
function App() {
10-
// set default values
11-
const defaultValues = React.useMemo(
12-
() => ({
13-
first_name: "",
14-
last_name: "",
15-
email_address: ""
16-
}),
17-
[]
18-
);
19-
const {
20-
Form,
21-
meta: { isSubmitting, isSubmitted, canSubmit, error }
22-
} = useForm({
23-
defaultValues,
24-
validate: values => {
25-
// validate any combinations of field values here
26-
},
27-
onSubmit: async (values, instance) => {
28-
await new Promise(resolve => setTimeout(resolve, 1000));
29-
},
30-
debugForm: true
31-
});
8+
// object used to populate the default values for the entire form
9+
const defaultValues = {
10+
first_name: "bill"
11+
}
12+
13+
// function used to validate multiple fields at the same time
14+
const validate = (values) => {
15+
if (values.first_name === "john") {
16+
return "change default value";
17+
}
18+
return false;
19+
}
20+
21+
// function used to hand form submit event
22+
const onSubmit = async (values, instance) => {
23+
await new Promise(resolve => setTimeout(resolve, 1000));
24+
}
3225

26+
// field validation
27+
const fieldValidation= (value) => {
28+
return value.length < 10 ? "name needs to be greater than 12 characters" : false
29+
}
30+
31+
function App() {
3332
return (
34-
<Form>
35-
<div style={{width: "500px", marginLeft: "auto", marginRight: "auto"}}>
36-
<InputContainer field="first_name" label="Given Name" Input={InputText} validate={isRequired} />
33+
<>
34+
<InputForm debugForm={true} onSubmit={onSubmit} validate={validate} defaultValues={defaultValues} >
35+
<InputContainer field="first_name" label="Given Name" Input={InputText} required validate={fieldValidation}/>
3736
<br />
3837
<br />
39-
<InputContainer field="last_name" label="Family Name" Input={InputText} validate={isRequired} />
38+
<InputContainer field="last_name" label="Family Name" Input={InputText} defaultValue="watson" required />
4039
<br />
4140
<br />
42-
<InputContainer field="email_address" label="Email" Input={InputText} Icon={faEnvelope} validate={isEmail} />
43-
44-
{isSubmitted ? <em>Thanks for submitting!</em> : null}
45-
46-
{error ? <strong>{error}</strong> : null}
47-
48-
{isSubmitting ? (
49-
"Submitting..."
50-
) : (
51-
<div>
52-
<button type="submit" disable={!canSubmit}>Submit</button>
53-
</div>
54-
)}
55-
</div>
56-
</Form>
41+
<InputContainer field="email_address" label="Email" Input={InputText} Icon={faEnvelope} />
42+
</InputForm>
43+
</>
5744
);
5845
}
5946

src/libs/validation/index.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
export const isRequired = (value) => {
2-
return !value ? "Required" : false
3-
}
41

52
export const isEmail = async value => {
63
if (!value) {
@@ -9,7 +6,6 @@ export const isEmail = async value => {
96
if (!validateEmail(value)) {
107
return "Please enter a valid email addresss";
118
}
12-
console.log(`Checking email: ${value}...`);
139
await new Promise(resolve => setTimeout(resolve, 2000));
1410

1511
return value === "bill@gmail.com"

0 commit comments

Comments
 (0)