From caa4d5e1f35f83a01a98470b2546699cecea8082 Mon Sep 17 00:00:00 2001 From: Ashelyn Dawn Date: Sat, 7 Mar 2020 12:06:16 -0700 Subject: [PATCH] Form controller - partially complete, needs onSubmit --- components/form/form.js | 75 +++++++++++++++++++++++++++++++ components/form/input.js | 11 +++++ components/form/styles.module.css | 3 ++ pages/form.js | 16 +++++++ 4 files changed, 105 insertions(+) create mode 100644 components/form/form.js create mode 100644 components/form/input.js create mode 100644 components/form/styles.module.css create mode 100644 pages/form.js diff --git a/components/form/form.js b/components/form/form.js new file mode 100644 index 0000000..de07d52 --- /dev/null +++ b/components/form/form.js @@ -0,0 +1,75 @@ +// TODO: Enable exportDefaultFrom in Babel syntax +import React, { useReducer } from 'react' + +export const Input = require('./input.js').default + +export const FormController = function FormController({children, onSubmit}){ + const initialState = { + fields: {} + } + + const reducer = (state, action)=>{ + let fields = {...state.fields} + + // Update currently changing field + const prevField = state.fields[action.name] + const updatedField = { + ...prevField, + value: action.value, + isValid: prevField.validate?prevField.validate(action.value, fields):true + } + fields[action.name] = updatedField + + // Update other fields where the validate function takes whole state + const fieldNames = Object.keys(fields) + for(const name of fieldNames){ + if(name === action.name) continue + + const field = fields[name] + + if(field.validate && field.validate.length > 1) + fields[name] = { + ...field, + isValid: field.validate(field.value, fields) + } + } + + return {fields} +} + + // Update initial state + React.Children.forEach(children, child => { + if(!child.props.name) return; + + initialState.fields[child.props.name] = { + name: child.props.name, + validate: child.props.validate, + value: child.props.initialValue, + isValid: true + } + }) + + // Create reducer + const [state, dispatch] = useReducer(reducer, initialState) + + const _children = React.Children.map(children, child => { + const {name} = child.props; + if(!name) return child; + + const newProps = { + onChange: ev=>dispatch({name, value: ev.target.value}), + value: state.fields[name].value, + isValid: "" + state.fields[name].isValid + } + + return React.cloneElement(child, newProps) + }) + + console.log(JSON.stringify(state.fields, null, 2)) + + return ( + <> + {_children} + + ) +} diff --git a/components/form/input.js b/components/form/input.js new file mode 100644 index 0000000..c097849 --- /dev/null +++ b/components/form/input.js @@ -0,0 +1,11 @@ +import React from 'react' + +import styles from './styles.module.css' + +export default function Input({type, name, value, onChange, isValid}){ + return ( +
+ +
+ ) +} diff --git a/components/form/styles.module.css b/components/form/styles.module.css new file mode 100644 index 0000000..ecf0bbd --- /dev/null +++ b/components/form/styles.module.css @@ -0,0 +1,3 @@ +.formElementContainer { + display: block; +} diff --git a/pages/form.js b/pages/form.js new file mode 100644 index 0000000..6a17d3a --- /dev/null +++ b/pages/form.js @@ -0,0 +1,16 @@ +import React from 'react' + +import {FormController, Input} from '~/components/form' + +const Index = () => ( + <> +

Form Controller Test

+ + (value.length >= 8)} initialValue="" /> + + +) +export default Index + +// Help Almyki figure out how to do 4 spaces python, 2 spaces html +// also show her how to add a vertical bar