Form controller - partially complete, needs onSubmit
parent
ea28458ff6
commit
caa4d5e1f3
@ -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}
|
||||
</>
|
||||
)
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import React from 'react'
|
||||
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export default function Input({type, name, value, onChange, isValid}){
|
||||
return (
|
||||
<div className={styles.formElementContainer}>
|
||||
<input type={type} name={name} value={value} onChange={onChange} />
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
.formElementContainer {
|
||||
display: block;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import React from 'react'
|
||||
|
||||
import {FormController, Input} from '~/components/form'
|
||||
|
||||
const Index = () => (
|
||||
<>
|
||||
<h1>Form Controller Test</h1>
|
||||
<FormController onSubmit={console.log}>
|
||||
<Input type="password" name="password" validate={value=>(value.length >= 8)} initialValue="" />
|
||||
</FormController>
|
||||
</>
|
||||
)
|
||||
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
|
Loading…
Reference in New Issue