Add new form components

This commit is contained in:
Eric Schultz 2018-10-01 15:27:58 -05:00
parent e4161531aa
commit 62f6228f81
8 changed files with 227 additions and 35 deletions

View file

@ -30,7 +30,7 @@ export default class StandardFieldComponent extends React.Component<StandardFiel
let stickyErrorDiv = this.props.inStickyError ? <div className="help-block" role="alert">{stickyErrorMessage}</div> : ""
return <div>
{this.renderChildren()}
{this.props.children}
{errorDiv}
{stickyErrorDiv }
</div>

View file

@ -6,6 +6,8 @@ import LabeledFieldComponent from "./LabeledFieldComponent";
import {injectIntl, InjectedIntl} from 'react-intl';
import {HoudiniField} from "../../lib/houdini_form";
import ReactInput from "./form/ReactInput";
import ReactSelect from './form/ReactSelect';
import ReactTextarea from "./form/ReactTextarea";
export const BasicField = observer((props:{field:Field, placeholder?:string, label?:string, wrapperClassName?:string, inputClassNames?:string}) =>{
@ -14,7 +16,46 @@ export const BasicField = observer((props:{field:Field, placeholder?:string, lab
inputId={props.field.id} labelText={field.label} inError={field.hasError} error={field.error}
inStickyError={field.hasServerError} stickyError={field.serverError}
className={props.wrapperClassName} >
<ReactInput field={field} label={props.label} placeholder={props.placeholder} className={`form-control ${props.inputClassNames || ''}`}/>
</LabeledFieldComponent>
})
})
export const SelectField = observer((props:{field:Field, placeholder?:string, label?:string, wrapperClassName?:string, inputClassNames?:string, options?:Array<{id:any, name:string}>}) =>{
let field = props.field as HoudiniField
return <LabeledFieldComponent
inputId={props.field.id} labelText={field.label} inError={field.hasError} error={field.error}
inStickyError={field.hasServerError} stickyError={field.serverError}
className={props.wrapperClassName} >
<ReactSelect field={field} label={props.label} placeholder={props.placeholder} className={`form-control ${props.inputClassNames}`} options={props.options}/>
</LabeledFieldComponent>
})
export const TextareaField = observer((props:{field:Field, placeholder?:string, label?:string, wrapperClassName?:string, inputClassNames?:string, rows?:number}) =>{
let field = props.field as HoudiniField
return <LabeledFieldComponent
inputId={props.field.id} labelText={field.label} inError={field.hasError} error={field.error}
inStickyError={field.hasServerError} stickyError={field.serverError}
className={props.wrapperClassName} >
<ReactTextarea field={field} label={props.label} placeholder={props.placeholder} className={`form-control ${props.inputClassNames}`} rows={props.rows}/>
</LabeledFieldComponent>
})
export const CurrencyField = observer((props:{field:Field,placeholder?:string, label?:string, currencySymbol?:string, wrapperClassName?:string, inputClassNames?:string}) => {
let field = props.field as HoudiniField
let currencySymbolId = props.field.id + "_____currency_symbol"
return <LabeledFieldComponent
inputId={props.field.id} labelText={field.label} inError={field.hasError} error={field.error}
inStickyError={field.hasServerError} stickyError={field.serverError}
className={props.wrapperClassName} >
<div className="input-group">
<span className="input-group-addon" id={currencySymbolId}>{props.currencySymbol}</span>
<ReactInput field={field} label={props.label} placeholder={props.placeholder} className={`form-control ${props.inputClassNames}`} aria-describedby={currencySymbolId}/>
</div>
</LabeledFieldComponent>
});

View file

@ -5,24 +5,18 @@ import {InjectedIntlProps, injectIntl} from 'react-intl';
import {Field} from "mobx-react-form";
import {observable, action, toJS, runInAction} from 'mobx';
import {InputHTMLAttributes} from 'react';
import {ReactInputProps} from "./react_input_props";
import {SelectHTMLAttributes} from "react";
import {ReactSelectProps} from "./ReactSelect";
import {castToNullIfUndef} from "../../../lib/utils";
type InputTypes = ReactInputProps &
InputHTMLAttributes<HTMLInputElement>
export interface ReactInputProps
{
field:Field
label?:string
placeholder?:string
}
class ReactInput extends React.Component<InputTypes, {}> {
function castToNullIfUndef(i:any){
return i === undefined ? null : i
}
class ReactInput extends React.Component<ReactInputProps & InputHTMLAttributes<HTMLInputElement>, {}> {
constructor(props:ReactInputProps){
constructor(props:InputTypes){
super(props)
}
@ -43,7 +37,7 @@ class ReactInput extends React.Component<ReactInputProps & InputHTMLAttributes<H
}
componentDidUpdate(prevProps: Readonly<ReactInputProps>, prevState: Readonly<{}>): void {
componentDidUpdate(prevProps: Readonly<InputTypes>, prevState: Readonly<{}>): void {
this.updateProps()
}
@ -53,18 +47,9 @@ class ReactInput extends React.Component<ReactInputProps & InputHTMLAttributes<H
this.field.set('placeholder', castToNullIfUndef(this.props.placeholder))
}
@action.bound
renderChildren(){
let ourProps = this.winnowProps()
let elem = React.cloneElement(this.props.children as React.ReactElement<any>,
{...ourProps, ...this.field.bind() })
return elem
}
///Removes the properties we don't want to put into the input element
@action.bound
winnowProps(): ReactInputProps & InputHTMLAttributes<HTMLInputElement> {
winnowProps(): InputTypes {
let ourProps = {...this.props}
delete ourProps.field
delete ourProps.value
@ -73,14 +58,7 @@ class ReactInput extends React.Component<ReactInputProps & InputHTMLAttributes<H
}
render() {
if (this.props.children)
{
return this.renderChildren()
}
else {
return <input {...this.winnowProps()} {...this.field.bind()}/>
}
}
}

View file

@ -0,0 +1,10 @@
// License: LGPL-3.0-or-later
import * as React from 'react';
import 'jest';
import ReactSelect from './ReactSelect'
describe('ReactSelect', () => {
test('your test here', () => {
expect(false).toBe(true)
})
})

View file

@ -0,0 +1,80 @@
// License: LGPL-3.0-or-later
import * as React from 'react';
import { observer } from 'mobx-react';
import {InjectedIntlProps, injectIntl} from 'react-intl';
import {Field} from "../../../../../types/mobx-react-form";
import {InputHTMLAttributes} from "react";
import {action, observable} from "mobx";
import {SelectHTMLAttributes} from "react";
import {ReactInputProps} from "./react_input_props";
import {castToNullIfUndef} from "../../../lib/utils";
export interface ReactSelectProps extends ReactInputProps
{
options?:Array<{id:any, name:string}>
}
type InputTypes = ReactSelectProps & SelectHTMLAttributes<HTMLSelectElement>
class ReactSelect extends React.Component<InputTypes, {}> {
constructor(props:InputTypes){
super(props)
}
@observable
field:Field
@action.bound
componentWillMount(){
this.field = this.props.field
this.updateProps()
}
componentWillUnmount(){
}
componentDidUpdate(prevProps: Readonly<InputTypes >, prevState: Readonly<{}>): void {
this.updateProps()
}
@action.bound
updateProps() {
this.field.set('label', castToNullIfUndef(this.props.label))
this.field.set('placeholder', castToNullIfUndef(this.props.placeholder))
}
///Removes the properties we don't want to put into the input element
@action.bound
winnowProps(): InputTypes {
let ourProps = {...this.props}
delete ourProps.field
delete ourProps.value
delete ourProps.options
return ourProps
}
render() {
return <select {...this.winnowProps()} {...this.field.bind()}>
{ this.props.options ? this.props.options.map(option =>
<option key={option.id} value={option.id}>{option.name}</option>
) : this.props.children
}
</select>
}
}
export default observer(ReactSelect)

View file

@ -0,0 +1,10 @@
// License: LGPL-3.0-or-later
import * as React from 'react';
import 'jest';
import ReactSelect from './ReactSelect'
describe('ReactSelect', () => {
test('your test here', () => {
expect(false).toBe(true)
})
})

View file

@ -0,0 +1,65 @@
// License: LGPL-3.0-or-later
import * as React from 'react';
import { observer } from 'mobx-react';
import {InjectedIntlProps, injectIntl} from 'react-intl';
import {Field} from "../../../../../types/mobx-react-form";
import {InputHTMLAttributes, ReactText, TextareaHTMLAttributes} from "react";
import {action, observable} from "mobx";
import {ReactInputProps} from "./react_input_props";
import {castToNullIfUndef} from "../../../lib/utils";
type InputTypes = ReactInputProps & TextareaHTMLAttributes<HTMLTextAreaElement>
class ReactTextarea extends React.Component<InputTypes, {}> {
constructor(props:InputTypes){
super(props)
}
@observable
field:Field
@action.bound
componentWillMount(){
this.field = this.props.field
this.updateProps()
}
componentWillUnmount(){
}
componentDidUpdate(prevProps: Readonly<InputTypes>, prevState: Readonly<{}>): void {
this.updateProps()
}
@action.bound
updateProps() {
this.field.set('label', castToNullIfUndef(this.props.label))
this.field.set('placeholder', castToNullIfUndef(this.props.placeholder))
}
///Removes the properties we don't want to put into the input element
@action.bound
winnowProps(): InputTypes {
let ourProps = {...this.props}
delete ourProps.field
delete ourProps.value
return ourProps
}
render() {
return <textarea {...this.winnowProps()} {...this.field.bind()}/>
}
}
export default observer(ReactTextarea)

View file

@ -0,0 +1,8 @@
import {Field} from "mobx-react-form";
export interface ReactInputProps
{
field:Field
label?:string
placeholder?:string
}