/* eslint-disable no-nested-ternary */ import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState, } from 'react'; import styled, { css } from 'styled-components'; import { position, size, space, width as styledWidth, WidthProps, } from 'styled-system'; import { MaterialClear } from '@t3n/icons'; import { getThemeColor, ThemeProps } from '@t3n/theme'; import Icon from '../Icon'; import Text from '../Text'; export interface TextareaProps extends Omit< React.TextareaHTMLAttributes, 'width' | 'value' >, WidthProps { onReset?: () => void; isFocused?: boolean; defaultValue?: string; error?: boolean; className?: string; } interface StyledNativeTextareaProps extends TextareaProps { isFocused: boolean; } const color = css` color: ${({ isFocused, error, disabled, theme, }: TextareaProps & ThemeProps) => error ? theme.colors.feedback.error : disabled ? theme.colors.shades.grey204 : isFocused ? theme.colors.shades.grey42 : theme.colors.shades.grey95}; `; const StyledTextarea = styled.div` position: relative; display: flex; align-items: center; ${styledWidth} ${color} `; const padding = ({ theme }: ThemeProps) => space({ pl: 2, pr: 6, pt: 1, pb: 1, theme }); const border = css` border: 1px solid ${({ isFocused, error, disabled, theme, }: StyledNativeTextareaProps & ThemeProps) => error ? theme.colors.feedback.error : disabled ? theme.colors.shades.grey204 : isFocused ? theme.colors.shades.grey42 : theme.colors.shades.grey95}; `; const StyledNativeTextarea = styled.textarea.attrs(() => ({ noValidate: true, }))` width: 100%; min-height: ${({ rows }: StyledNativeTextareaProps) => rows ? `${rows * 30}px` : '120px'}; font-family: ${({ theme }) => theme.fonts.default}; font-size: 1rem; line-height: 30px; color: ${getThemeColor('text.primary')}; background-color: ${getThemeColor('background.primary')}; border-radius: ${(props) => props.theme.border.radii[1]}; outline: 0; ${border} ${padding} -webkit-appearance: none; -moz-appearance: none; appearance: none; resize: vertical; ::placeholder, :disabled { opacity: 0.6; } &::-ms-clear { display: none; } `; const StyledText = styled(Text)` position: absolute; font-size: 0.7rem; top: calc(100% - 6px); right: 0; `; const Button = styled.button.attrs(() => ({ type: 'button', }))` position: absolute; padding: 0; margin-top: 0.4rem; background: transparent; border: none; outline: 0; ${({ theme }) => size({ theme, width: 3, height: 3 })} ${({ theme }) => position({ theme, top: 0, right: 1 })} &:hover { cursor: pointer; } `; const Textarea = forwardRef( ( { disabled, error, width = '100%', rows, className, onFocus, onBlur, onChange, onReset, isFocused = false, defaultValue, maxLength, ...props }: TextareaProps, ref: React.Ref, ) => { const textareaRef = useRef(null); const [value, setValue] = useState(defaultValue || ''); const [focused, setFocused] = useState(isFocused || false); useImperativeHandle(ref, () => textareaRef.current); const handleFocus = (e: React.FocusEvent) => { e.stopPropagation(); setFocused(true); if (onFocus) onFocus(e); }; const handleBlur = (e: React.FocusEvent) => { e.stopPropagation(); setFocused(false); if (onBlur) onBlur(e); }; const handleOnChange = (e: React.ChangeEvent) => { e.stopPropagation(); setValue(e.target.value); if (onChange) onChange(e); }; const handleReset = () => { setValue(''); if (textareaRef !== null && textareaRef.current !== null) { textareaRef.current.focus(); } if (onReset) onReset(); }; useEffect(() => { if (focused && textareaRef !== null && textareaRef.current !== null) { textareaRef.current.focus(); textareaRef.current.selectionStart = textareaRef.current.value.length; } }, [focused]); return ( {value.length > 0 && !disabled ? ( ) : null} {typeof maxLength !== 'undefined' && maxLength >= 1 && ( {value.length} / {maxLength} )} ); }, ); export default Textarea;