UNPKG

weex-nuke

Version:

基于 Rax 、Weex 的高性能组件体系 ~~

363 lines (344 loc) 9.87 kB
'use strict'; /** @jsx createElement */ import { createElement, Component, PropTypes } from 'rax'; import View from 'nuke-view'; import Text from 'nuke-text'; import Image from 'nuke-image'; import { isWeex } from 'nuke-env'; import { bubbleKeys } from 'nuke-helper'; import BaseInput from 'nuke-base-input'; import TEXTINHERITKEYS from '../mods/inherit-keys'; import IMAGE_URL from '../mods/image'; class Input extends Component { constructor(props, context) { super(props); let value = null; if ('value' in props) { value = props.value; } else if ('defaultValue' in props) { value = props.defaultValue; } const count = (value && value.length) || 0; this.state = { value, inputValue: value, count: (value && value.length) || 0, maxLengthError: count > props.maxLength, }; this.fixedFont = context.commonConfigs && context.commonConfigs.fixedFont; if ('fixedFont' in props) { this.fixedFont = props.fixedFont; } this.inputHandler = this.inputHandler.bind(this); this.changeHander = this.changeHander.bind(this); this.clearHandler = this.clearHandler.bind(this); this.focusHandler = this.focusHandler.bind(this); this.blurHandler = this.blurHandler.bind(this); this.getRef = this.getRef.bind(this); this.getValue = this.getValue.bind(this); this.focus = this.focus.bind(this); this.blur = this.blur.bind(this); this.clear = this.clear.bind(this); } componentWillReceiveProps(nextProps) { if ( 'value' in nextProps && (typeof nextProps.value === 'string' || typeof nextProps.value === 'number') && nextProps.value !== this.state.inputValue ) { this.setState({ value: nextProps.value, inputValue: nextProps.value, count: nextProps.value.length, maxLengthError: nextProps.value.length > this.props.maxLength, }); } } inputHandler(text, eventObj) { const { maxLength } = this.props; this.setState({ // value: text, inputValue: text, count: text.length, maxLengthError: text.length > maxLength, }); this.trigger('onInput', eventObj); } changeHander(text, eventObj) { const { maxLength } = this.props; this.setState({ value: text, inputValue: text, count: text.length, maxLengthError: text.length > maxLength, }); this.trigger('onChange', text, eventObj); } getInput() { const { readOnly, disabled, onInput, onChange, hasClear, inputStyle, rows, multiple, style, ...others } = this.props; const { value } = this.state; const styles = this.props.themeStyle; const inputAttrs = { ...others, value: typeof value !== null ? value : null, readOnly, multiple, onInput: this.inputHandler, onChange: this.changeHander, onFocus: this.focusHandler, onBlur: this.blurHandler, disabled, }; if (isWeex) { // 如果是多行文本,添加 returnKeyType 会导致无法换换 if (multiple && !this.props.onReturn) { delete inputAttrs.onReturn; delete inputAttrs.returnKeyType; } } else if (!disabled) { delete inputAttrs.disabled; } if (multiple) { inputAttrs.rows = rows || 3; inputAttrs.style = Object.assign({}, styles['multiple-input-ele']); if (inputStyle.height || style.height) { inputAttrs.style.height = inputStyle.height || style.height; } if (inputStyle.lineHeight || style.lineHeight) { inputAttrs.style.lineHeight = inputStyle.lineHeight || style.lineHeight; } } else { inputAttrs.style = Object.assign({}, styles['single-input-ele']); if (inputStyle.height || style.height) { inputAttrs.style.height = inputStyle.height || style.height; } inputAttrs.style.lineHeight = inputStyle.lineHeight || style.lineHeight || inputAttrs.style.height; } TEXTINHERITKEYS.map((item) => { if (styles[item]) { inputAttrs.style[item] = styles[item]; } }); return ( <BaseInput fixedFont={this.fixedFont} {...inputAttrs} ref={(n) => { this.input = n; }} /> ); } clear() { this.setState({ value: '', count: 0, }); } clearHandler(e) { this.setState({ value: this.state.inputValue, }); this.setState({ value: '', inputValue: '', count: 0, }); this.focus(); this.trigger('onClear', ''); } focusHandler(e) { this.setState({ focus: true, }); this.trigger('onFocus', e); } trigger(fn, ...attrs) { if (typeof fn === 'string') fn = this.props[fn]; if (!(typeof fn === 'function')) return; return fn.apply(this, attrs); } blurHandler(e) { this.setState({ focus: false, }); this.trigger('onBlur', e); } focus() { this.input.focus(); } getRef() { return this.input.getRef(); } blur() { this.input.blur(); } getValue() { return this.input.getValue(); } renderClear(styles, height) { const { count } = this.state; return count ? ( <View style={[styles.clearWrap, { height }]} onClick={this.clearHandler}> <Image source={{ uri: IMAGE_URL.clear }} // onClick={this.clearHandler} style={styles.clear} /> </View> ) : null; } renderCustomIcon(styles, height) { const { icon = {} } = this.props; const { uri, onPress = () => {}, style = {} } = icon; if (!uri) return null; return ( <View style={[styles.icon, { height }, style]} onClick={onPress}> <Image source={{ uri }} style={[styles['icon-image'], style]} /> </View> ); } renderCount(styles) { const { maxLength, multiple, renderCount } = this.props; const { maxLengthError } = this.state; if (!maxLength || !renderCount) return null; const { count } = this.state; return ( <View x="count" style={styles[`${multiple ? 'multiple-count-wrap' : 'single-count-wrap'}`]}> <Text fixedFont={this.fixedFont} style={[ styles[`${multiple ? 'multiple-count-text' : 'single-count-text'}`], maxLengthError ? styles['count-error'] : {}, ]} > {count} / {maxLength} </Text> </View> ); } render() { const { readOnly, disabled, style = {}, renderCount, hideErrorWhenFocus, hasClear, multiple, status, errorMessage, } = this.props; const styles = this.props.themeStyle; const { focus, maxLengthError } = this.state; let inputWrapperStyle = Object.assign( {}, styles['input-wrap'], styles[`${multiple ? 'multiple-wrap' : 'single-wrap'}`], readOnly ? styles.readonly : {}, status === 'error' ? styles['error-input-wrap'] : {}, focus ? styles['focus-input-wrap'] : {}, disabled ? styles[`${multiple ? 'multiple' : 'single'}-disabled`] : {}, style ); const customHeight = inputWrapperStyle.height; // debugger; if ((status === 'error' && !hideErrorWhenFocus) || maxLengthError) { inputWrapperStyle = Object.assign(inputWrapperStyle, styles['error-input-wrap']); } if (disabled) { inputWrapperStyle = Object.assign(inputWrapperStyle, styles[`${multiple ? 'multiple' : 'single'}-disabled`]); } const outerStyle = {}; bubbleKeys.map((item) => { if (item in inputWrapperStyle) { outerStyle[item] = inputWrapperStyle[item]; } }); if (outerStyle.height) { delete outerStyle.height; } if (outerStyle.backgroundColor) { delete outerStyle.backgroundColor; } return ( <View x="normal-outter" style={outerStyle}> <View x="input-wrap" style={inputWrapperStyle}> {this.getInput()} </View> {hasClear ? this.renderClear(styles, customHeight) : null} {!hasClear ? this.renderCustomIcon(styles, customHeight) : null} {(status === 'error' && errorMessage) || renderCount ? ( <View x="help" style={styles.help}> {!focus && status === 'error' && errorMessage ? ( <Text fixedFont={this.fixedFont} style={styles['error-text']}> {errorMessage} </Text> ) : null} {this.renderCount(styles)} </View> ) : null} </View> ); } } Input.propTypes = { defaultValue: PropTypes.any, onFocus: PropTypes.func, onInput: PropTypes.func, onBlur: PropTypes.func, onReturn: PropTypes.func, placeholder: PropTypes.string, readOnly: PropTypes.boolean, disabled: PropTypes.boolean, style: PropTypes.any, maxLength: PropTypes.number, multiple: PropTypes.boolean, inputStyle: PropTypes.any, returnKeyType: PropTypes.any, hasClear: PropTypes.boolean, rows: PropTypes.number, maxRows: PropTypes.number, type: PropTypes.oneOf(['text', 'url', 'password', 'tel', 'date', 'time', 'email']), status: PropTypes.oneOf(['success', 'error']), errorMessage: PropTypes.string, renderCount: PropTypes.boolean, value: PropTypes.string, themeStyle: PropTypes.any, hideErrorWhenFocus: PropTypes.boolean, }; Input.defaultProps = { onFocus: () => {}, onInput: () => {}, onBlur: () => {}, onReturn: () => {}, placeholder: '', readOnly: false, disabled: false, style: {}, multiple: false, inputStyle: {}, hasClear: false, type: 'text', status: 'success', themeStyle: {}, renderCount: false, placeholderColor: '#999999', hideErrorWhenFocus: true, }; Input.contextTypes = { androidConfigs: PropTypes.any, commonConfigs: PropTypes.any, }; export default Input;