Skip to content

Instantly share code, notes, and snippets.

@karlbright
Created January 31, 2017 09:02
Show Gist options
  • Save karlbright/8ff8347e01ab167bf26fd0647202466c to your computer and use it in GitHub Desktop.
Save karlbright/8ff8347e01ab167bf26fd0647202466c to your computer and use it in GitHub Desktop.
import React from 'react'
import classnames from 'classnames'
import Input from './input'
import ColorPicker from './color_picker'
import FieldLabel from './field_label'
import ImageGrid from './image_grid'
import ImageField from './image_field'
import Divider from './divider'
import LargeButton from './large_button'
import camelcase from 'camelcase'
import {omit} from 'lodash'
import './experimental_form.sass'
const getAvailableFieldEventHandlers = (props, name) => {
if (!name) return {}
const events = [
'key down', 'key press', 'key up',
'focus', 'blur',
'change', 'input', 'submit',
'click', 'double click',
'drag', 'drag end', 'drag enter', 'drag exit', 'drag leave', 'drag over', 'drag start', 'drop',
'mouse down', 'mouse enter', 'mouse leave', 'mouse move', 'mouse out', 'mouse over', 'mouse up',
'select',
'touch cancel', 'touch end', 'touch move', 'touch start'
]
return events.reduce((obj, event, index) => {
const target = props[camelcase(`on ${name} ${event}`)]
if (target) obj[camelcase(`on ${event}`)] = target
return obj
}, {})
}
const getValidFieldProps = (field) => {
return omit(field, ['help', 'label'])
}
const getFieldComponent = (type) => {
switch (type) {
case 'color': return ColorPicker
case 'text': return Input
case 'image': return ImageField
case 'image-grid': return ImageGrid
default: return null
}
}
const getFieldValue = (props, field) => {
const valueOverrideProp = props[`${field.name}Value`]
if (valueOverrideProp) return valueOverrideProp
return props.values[field.name] ? props.values[field.name] : field.value
}
const renderField = (props, field) => {
const fieldValidProps = getValidFieldProps(field)
const fieldEventHandlers = getAvailableFieldEventHandlers(props, field.name)
const fieldComponent = getFieldComponent(field.type)
const fieldValue = getFieldValue(props, field)
return React.createElement(fieldComponent, {
...fieldValidProps,
...fieldEventHandlers,
value: props.values[field.name] ? props.values[field.name] : fieldValidProps.value
})
}
const renderSchema = (props) => props.schema.map((field, index) => {
const isLastField = index === props.schema.length
const labelClassNames = classnames('experimental-form__label', { '-with-help': field.help })
const renderedField = renderField(props, field)
if (!renderedField) {
console.warn(`Unable to render field type: ${field.type}`, field)
return null
}
return (
<div key={index}>
<div className={labelClassNames}><FieldLabel {...field} /></div>
<div className='experimental-form__field'>{renderedField}</div>
{isLastField ? null : <div className='experimental-form__divider'><Divider /></div>}
</div>
)
})
const renderSubmit = (props) => {
if (!props.onSubmit) return null
const label = props.submitLabel || 'Submit'
return (
<div className='experimental-form__action'>
<LargeButton success type='submit'>{label}</LargeButton>
</div>
)
}
const renderCancel = (props) => {
if (!props.onCancel) return null
const label = props.cancelLabel || 'Cancel'
return (
<div className='experimental-form__action'>
<LargeButton danger onClick={props.onCancel}>{label}</LargeButton>
</div>
)
}
const ExperimentalForm = (props) => {
return (
<form onSubmit={props.onSubmit}>
{renderSchema(props)}
{renderSubmit(props)}
{renderCancel(props)}
</form>
)
}
export default ExperimentalForm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment