erikras/redux-form

View on GitHub
src/createFieldProps.js

Summary

Maintainability
A
30 mins
Test Coverage
// @flow
import type { Event, Structure } from './types'
import type { Dispatch } from 'redux'
import type { FieldProps, InputProps } from './FieldProps.types'

export type Props = {
  asyncError: any,
  asyncValidating: boolean,
  onBlur: {
    (event: Event, newValue: ?any, previousValue: ?any, name: ?string): void
  },
  onChange: {
    (event: Event, newValue: ?any, previousValue: ?any, name: ?string): void
  },
  onDrop: {
    (event: Event, newValue: ?any, previousValue: ?any, name: ?string): void
  },
  onDragStart: { (event: Event, name: ?string): void },
  onFocus: { (event: Event, name: ?string): void },
  dirty: boolean,
  dispatch: Dispatch<any>,
  form: string,
  format?: { (value: any, name: string): any },
  initial: any,
  parse?: { (value: any, name: string): any },
  normalize?: { (value: any): any },
  pristine: boolean,
  props?: Object,
  state: any,
  submitError?: string,
  submitFailed: boolean,
  submitting: boolean,
  syncError?: any,
  syncWarning?: any,
  type?: string,
  validate?: { (values: any): Object },
  value: any,
  _value: any,
  warn?: { (values: any): Object }
}

const processProps = (
  type: ?string,
  props: InputProps,
  _value: any,
  deepEqual: Function
): Object => {
  const { value } = props
  if (type === 'checkbox') {
    return {
      ...props,
      checked: !!value
    }
  }
  if (type === 'radio') {
    return {
      ...props,
      checked: deepEqual(value, _value),
      value: _value
    }
  }
  if (type === 'select-multiple') {
    return {
      ...props,
      value: value || []
    }
  }
  if (type === 'file') {
    return {
      ...props,
      value: value || undefined
    }
  }
  return props
}

export default function createFieldProps(
  { getIn, toJS, deepEqual }: Structure<any, any>,
  name: string,
  {
    asyncError,
    asyncValidating,
    onBlur,
    onChange,
    onDrop,
    onDragStart,
    dirty,
    dispatch,
    onFocus,
    form,
    format,
    initial,
    parse, // eslint-disable-line no-unused-vars
    pristine,
    props,
    state,
    submitError,
    submitFailed,
    submitting,
    syncError,
    syncWarning,
    validate, // eslint-disable-line no-unused-vars
    value,
    _value,
    warn, // eslint-disable-line no-unused-vars
    ...custom
  }: Props
): FieldProps {
  const error = syncError || asyncError || submitError
  const warning = syncWarning

  const formatFieldValue = (value, format) => {
    if (format === null) {
      return value
    }
    const defaultFormattedValue = value == null ? '' : value
    return format ? format(value, name) : defaultFormattedValue
  }

  const formattedFieldValue = formatFieldValue(value, format)

  return {
    input: processProps(
      custom.type,
      {
        name,
        onBlur,
        onChange,
        onDragStart,
        onDrop,
        onFocus,
        value: formattedFieldValue
      },
      _value,
      deepEqual
    ),
    meta: {
      ...toJS(state),
      active: !!(state && getIn(state, 'active')),
      asyncValidating,
      autofilled: !!(state && getIn(state, 'autofilled')),
      dirty,
      dispatch,
      error,
      form,
      initial,
      warning,
      invalid: !!error,
      pristine,
      submitting: !!submitting,
      submitFailed: !!submitFailed,
      touched: !!(state && getIn(state, 'touched')),
      valid: !error,
      visited: !!(state && getIn(state, 'visited'))
    },
    custom: { ...custom, ...props }
  }
}