@react-ui-org/react-ui
Version:
React UI is a themeable UI library for React apps.
168 lines (160 loc) • 4.52 kB
JSX
import PropTypes from 'prop-types';
import React, { useContext } from 'react';
import { withGlobalProps } from '../../providers/globalProps';
import { classNames } from '../../helpers/classNames/classNames';
import { transferProps } from '../../helpers/transferProps';
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
import { FormLayoutContext } from '../FormLayout';
import styles from './TextArea.module.scss';
export const TextArea = React.forwardRef((props, ref) => {
const {
disabled,
fullWidth,
helpText,
id,
isLabelVisible,
label,
layout,
required,
size,
validationState,
validationText,
variant,
...restProps
} = props;
const context = useContext(FormLayoutContext);
return (
<label
className={classNames(
styles.root,
fullWidth && styles.isRootFullWidth,
context && styles.isRootInFormLayout,
resolveContextOrProp(context && context.layout, layout) === 'horizontal'
? styles.isRootLayoutHorizontal
: styles.isRootLayoutVertical,
disabled && styles.isRootDisabled,
required && styles.isRootRequired,
getRootSizeClassName(size, styles),
getRootValidationStateClassName(validationState, styles),
variant === 'filled' ? styles.isRootVariantFilled : styles.isRootVariantOutline,
)}
htmlFor={id}
id={id && `${id}__label`}
>
<div
className={classNames(
styles.label,
!isLabelVisible && styles.isLabelHidden,
)}
id={id && `${id}__labelText`}
>
{label}
</div>
<div className={styles.field}>
<div className={styles.inputContainer}>
<textarea
{...transferProps(restProps)}
className={styles.input}
disabled={disabled}
id={id}
ref={ref}
required={required}
/>
{variant === 'filled' && (
<div className={styles.bottomLine} />
)}
</div>
{helpText && (
<div
className={styles.helpText}
id={id && `${id}__helpText`}
>
{helpText}
</div>
)}
{validationText && (
<div
className={styles.validationText}
id={id && `${id}__validationText`}
>
{validationText}
</div>
)}
</div>
</label>
);
});
TextArea.defaultProps = {
disabled: false,
fullWidth: false,
helpText: null,
id: undefined,
isLabelVisible: true,
layout: 'vertical',
required: false,
size: 'medium',
validationState: null,
validationText: null,
variant: 'outline',
};
TextArea.propTypes = {
/**
* If `true`, the input will be disabled.
*/
disabled: PropTypes.bool,
/**
* If `true`, the field will span the full width of its parent.
*/
fullWidth: PropTypes.bool,
/**
* Optional help text.
*/
helpText: PropTypes.node,
/** ID of the input HTML element. It also serves as a prefix for nested elements:
* * `<ID>__label`
* * `<ID>__labelText`
* * `<ID>__helpText`
* * `<ID>__validationText`
*/
id: PropTypes.string,
/**
* If `false`, the label will be visually hidden (but remains accessible by assistive
* technologies).
*/
isLabelVisible: PropTypes.bool,
/**
* Text field label.
*/
label: PropTypes.node.isRequired,
/**
* Layout of the field.
*
* Ignored if the component is rendered within `FormLayout` component
* as the value is inherited in such case.
*/
layout: PropTypes.oneOf(['horizontal', 'vertical']),
/**
* If `true`, the input will be required.
*/
required: PropTypes.bool,
/**
* Size of the field.
*/
size: PropTypes.oneOf(['small', 'medium', 'large']),
/**
* Alter the field to provide feedback based on validation result.
*/
validationState: PropTypes.oneOf(['invalid', 'valid', 'warning']),
/**
* Validation message to be displayed.
*/
validationText: PropTypes.node,
/**
* Design variant of the field, further customizable with CSS custom properties.
*/
variant: PropTypes.oneOf(['filled', 'outline']),
};
export const TextAreaWithGlobalProps = withGlobalProps(TextArea, 'TextArea');
export default TextAreaWithGlobalProps;