You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.5 KiB
134 lines
3.5 KiB
import React from 'react'
|
|
import { asField } from 'informed'
|
|
import system from '@rebass/components'
|
|
import { styles } from 'styled-system'
|
|
import { withTheme } from 'styled-components'
|
|
import { Flex } from 'rebass'
|
|
import { Message } from 'components/UI'
|
|
|
|
// Create an html textarea element that accepts all style props from styled-system.
|
|
const SystemTextArea = system(
|
|
{
|
|
as: 'textarea',
|
|
border: 1,
|
|
borderColor: 'gray',
|
|
borderRadius: '5px',
|
|
bg: 'transparent',
|
|
color: 'primaryText',
|
|
fontFamily: 'sans',
|
|
fontSize: 'm',
|
|
fontWeight: 'light',
|
|
p: 3,
|
|
width: 1,
|
|
rows: 5
|
|
},
|
|
...Object.keys(styles)
|
|
)
|
|
|
|
/**
|
|
* @render react
|
|
* @name TextArea
|
|
* @example
|
|
* <TextArea />
|
|
*/
|
|
class TextArea extends React.PureComponent {
|
|
static displayName = 'TextArea'
|
|
|
|
state = {
|
|
hasFocus: false
|
|
}
|
|
|
|
constructor(props) {
|
|
super(props)
|
|
const { forwardedRef } = this.props
|
|
this.inputRef = forwardedRef || React.createRef()
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
css,
|
|
onChange,
|
|
onBlur,
|
|
onFocus,
|
|
forwardedRef,
|
|
theme,
|
|
fieldApi,
|
|
fieldState,
|
|
justifyContent,
|
|
...rest
|
|
} = this.props
|
|
const { readOnly } = this.props
|
|
const { hasFocus } = this.state
|
|
const { setValue, setTouched } = fieldApi
|
|
const { value } = fieldState
|
|
const isValid = value && !fieldState.error
|
|
|
|
// Calculate the border color based on the current field state.
|
|
let borderColor
|
|
if (readOnly) {
|
|
borderColor = theme.colors.gray
|
|
} else if (fieldState.error) {
|
|
borderColor = theme.colors.superRed
|
|
} else if (value && !fieldState.error) {
|
|
borderColor = theme.colors.superGreen
|
|
}
|
|
|
|
return (
|
|
<Flex flexDirection="column" justifyContent={justifyContent}>
|
|
<SystemTextArea
|
|
borderColor={borderColor || theme.colors.gray}
|
|
opacity={readOnly ? 0.6 : null}
|
|
css={Object.assign(
|
|
{
|
|
outline: 'none',
|
|
'&:not([readOnly]):not([disabled]):focus': {
|
|
border: `1px solid ${
|
|
isValid ? theme.colors.superGreen : theme.colors.lightningOrange
|
|
} }`
|
|
}
|
|
},
|
|
css
|
|
)}
|
|
{...rest}
|
|
ref={this.inputRef}
|
|
value={!value && value !== 0 ? '' : value}
|
|
onChange={e => {
|
|
setValue(e.target.value)
|
|
if (onChange) {
|
|
onChange(e)
|
|
}
|
|
}}
|
|
onBlur={e => {
|
|
setTouched()
|
|
// Make the state aware that the element is now focused.
|
|
const newHasFocus = document.activeElement === this.inputRef.current
|
|
if (hasFocus !== newHasFocus) {
|
|
this.setState({ hasFocus: newHasFocus })
|
|
}
|
|
if (onBlur) {
|
|
onBlur(e)
|
|
}
|
|
}}
|
|
onFocus={e => {
|
|
// Make the state aware that the element is no longer focused.
|
|
const newHasFocus = document.activeElement === this.inputRef.current
|
|
if (hasFocus !== newHasFocus) {
|
|
this.setState({ hasFocus: newHasFocus })
|
|
}
|
|
if (onFocus) {
|
|
onFocus(e)
|
|
}
|
|
}}
|
|
error={fieldState.error}
|
|
/>
|
|
{fieldState.error && (
|
|
<Message variant={hasFocus ? 'warning' : 'error'} justifyContent={justifyContent} mt={2}>
|
|
{fieldState.error}
|
|
</Message>
|
|
)}
|
|
</Flex>
|
|
)
|
|
}
|
|
}
|
|
|
|
export default asField(withTheme(TextArea))
|
|
|