UNPKG

mh-rn-component

Version:

171 lines (167 loc) 4.75 kB
import React, { useState, useEffect } from 'react' import { ScrollView, View, Text, TextInput, TextStyle, ViewStyle, StyleProp, StyleSheet, TouchableWithoutFeedback, TextInputProps } from 'react-native'; import { FieldRefType } from '../types' import Icon from '../Icon' import renderNode from '../helpers/renderNode' /** * todo 要怎么定义字体大小? * todo 报错了 React.ComponentPropsWithRef<typeof TextInput> & */ interface Props extends TextInputProps { type?: string, disabled?: boolean; disabledInputStyle?: StyleProp<ViewStyle>; label?: string; // todo 字体大小 这个字段是否需要 我认为label只需要简单提供就好了 所以不用太精细 labelFontSize?: number, labelStyle?: StyleProp<ViewStyle>; style?: StyleProp<ViewStyle>; rightIcon?: string | React.ReactElement<{}> onRightIconClick?: () => void; clearable?: boolean; clearIcon?: string,//清除图标的icon name clearIconColor?: string//清除图标的icon 颜色 onInput?: (value: string) => void border?: boolean//是否显示边框 borderStyle?: StyleProp<ViewStyle>; maxlength?: number showWordLimit?: boolean //是否显示字数统计 fieldStyle?: StyleProp<ViewStyle>; } type TextInputHandles = FieldRefType const Field = React.forwardRef<TextInputHandles, Props>(({ onRightIconClick, clearable, style, type, border = true, ...rest }: Props, ref) => { /** * 传递ref节点添加方法 */ const root = React.useRef<TextInput>(null); React.useImperativeHandle(ref, () => { const input = root.current; if (input) { return { focus: () => input.focus(), clear: () => input.clear(), // setNativeProps: (args: TextInputProps) => input.setNativeProps(args), isFocused: () => input.isFocused(), blur: () => input.blur(), }; } const noop = () => { throw new Error('TextInput is not available'); }; return { focus: noop, clear: noop, blur: noop, isFocused: noop }; }); const clearableHandel = () => { rest?.onInput && rest?.onInput("") root.current?.clear() } /** * [Props]type * 输入框形态 * 软键盘形态 */ const keyboardType = (type === 'number' ? 'numeric' : 'default') return ( <View style={StyleSheet.flatten([ styles.container, { paddingBottom: rest.showWordLimit ? 20 : 8 }, rest.disabled && styles.disabledInput, rest.disabled && rest.disabledInputStyle, rest.fieldStyle])}> {rest.label && ( <View style={[{ paddingRight: 8 }, rest.labelStyle]}> <Text style={{ fontSize: rest.labelFontSize || 16 }}>{rest.label}:</Text> </View>) } <View style={ StyleSheet.flatten([ styles.inputMain, border && styles.border, rest.borderStyle && rest.borderStyle]) }> <TextInput ref={root} style={StyleSheet.flatten([ styles.input, type === 'textarea' && styles.textarea, style ])} underlineColorAndroid="transparent" editable={!rest.disabled} secureTextEntry={type === 'password'} keyboardType={keyboardType} onChangeText={rest.onInput} multiline={type === 'textarea'} {...rest} /> {clearable && ( <Text style={{ display: rest.value ? "flex" : "none" }} onPress={clearableHandel}> <Icon name={rest.clearIcon || "closecircle"} color={rest.clearIconColor || "#333"}></Icon> </Text> )} {rest.rightIcon && ( <TouchableWithoutFeedback onPress={onRightIconClick}> <View>{renderNode(Icon, rest.rightIcon)}</View> </TouchableWithoutFeedback>) } </View> { (rest.showWordLimit && rest.maxlength) && <View style={styles.showWordLimit}> <Text>{rest.value?.length}/{rest.maxlength}</Text> </View> } {/* 自定义右边内容 */} </View> ) }) const styles = StyleSheet.create({ container: { width: "100%", flexDirection: 'row', alignItems: 'center', padding: 8, backgroundColor: '#fff', position: "relative", }, inputMain: { flexDirection: 'row', alignItems: 'center', flex: 1, paddingLeft: 8, paddingRight: 8, }, border: { borderWidth: 1, borderColor: "#ccc", borderRadius: 6, }, input: { flex: 1, fontSize: 16, minHeight: 40, }, textarea: { minHeight: 80, textAlignVertical: 'top' }, disabledInput: { opacity: 0.5, }, showWordLimit: { position: "absolute", right: 12, bottom: 0 } }); export default Field