UNPKG

@spaced-out/ui-design-system

Version:
140 lines (128 loc) 3.57 kB
// @flow strict import * as React from 'react'; import {classify} from '../../utils/classify'; import {BodySmall, FormLabelSmall} from '../Text'; import css from './Textarea.module.css'; type ClassNames = $ReadOnly<{box?: string, textarea?: string}>; export type TextareaProps = { value?: string, onChange?: ( evt: SyntheticInputEvent<HTMLInputElement>, isEnter?: boolean, ) => mixed, onFocus?: (e: SyntheticInputEvent<HTMLInputElement>) => mixed, onBlur?: (e: SyntheticInputEvent<HTMLInputElement>) => mixed, onKeyDown?: (e: SyntheticKeyboardEvent<HTMLInputElement>) => mixed, name?: string, disabled?: boolean, placeholder?: string, locked?: boolean, error?: boolean, errorText?: string, label?: string | React.Node, helperText?: string | React.Node, classNames?: ClassNames, size?: 'medium' | 'small', required?: boolean, textCountLimit?: number, ... }; const Textarea_ = (props: TextareaProps, ref): React.Node => { const { value, onChange, onFocus, onBlur, name, disabled, placeholder, error, locked, errorText, label, helperText, classNames, size = 'medium', required, textCountLimit, ...textareaProps } = props; const [textCountError, setTextCountError] = React.useState(false); React.useEffect(() => { if (textCountLimit) { if (value && value.length > textCountLimit) { setTextCountError(true); } else { setTextCountError(false); } } }, [value]); const controlledTextareaFilled = value !== ''; return ( <div className={classify(css.wrapper, { [css.filled]: controlledTextareaFilled ?? false, [css.withError]: (error || textCountError) ?? false, })} > {Boolean(label) && ( <div className={css.info}> <div className={css.infoContent}> <FormLabelSmall color="secondary">{label ?? ''}</FormLabelSmall> &nbsp; {required && <FormLabelSmall color="danger">{'*'}</FormLabelSmall>} </div> <FormLabelSmall color={error || textCountError ? 'danger' : 'secondary'} > {!!textCountLimit && ((value && value.length) || 0) + '/' + textCountLimit} </FormLabelSmall> </div> )} <div className={classify( css.box, { [css.inputDisabled]: disabled ?? false, [css.medium]: size === 'medium', [css.small]: size === 'small', [css.locked]: locked, }, classNames?.box, )} > <textarea {...textareaProps} disabled={locked || disabled} name={name} ref={ref} placeholder={placeholder} value={value} onChange={onChange} onFocus={onFocus} onBlur={onBlur} className={classNames?.textarea} ></textarea> </div> {(Boolean(helperText) || error) && ( <div className={css.info}> <BodySmall color={ error && errorText ? 'danger' : disabled ? 'disabled' : 'secondary' } > {error && errorText ? errorText : helperText ?? ''} </BodySmall> </div> )} </div> ); }; export const Textarea = (React.forwardRef<TextareaProps, HTMLTextAreaElement>( Textarea_, ): React$AbstractComponent<TextareaProps, HTMLTextAreaElement>);