Repository URL to install this package:
Version:
0.14.1 ▾
|
/* 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