Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
/* eslint-disable brace-style */
import toClassName from 'classnames'
import {
  isObj,
  isFunction,
  Serializable,
  EMPTY_OBJ,
  isArray,
} from 'exotic'
import { InputState } from '../input/InputState'
import { GetInputValueType, InputStateComposedType } from '../input/typings'
import { KeyValueSpreadType, FormState } from './typings'
import { classes } from './fixture'

/**
 * === added these 4 fns to split out serializing ===
 */

export function toSerialized(serializable: Serializable): string {
  return serializable.toJSON
    ? serializable.toJSON()
    : JSON.stringify(serializable)
}

export function fromInputToSpread(inputData: Serializable): KeyValueSpreadType {
  const keyArray = Object.keys(inputData)
  const key = keyArray[0]
  const value = inputData[key]
  return { value, key }
}

export function fromInputToSerializable(
  input: InputStateComposedType,
  getInputValue: GetInputValueType
) {
  if (input.type === 'groupElements') {
    return input.elementList.slice(0).map(getInputValue)
  } else {
    return input
  }
}

/**
 * we pass getInputValue here because it's used as a recursive tail call
 * @see http://2ality.com/2015/06/tail-call-optimization.html
 */
export function fromInputToSerializedKeyValue(
  input: InputStateComposedType,
  getInputValue: GetInputValueType
) {
  const serializable = fromInputToSerializable(input, getInputValue)
  const inputData = toSerialized(serializable)
  return fromInputToSpread(inputData)
}

/**
 * @todo -  this should be InputState.from
 * @description ensure the value is coerced to inputstate
 */
export function toInputState(input: InputStateComposedType, index?: number) {
  // console.log('formstate input', input)
  if (input.type === 'groupElements') {
    input.elementList = input.elementList.map(toInputState)
  }
  // already something that extends input state
  if (isFunction(input.setValue)) {
    return input
  } else {
    return InputState.init(input)
  }
}

/**
 * @todo split
 * @param {ObserverForm} instance
 */
export function toClassList(instance) {
  const {
    formClassName,
    // @deprecated
    SubmitCustomClass,
    CancelCustomClass,
    ButtonGroupCustomClass,
    // cache stringified
    cachedClassList,
  } = instance
  const customClasslist = instance.classList || EMPTY_OBJ

  const custom = {
    form: formClassName,
    buttonGroup: customClasslist.buttonClass || ButtonGroupCustomClass,
    submitButton: customClasslist.submitButton || SubmitCustomClass,
    cancelButton: customClasslist.cancelButton || CancelCustomClass,
  }

  if (JSON.stringify(custom) === JSON.stringify(cachedClassList)) {
    return cachedClassList
  }

  const classList = {
    /**
     * classNames
     * @todo - variable names are camelCase...
     */
    // form: [classes.form, custom.form],
    form: toClassName(classes.form, custom.form),
    /**
     * is usually Blue
     * there is no need for custom classname
     * use scoped styles
     */
    // submitButton: [classes.submitButton, custom.submitButton],
    submitButton: toClassName(classes.submitButton, custom.submitButton),

    /**
     * is usually GhostButton or BlueButton.grey
     */
    // cancelButton: [classes.cancelButton, custom.cancelButton],
    cancelButton: toClassName(classes.cancelButton, custom.cancelButton),

    /**
     * meh
     */
    // buttonGroup: [classes.buttonGroup, custom.buttonGroup],
    buttonGroup: toClassName(classes.buttonGroup, custom.buttonGroup),
  }

  instance.cachedClassList = classList
  return classList
}

/**
 * @example
 * <label for='eh'>
 *    <?img /> to show an image instead of the input for custom styles
 *    <input id='eh'/>
 *    <span|div> children|text
 * </label>
 */

export const isInputState = input => isObj(input) && isFunction(input.setValue)

export function handleRecursive(state: FormState, index: number) {
  const input = state.inputsList[index]
  const { elementList } = input
  if (isArray(elementList) === false) {
    return
  }

  const toChild = (nested, nestedIndex) => {
    const nestedState = toInputStateAt(input, nestedIndex)
    // just metadata, can remove
    // nestedState.parent = input
    // nestedState.form = state
    return nestedState
  }

  // for toInputStateAt...
  input.inputsList = input.elementList
  input.elementList = input.elementList.map(toChild)
  input.elementList = input.inputsList
  delete input.inputsList
}

export function toInputStateAt(
  state: FormState,
  index: number
): InputStateComposedType {
  // annoyingly named
  const inputsList = state.inputsList
  const initialState = inputsList[index]

  // !!!! THIS IS THE ISSUE
  // initialState && initialState instanceof InputState
  const isAlreadyState = isInputState(initialState)

  // for sanity
  if (isAlreadyState === true) {
    return initialState
  }
  // should call action...
  if (isAlreadyState === false) {
    // could pass in form as a parent (, state)
    state.inputsList[index] = new InputState(initialState)
    handleRecursive(state, index)
  }
  const instantiated = inputsList[index]
  return instantiated
}