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