import * as React from 'react' import { connect } from 'react-redux' import { FormFieldWrapper, BaseFormField } from '.' import { FORM_REDUCER_KEY } from '../reducers' import { mapStateToField } from '../selectors' import { NumberInputProps, NumberInputComponentProps, AbstractFormField } from '../interfaces' import { setFormField } from '../actions' const styles = require('../../src/styles/components/forms.scss') /** * NOTE: you can't really have a number input in React * because of the error message of changing a controlled * component to an uncontrolled component. This happens because * undefined is not a valid starting value for a field * Instead it is much easier to use a string text field (which uses * the empty string as a valid starting input) and then to parse * the string as an int. This also gets round the problem that * e is a valid number in html */ class NumberInputComponent extends BaseFormField { public renderField() { const { name, disabled, placeholder } = this.props return ( ) } public getValueFromEvent(e: React.SyntheticEvent) { const val = e.currentTarget.value // handy trick to parse as either int or float const parsed = val * 1 if (Number.isNaN(parsed)) { // the user could have added an invalid char // at the end of a sequence of valid chars - so we need // to go back and check the last know value const oldValue = this.getValueFromState() // if the last known value weas the empty string then // we should convert it to undefined so it doesn't violate // type rules in the state tree return oldValue || undefined } return parsed } public getValueFromState() { const { value, onChange, field } = this.props // the value we get from the state will be an int or float const res = value && onChange ? value : field.value // the value we give to the input field must be a string return res ? res.toString() : '' } } const mapStateToProps = (state: any, ownProps: NumberInputProps) => ({ ...ownProps, field: mapStateToField(state[FORM_REDUCER_KEY], ownProps), }) const mapDispatchToProps = { setFormField, } const ConnectedNumberInput = connect(mapStateToProps, mapDispatchToProps)(NumberInputComponent) export class NumberInput extends FormFieldWrapper { public render() { return ( ) } }