import * as React from 'react'; import * as _ from 'lodash'; import { CSSProperties } from 'react'; import { IsBoolean, IsString } from 'class-validator'; import { Icon, Input, Select} from '@native-ads/antd'; import { BasicConfig, BasicContainer, BasicContainerPropsInterface } from '../../render/core/Container/types'; import componentLoader from '../../render/util/componentLoader'; import { InputProps } from '@native-ads/antd/lib/input/Input'; import { SelectValue } from '@native-ads/antd/lib/select'; const InputGroup = Input.Group; const SelectOption = Select.Option; export class InputConfig extends BasicConfig { /** * Input的数据模型Key */ name?: string; /** * Input 分组的配置 */ groups?: { name: string, label: string }[]; /** * 默认值 */ defaultValue?: string | number; /** * 延迟一定时间再更新数据模型 */ debounce?: number; /** * 输入框类型 * @public * @default text */ inputType: 'text' | 'number' | 'password' | 'email' | 'search'; /** * 输入框ID * @public * @default '' */ @IsString() id: string; /** * 空间大小 * @public * @default 'default' */ @IsString() size: 'default' | 'large' | 'small'; /** * 是否禁用 * @public * @default false */ @IsBoolean() disabled: boolean; /** * 带标签的 input,设置前置标签 * @public * @default '' */ @IsString() addonBefore: string; /** * 带标签的 input,设置后置标签 * @public * @default '' */ @IsString() addonAfter: string; /** * 没有输入展示的文字 */ @IsString() placeholder?: string; /** * 是否可读 */ @IsBoolean() readOnly?: boolean; /** * 前置图标 */ @IsString() prefix?: string; /** * 后置图标 */ @IsString() suffix?: string; /** * 文字检查 */ @IsBoolean() spellCheck?: boolean; /** * CSS class */ @IsString() className?: string; /** * 内联CSS属性 */ style?: CSSProperties; /** * 自动聚焦 */ @IsBoolean() autoFocus?: boolean; } export class InputPropsInterface extends BasicContainerPropsInterface { info: InputConfig; } export interface InputStateInterface { /** * inputGroup的选中项 */ selectedName: string; /** * 保存一份数据, 提供debounce功能 */ value: string | number; } class AbstractInput extends BasicContainer { private debounce$SetData: (name: string, value: any) => void; constructor(props: InputPropsInterface) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { selectedName: '', value: '' }; const $setData = this.props.$setData; if ($setData && this.props.info.debounce) { this.debounce$SetData = _.debounce((name: string, value: any) => { $setData(name, value); this.commonEventHandler('onChange', { event, value: value }); }, this.props.info.debounce); } } componentWillMount() { let info = this.getPropsInfo(this.props.info); if (this.props.$setData && info.name) { const $setData = this.props.$setData; const storeValue = this.getValueFromDataStore(info.name); let inputValue: string | number = ''; if (typeof storeValue === 'string' && storeValue.length > 0) { inputValue = storeValue; } else if (!_.isNil(info.defaultValue)) { inputValue = info.defaultValue; $setData(info.name, info.defaultValue); } // debounse模式是由state自主控制,其他是由上层store控制 if (info.debounce) { this.setState({ value: inputValue }); } } } private handleChange(key: string) { return (event: React.ChangeEvent) => { let value: string | number = event.target.value; let info = this.getPropsInfo(this.props.info); if (info.inputType === 'number') { value = Number(value); } if (this.props.$setData) { if (info.debounce) { this.setState({ value: value }, () => { this.debounce$SetData(key, value); }); } else { this.props.$setData(key, value); this.commonEventHandler('onChange', { event, value: value }); } } }; } componentWillReceiveProps(nextProps: InputPropsInterface) { let nextInfo = this.getPropsInfo(nextProps.info, nextProps); let name = nextInfo.name; if (name && nextProps.$data) { let nextValue = this.getValueFromDataStore(name, nextProps.$data); let existValue = this.state.value; if (nextValue !== existValue) { this.setState({ value: nextValue }); } } } private mapOptions(info: InputConfig): InputProps { return { placeholder: info.placeholder, type: info.inputType, id: info.id, name: info.name, size: info.size, disabled: info.disabled, readOnly: info.readOnly, addonBefore: info.addonBefore, addonAfter: info.addonAfter, autoComplete: 'off', prefix: info.prefix && , suffix: info.suffix && , spellCheck: info.spellCheck, autoFocus: info.autoFocus, className: info.className, style: info.style }; } private createInputElement(info: InputConfig, value: string, key: string) { let inputProps = this.mapOptions(info); return React.createElement(Input, { value: value, onChange: this.handleChange(key), onPressEnter: (event: React.KeyboardEvent) => { this.commonEventHandler('onPressEnter', { event: event, value: value }); }, onKeyDown: (event: React.KeyboardEvent) => { this.commonEventHandler('onKeyDown', { event: event, value: value }); }, onClick: (event: React.MouseEvent) => { this.commonEventHandler('onClick', { event: event, value: value }); }, onFocus: (event: React.MouseEvent) => { this.commonEventHandler('onFocus', { event: event, value: value }); }, onBlur: (event: React.MouseEvent) => { this.commonEventHandler('onBlur', { event: event, value: value }); }, ...inputProps }); } render() { let info = this.getPropsInfo(this.props.info); if (!info.name && !info.groups) { return
name or groups property is required for Input Element
; } if (!this.isUnderContainerEnv()) { console.log('Input Element is out of RCRE control, please put it inside container component'); return ; } let childElement; if (info.groups instanceof Array && info.groups.length > 0) { let groups = info.groups; let selectOptions = groups.map(group => { return ( {group.label} ); }); const selectChangeCallback = (val: SelectValue) => { if (typeof val === 'string') { let selectedValue = this.getValueFromDataStore(val); this.setState({ selectedName: val, value: selectedValue }); } }; let name = this.state.selectedName || groups[0].name; let inputValue; if (info.debounce) { inputValue = this.state.value; } else { inputValue = this.getValueFromDataStore(name); } let inputElement = this.createInputElement(info, inputValue, name); childElement = ( {inputElement} ); } else if (info.name) { let name = info.name; let value; if (info.debounce) { value = this.state.value; } else { value = this.getValueFromDataStore(name); } childElement = this.createInputElement(info, value, name); } return (
{childElement}
); } } componentLoader.addComponent('input', AbstractInput, InputPropsInterface); export default AbstractInput;