TextField.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import React, { useState, useRef, useEffect } from 'react'
  2. import { useCSS, TextFieldStyleProps } from './TextField.style'
  3. import { IconProp } from '@fortawesome/fontawesome-svg-core'
  4. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
  5. import { spacing } from './../../theme'
  6. type TextFieldProps = {
  7. label: string
  8. helper?: string
  9. value?: string
  10. icon?: IconProp | undefined
  11. onChange?: (e: React.ChangeEvent) => void
  12. } & TextFieldStyleProps
  13. export default function TextField({
  14. label,
  15. helper = '',
  16. value = '',
  17. icon,
  18. disabled = false,
  19. onChange,
  20. ...styleProps
  21. }: TextFieldProps) {
  22. const inputRef = useRef<HTMLInputElement>(null)
  23. const [isActive, setIsActive] = useState(!!value)
  24. const [inputTextValue, setInputTextValue] = useState(value)
  25. const styles = useCSS({ isActive, disabled, ...styleProps })
  26. useEffect(() => {
  27. if (inputRef.current != null) {
  28. if (isActive) {
  29. inputRef.current.focus()
  30. } else {
  31. inputRef.current.blur()
  32. }
  33. }
  34. }, [isActive, inputRef])
  35. function onTextFieldClick() {
  36. if (!disabled) setIsActive(true)
  37. }
  38. function onInputTextBlur() {
  39. setIsActive(false)
  40. }
  41. // FIXME: add correct typing to event, see here: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239
  42. function onInputTextChange(event: any): void {
  43. if (!disabled) setInputTextValue(event.currentTarget.value)
  44. }
  45. return (
  46. <div css={styles.wrapper}>
  47. <div css={styles.container} onClick={onTextFieldClick}>
  48. <div css={styles.border}>
  49. <div
  50. css={styles.label}
  51. style={
  52. !inputTextValue && !isActive
  53. ? {}
  54. : {
  55. position: 'absolute',
  56. top: '-8px',
  57. left: '5px',
  58. fontSize: '0.7rem',
  59. padding: `0 ${spacing.xs}`,
  60. }
  61. }
  62. >
  63. {label}
  64. </div>
  65. <input
  66. css={styles.input}
  67. style={{ display: !!inputTextValue || isActive ? 'block' : 'none' }}
  68. ref={inputRef}
  69. type="text"
  70. value={inputTextValue}
  71. onChange={onInputTextChange}
  72. onBlur={onInputTextBlur}
  73. disabled={disabled}
  74. />
  75. {!!icon && <FontAwesomeIcon icon={icon || 'check'} css={styles.icon} />}
  76. </div>
  77. </div>
  78. {!!helper && <p css={styles.helper}>{helper}</p>}
  79. </div>
  80. )
  81. }