Repository URL to install this package:
|
Version:
4.0.7 ▾
|
import { FocusEvent } from 'react'
import { Serializable } from '@skava/typings'
import { toBoolean, isArray } from 'exotic'
import { extendObservable, action, observable, computed } from 'xmobx/mobx'
import { isValid, errorMessage } from '../deps'
import { FormStateType } from '../form/typings'
import { shouldRemap, unknown, hasType } from './deps'
import {
InputStateType,
InputStateMethodsType,
InputValue,
InputStringType,
} from './typings'
import { toggleTypes, validTypes, types } from './fixture'
/**
* @todo use mobx actions
* @todo - onValueChange, keyboard navigation, plugins...
*/
class InputState<Props = any> extends InputStateType<Props> {
// @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
formState: FormStateType
static init(data?: Object) {
return new InputState(data)
}
static types = types
isInputState: boolean = true
constructor(stateData: Object = {}) {
// shouldn't need this super call...
super()
/**
* @todo !!!!!!!!!!!!!!! REMOVE - THIS MAKES EVERYTHING OBSERVABLE @@PERF
*/
console.warn(
'!!!!!!!!!!!!!!! REMOVE - THIS MAKES EVERYTHING OBSERVABLE @@PERF'
)
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
* @see chain.from
*/
@action
from(obj: Object = {}) {
// we can replace a whole object
// that replacement can be observable
const dynamic = {}
const set = (key: string, value: any) => {
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: FocusEvent<any>, 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 as string)
}
@action.bound
setValue(value: InputValue) {
console.log('setting_value', { selfValue: this.value, value, self: this })
if (toggleTypes.includes(this.type as InputStringType)) {
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 as InputStringType)) {
return this.isSelected as boolean
}
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: boolean) => {
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
*/
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']
}
/**
* @todo @@perf put in in env, remove, use new form flow
*/
if (isArray(this.elementList) && this.elementList.length > 0) {
const serializedChildren =
isArray(this.elementList) &&
this.elementList.length > 0 &&
JSON.stringify(this.elementList)
console.warn('can serialize children !!! ', serializedChildren)
}
return serialized
}
toString() {
return JSON.stringify(this.toJSON(), undefined, 2)
}
}
export { InputState }
export default InputState