CustomInput.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. import {
  2. FilledTextFieldProps,
  3. FormControl,
  4. FormHelperText,
  5. Grid,
  6. IconButton,
  7. Input,
  8. InputAdornment,
  9. InputLabel,
  10. makeStyles,
  11. StandardTextFieldProps,
  12. TextField,
  13. } from '@material-ui/core';
  14. import Icons from '../icons/Icons';
  15. import { ReactElement } from 'react';
  16. import {
  17. IAdornmentConfig,
  18. IIconConfig,
  19. ITextfieldConfig,
  20. ICustomInputProps,
  21. IBlurParam,
  22. IValidInfo,
  23. IChangeParam,
  24. } from './Types';
  25. const handleOnBlur = (param: IBlurParam) => {
  26. const {
  27. event,
  28. key,
  29. param: { cb, checkValid, validations },
  30. } = param;
  31. const input = event.target.value;
  32. const isValid = validations
  33. ? checkValid({
  34. key,
  35. value: input,
  36. rules: validations,
  37. })
  38. : true;
  39. if (isValid) {
  40. cb(input);
  41. }
  42. };
  43. const handleOnChange = (param: IChangeParam) => {
  44. const {
  45. event,
  46. key,
  47. param: { cb, checkValid, validations },
  48. } = param;
  49. const input = event.target.value;
  50. const isValid = validations
  51. ? checkValid({
  52. key,
  53. value: input,
  54. rules: validations,
  55. })
  56. : true;
  57. if (isValid) {
  58. cb(input);
  59. }
  60. };
  61. const getAdornmentStyles = makeStyles(theme => ({
  62. icon: {
  63. color: theme.palette.milvusGrey.dark,
  64. },
  65. }));
  66. const getAdornmentInput = (
  67. config: IAdornmentConfig,
  68. checkValid: Function,
  69. validInfo: IValidInfo
  70. ): ReactElement => {
  71. const {
  72. label,
  73. key,
  74. icon,
  75. isPasswordType = false,
  76. inputClass,
  77. showPassword,
  78. validations,
  79. onIconClick,
  80. onInputBlur,
  81. onInputChange,
  82. } = config;
  83. const classes = getAdornmentStyles();
  84. const param = {
  85. cb: onInputBlur || (() => {}),
  86. validations: validations || [],
  87. checkValid,
  88. };
  89. const info = validInfo ? validInfo[key] : null;
  90. return (
  91. <FormControl>
  92. <InputLabel htmlFor="standard-adornment-password">{label}</InputLabel>
  93. <Input
  94. classes={{ root: `${inputClass || {}}` }}
  95. type={isPasswordType ? (showPassword ? 'text' : 'password') : 'text'}
  96. onBlur={e => {
  97. handleOnBlur({ event: e, key, param });
  98. }}
  99. onChange={e => {
  100. handleOnChange({
  101. event: e,
  102. key,
  103. param: {
  104. ...param,
  105. cb: onInputChange || (() => {}),
  106. },
  107. });
  108. }}
  109. endAdornment={
  110. <InputAdornment position="end">
  111. <IconButton onClick={onIconClick || (() => {})} edge="end">
  112. {isPasswordType
  113. ? showPassword
  114. ? Icons.visible({ classes: { root: classes.icon } })
  115. : Icons.invisible({ classes: { root: classes.icon } })
  116. : icon}
  117. </IconButton>
  118. </InputAdornment>
  119. }
  120. inputProps={{
  121. 'data-cy': key,
  122. }}
  123. />
  124. {
  125. <FormHelperText classes={{ root: `${inputClass || {}}` }}>
  126. {info && info.result && info.errText
  127. ? createHelperTextNode(info.errText)
  128. : ' '}
  129. </FormHelperText>
  130. }
  131. </FormControl>
  132. );
  133. };
  134. const getIconInput = (
  135. config: IIconConfig,
  136. checkValid: Function,
  137. validInfo: IValidInfo
  138. ): ReactElement => {
  139. const { icon, inputType, inputConfig, containerClass, spacing, alignItems } =
  140. config;
  141. return (
  142. <Grid
  143. classes={{ container: `${containerClass || {}}` }}
  144. container
  145. spacing={spacing || 0}
  146. alignItems={alignItems}
  147. >
  148. <Grid item>{icon}</Grid>
  149. <Grid item>
  150. {inputType === 'icon'
  151. ? getTextfield(inputConfig as ITextfieldConfig, checkValid, validInfo)
  152. : getAdornmentInput(
  153. inputConfig as IAdornmentConfig,
  154. checkValid,
  155. validInfo
  156. )}
  157. </Grid>
  158. </Grid>
  159. );
  160. };
  161. const getTextfield = (
  162. config: ITextfieldConfig,
  163. checkValid: Function,
  164. validInfo: IValidInfo
  165. ): ReactElement => {
  166. const {
  167. key,
  168. className,
  169. validations,
  170. onBlur,
  171. onChange,
  172. fullWidth,
  173. size,
  174. placeholder,
  175. inputProps,
  176. InputProps,
  177. value,
  178. ...others
  179. } = config;
  180. if (value !== undefined) {
  181. (others as any).value = value;
  182. }
  183. const param = {
  184. cb: onBlur || (() => {}),
  185. validations: validations || [],
  186. checkValid,
  187. };
  188. const info = validInfo ? validInfo[key] : null;
  189. const defaultInputProps = { 'data-cy': key };
  190. return (
  191. <TextField
  192. {...(others as
  193. | StandardTextFieldProps
  194. | FilledTextFieldProps
  195. | FilledTextFieldProps)}
  196. size={size || 'medium'}
  197. fullWidth={fullWidth}
  198. placeholder={placeholder || ''}
  199. inputProps={
  200. inputProps
  201. ? { ...inputProps, ...defaultInputProps }
  202. : { ...defaultInputProps }
  203. }
  204. error={info?.result && info.errText !== ''}
  205. InputProps={InputProps ? { ...InputProps } : {}}
  206. helperText={
  207. info && info.result && info.errText
  208. ? createHelperTextNode(info.errText)
  209. : ' '
  210. }
  211. className={className || ''}
  212. onBlur={event => {
  213. handleOnBlur({ event, key, param });
  214. }}
  215. // value={value}
  216. onChange={event => {
  217. handleOnChange({
  218. event,
  219. key,
  220. param: { ...param, cb: onChange || (() => {}) },
  221. });
  222. }}
  223. />
  224. );
  225. };
  226. const getStyles = makeStyles(theme => ({
  227. errWrapper: {
  228. display: 'flex',
  229. alignItems: 'flex-start',
  230. color: `${theme.palette.error.main}`,
  231. wordWrap: 'break-word',
  232. wordBreak: 'break-all',
  233. overflow: 'hidden',
  234. marginLeft: '12px',
  235. },
  236. errBtn: {
  237. marginRight: `${theme.spacing(1)}`,
  238. },
  239. }));
  240. const createHelperTextNode = (hint: string): ReactElement => {
  241. const classes = getStyles();
  242. return (
  243. <span className={classes.errWrapper}>
  244. {/* {Icons.error({
  245. fontSize: 'small',
  246. classes: {
  247. root: classes.errBtn,
  248. },
  249. })} */}
  250. {hint}
  251. </span>
  252. );
  253. };
  254. const CustomInput = (props: ICustomInputProps) => {
  255. const {
  256. type,
  257. iconConfig,
  258. textConfig,
  259. adornmentConfig,
  260. checkValid,
  261. validInfo,
  262. } = props;
  263. let template: ReactElement | null;
  264. switch (type) {
  265. case 'adornment':
  266. template = getAdornmentInput(adornmentConfig!, checkValid!, validInfo!);
  267. break;
  268. case 'icon':
  269. template = getIconInput(iconConfig!, checkValid!, validInfo!);
  270. break;
  271. case 'text':
  272. template = getTextfield(textConfig!, checkValid!, validInfo!);
  273. break;
  274. default:
  275. // default is plain text input
  276. template = getTextfield(textConfig!, checkValid!, validInfo!);
  277. }
  278. return template;
  279. };
  280. export default CustomInput;