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 / ObserverInput.tsx
Size: Mime:
/* eslint-disable brace-style */
/**
 * @todo @fixme has big issue with SSR
 */
import React from 'react'
import { isFunction, isObj, isSafe, isUndefined } from 'exotic'
import { observer } from 'xmobx/mobx-react'
import FormState from '../form/FormState'
import { InputChain } from './InputChain'
import TextAreaInput from './plugins/Text/TextAreaInput'
import { GroupElementsWrap, InputWrap, InputElement } from './_elements'
import { fromPropsToInputChain, isVisible } from './deps'
import {
  defaultProps,
  toggleTypes,
  validTypes,
  types,
  inputTypes,
} from './fixture'
import { ObserverInputProps } from './typings'

function toState(props) {
  // because address has string state...
  if (isObj(props.state) === true) {
    return props.state
  } else {
    console.warn('did not pass state')
    // @todo - why is this a form state not input state.......
    return new FormState()
  }
}

function decorateState(props, state): void {
  // @todo - with typescript, it does not compile .name property safely
  const name = props.name || props.identity || props.identifier
  if (name && !state.name && Object.isExtensible(state)) {
    state.name = name
  }

  if (isFunction(state.setProps)) {
    state.setProps(props)
  }
}

// State = typeof FormState
@observer
class ObserverInput<
Props = ObserverInputProps,
State = any
> extends React.Component<Props, State> {
  plugin: InputChain

  static defaultProps = defaultProps

  // @note - unused
  // Input = InputElement
  Wrap = InputWrap

  /**
   * @param {React.ClassAttributes} props
   * @todo should default pass in parent form on state for parent-child state chain factorying
   */
  constructor(props: Props) {
    super(props)

    this.state = toState(props)
    decorateState(props, this.state)
    // seemingly the componentWillMount has an issue...
    this.updatePluginFrom(this.props)
  }

  // ========= @note - command click on the React.Name to see the types =========

  handleChange = event => {
    // log('handleChange')
    const value = isObj(event) ? event.target && event.target.value : event

    if (isFunction(this.state.setValue)) {
      this.state.setValue(value)
    } else {
      console.warn('[ObserverInput] state should implement .setValue')
    }

    // @note - should not be needed
    this.forceUpdate()
  }

  handleFocus = event => {
    // log('handleFocus')
    if (isFunction(this.state.updateFocused)) {
      this.state.updateFocused(event)
    } else {
      console.warn('[ObserverInput] state should implement .updateFocused')
    }

    this.forceUpdate()
  }

  handleBlur = event => {
    // log('handleBlur')
    // this.state.emitBlur(event)
  }

  /**
   * @todo @ada
   */
  renderGroupBox(props: Props) {
    const listView = props.elementList.map(this.renderNestedInputs)
    return (
      <GroupElementsWrap className={props.className}>
        {listView}
      </GroupElementsWrap>
    )
  }

  handleToggle = () => {
    // onToggle, onChange, onSelect, onClick...
    // console.log('this.state', this.state, this.props)
    if (isFunction(this.props.onToggle)) {
      this.props.onToggle(this.state)
    } else if (isFunction(this.props.onClick)) {
      // common props - used in makeDefault, maybe gift options
      this.props.onClick()
    } else if (isFunction(this.state.handleToggleSelected) === true) {
      // common state
      this.state.handleToggleSelected()
    } else if (isFunction(this.state.setIsSelected) === true) {
      // input state
      this.state.setIsSelected(!this.state.isSelected)
    }
    // @note added
    // if (isFunction(this.state.onClick)) {
    //   this.state.onToggle(this.state)
    // }
  }

  updateDropDownState = () => {
    // TODO
    // log('Inside updateDropDownState')
  }

  // @todo or renderProp
  renderWrap(...children) {
    return <this.Wrap>{children}</this.Wrap>
  }

  // @action
  validate() {
    this.plugin.validate()
  }

  updatePluginFrom(props: Props = this.props) {
    console.info('[ObserverInput] props: ')
    console.dir(props)

    // if (this.plugin) {
    //   // do we need to make a new chain...?
    //   return
    // }

    // this is actually more of a decorator...
    this.plugin = fromPropsToInputChain(props) || this.plugin

    if (isObj(this.plugin) === true) {
      this.plugin.setPluginState(props.state)
      this.plugin.setPluginProps(props.state)
      // has no nested test
      // this.plugin.state = this.props.state
      // trigger setter
      // this.plugin.props = this.props
    }
  }
  // or only on browser...
  // componentDidMount
  componentWillMount() {
    this.updatePluginFrom(this.props)
  }

  /**
   * @todo !!! @ganesh this should be an InputChain !!!
   */
  renderNestedInputs = (props: Props): InputChain => {
    if (props.type === inputTypes.groupElement) {
      return this.renderGroupBox(props)
    } else {
      const currentPlugin = fromPropsToInputChain(props)
      if (currentPlugin) {
        // console.log('inside plugins modal - Input type: ', props.type)
        const state = props.state ? props.state : props
        // currentPlugin.state = state
        const prop = { ...props, state }
        // currentPlugin.props = prop
        currentPlugin.setPluginProps(prop)
        currentPlugin.setPluginState(state)

        return currentPlugin.render()
      } else {
        console.warn('[ObserverInput] Plugin not found!')
      }
    }
  }

  renderInput = props => {
    // return this.plugin.render()
    // if (isObj(this.plugin) && isFunction(this.plugin.render)) {
    if (this.plugin && this.plugin.render) {
      this.plugin.setPluginProps(props)
      return this.plugin.render()
      // try {
      //   return this.plugin.render()
      // } catch (unknown) {
      //   console.error(unknown)
      // }
    } else {
      console.warn('[ObserverInput] missing plugin - (expand for stack trace)')
      console.log(this.plugin)
      return '@@input error'
    }
  }

  render() {
    const { type, isHidden } = this.props

    // @todo improve this conditional
    if (isVisible(isHidden) === false) {
      return ''
    }

    if (type === inputTypes.groupElement) {
      return this.renderGroupBox(this.props)
    } else {
      return this.renderInput(this.props)
    }
  }
}

export { ObserverInput as ObservableInput }
export { ObserverInput as Input }
export { ObserverInput }
export default ObserverInput