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    
ui-component-library / src / forms / input / InputState.tsx
Size: Mime:
/* eslint-disable brace-style */
/* eslint-disable curly */
/**
 * @fileoverview @todo - add the autocompletes from the inputs.d.ts
 * @todo - add preference to turn off autocomplete
 */
import { Serializable } from 'exotic'
import { toBoolean } from 'exotic'
import {
  extendObservable,
  action,
  observable,
  computed,
  decorate,
} from 'xmobx/mobx'
import { isValid, errorMessage } from '../deps'
import { shouldRemap, unknown, hasType } from './deps'
import { InputStateType, InputStateMethodsType, InputValue } from './typings'
import { toggleTypes, validTypes, types } from './fixture'

/**
 * @todo use mobx actions
 * @todo - onValueChange, keyboard navigation, plugins...
 */
// class InputState<Props = any> extends InputStateType<Props> implements InputStateMethodsType {
class InputState extends InputStateType {
  // @observable className = undefined
  // @observable value: InputValue = ''
  // @observable isEnabled = true
  // @observable isFocused = false
  // @observable isSelected = false
  // @observable type = 'text'
  // @observable elementList = []
  // @observable error: undefined | Error = undefined
  // @observable isValidInput = true
  @observable
  isVisible = true

  static init(data?: Object) {
    return new InputState(data)
  }
  static types = types
  isInputState: boolean = true

  constructor(stateData: Object = {}) {
    // shouldn't need this super call...
    super()

    // maybe it's mutating the static
    extendObservable(this, { ...types })

    // @note - this loops through to dynamically take all props
    // this is bad because it takes tooo many properties
    this.from(stateData)
  }

  // loop through keys, set props
  // chain.from
  @action
  from(obj: Object = {}) {
    // we can replace a whole object
    // that replacement can be observable
    const dynamic = {}

    const set = (key, value) => {
      const should = shouldRemap(key)

      if (should === false) {
        unknown(key, value)
      }
      if (key === 'identifier') {
        this._identifier = value
        // this.identity = this.identity || value
        this.identity = value
        return
      }

      // regardless
      dynamic[key] = value
      // === this will not update ===
      this[key] = value
    }

    const onKey = key => {
      const value = obj[key]
      if (hasType(key) === true) this[key] = value
      else set(key, value)
    }

    Object.keys(obj).forEach(onKey)

    // update
    this.dynamicState = dynamic
    return this
  }

  /**
   * @todo @name setIsFocused
   */
  @action.bound
  updateFocused(event: Event, instance) {
    if (!event || event.target.value === '') {
      this.isFocused = !this.isFocused
    }
  }

  /**
   * @note @todo @fixme - this is why we do actions to set the data
   */
  @action.bound
  validateInput() {
    this.setIsValidInput(isValid(this.value, this.validationType))
    this.errorMessage = errorMessage(this.errorMessageFor)
  }

  @action.bound
  setValue(value: InputValue) {
    console.log('setting_value', { selfValue: this.value, value, self: this })

    if (toggleTypes.includes(this.type)) {
      this.isSelected = toBoolean(value)
      return
    }
    this.value = value || ''
  }
  /**
   * @todo should be computed eh...
   */
  getValue = (): InputValue => {
    // @todo and radio, it should return value?
    if (toggleTypes.includes(this.type)) {
      return this.isSelected
    }
    return this.value
  }

  @action
  setValidationType(validationType: string) {
    this.validationType = validationType || ''
  }
  @action
  setType(type: string) {
    this.type = type
  }

  @action
  setIsValidInput(value: boolean) {
    this.isValidInput = value
  }
  // setEnabled
  disable = () => {
    this.isEnabled = false
  }
  enable = () => {
    this.isEnabled = true
  }
  // setValidity
  invalid = () => {
    this.isValid = false
  }
  // setValidity
  valid = () => {
    this.isValid = true
  }
  get identifier() {
    return this._identifier || this.identity || this.name || '@@empty'
  }
  select = () => {
    this.isSelected = true
  }
  unselect = () => {
    this.isSelected = false
  }

  @action.bound
  setIsSelected = isSelected => {
    this.isSelected = isSelected
  }

  @action
  setIsVisible(isVisible: boolean): void {
    this.isVisible = isVisible
  }

  /**
   * @description should not really be used - if ever used, as a last resort
   * @type {IAction}
   * @modifies this.input
   */
  setInputReference = (dom: HTMLInputElement) => {
    this.input = dom
  }

  /**
   * @description to put props into container
   */
  @action.bound
  setProps(props: Props) {
    console.log('input state setprops', props)
    this.props = props
  }

  // ========= protected read =========

  /**
   * @variation radio [name] for when it's a radio, because there is only one with the same name
   * @variation toggle/checkbox .isSelected
   * @variation text/textarea/other .value
   * @todo elementList
   *
   * @type {Computed}
   * @return {Serializable | JSON | Object}
   */
  toJSON(): Serializable {
    const key = this.name || this.identity
    const serialized = {
      [key]: this.value || this.isSelected,
    }

    /**
     * @todo @fixme bad serialization - fixed in ui-component-library
     */
    if (serialized['0'] === key) {
      delete serialized['0']
    }
    const serializedChildren =
      this.elementList.length > 0 && JSON.stringify(this.elementList)
    if (this.elementList.length > 0) {
      console.warn('can serialize children !!! ', serializedChildren)
    }
    return serialized
  }

  /**
   * @alias toSerialized
   * @type {Computed}
   * @return {String}
   */
  toString() {
    return JSON.stringify(this.toJSON(), undefined, 2)
  }
}

// map types to observable.ref
// decorate(InputState, {
//   types
// })

export { InputState }
export default InputState