terra-clinical-item-display
Version:
The Item Display component creates an display for text and an optional graphic. The Comment subcomponent creates a display for text with a comment icon.
146 lines (134 loc) • 4.66 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import classNamesBind from 'classnames/bind';
import ThemeContext from 'terra-theme-context';
import VisuallyHiddenText from 'terra-visually-hidden-text';
import { injectIntl } from 'react-intl';
import styles from './ItemDisplay.module.scss';
const cx = classNamesBind.bind(styles);
const TextStyles = {
PRIMARY: 'primary',
SECONDARY: 'secondary',
ATTENTION: 'attention',
STRIKETHROUGH: 'strikeThrough',
STRONG: 'strong',
};
const propTypes = {
/**
* The text to be displayed for the comment.
*/
text: PropTypes.string,
/**
* The visual style to be applied to the display element.
* One of `'primary'`, `'secondary'`, `'strong'`, `'attention'`, or `'strikeThrough'`.
*/
textStyle: PropTypes.oneOf(Object.values(TextStyles)),
/**
* Whether or not the text should be truncated. Note: To ensure keyboard accessibility, if this prop
* is used, consumers will need to provide a method to disclose the rest of the text so that it is
* accessible to keyboard users.
*/
isTruncated: PropTypes.bool,
// TODO: remove isDisabled in the next major release.
/**
* (Deprecated) Whether or not the display is disabled.
*/
isDisabled: PropTypes.bool,
/**
* The icon react element to be displayed next to the display text.
*/
icon: PropTypes.element,
/**
* The position of the icon to be displayed next to the text,
* noticeable when the text display wraps multiple line.
* One of `'center'`, `'top'`, `'inline'`.
*/
iconAlignment: PropTypes.oneOf(['center', 'top', 'inline']),
/**
* 
* The meaning of the text styling, for use by screen readers.
* Changing `textStyleMeaning` will not visually change the style of the content.
* Defaults to "deletion" for `textStyle` of `'strikeThrough'`.
*/
textStyleMeaning: PropTypes.string,
/**
* @private
* The intl object containing translations. This is retrieved from the context automatically by injectIntl.
*/
intl: PropTypes.shape({ formatMessage: PropTypes.func }).isRequired,
};
const defaultProps = {
text: '',
textStyle: 'primary',
isTruncated: false,
isDisabled: false,
icon: undefined,
iconAlignment: 'center',
};
const ItemDisplay = ({
text,
textStyle,
isTruncated,
isDisabled,
icon,
iconAlignment,
textStyleMeaning,
intl,
...customProps
}) => {
const theme = React.useContext(ThemeContext);
const componentClassNames = classNames(
cx(
'item-display',
{ 'is-disabled': isDisabled },
{ [`icon-${iconAlignment}`]: icon },
theme.className,
),
customProps.className,
);
const textClassNames = cx([
'text',
{ 'is-truncated': isTruncated },
{ [`${textStyle}`]: textStyle === TextStyles.SECONDARY },
{ [`${textStyle}`]: textStyle === TextStyles.ATTENTION },
{ [`${textStyle}`]: textStyle === TextStyles.STRONG },
{ 'strike-through': textStyle === TextStyles.STRIKETHROUGH },
]);
// TODO: remove this warning in the next major release.
if (isDisabled) {
// eslint-disable-next-line no-console
console.warn('The isDisabled prop does not meet a11y standards and should not be used. It will be removed in the next major release.');
}
let displayIcon;
if (icon) {
displayIcon = <div className={cx('icon')}>{icon}</div>;
}
let textWrapper = <span>{text}</span>;
if (textStyle === TextStyles.STRONG) {
textWrapper = <strong>{text}</strong>;
}
let hiddenStyleMeaning;
let hiddenStyleMeaningEnd;
if (textStyleMeaning) {
hiddenStyleMeaning = textStyleMeaning;
hiddenStyleMeaningEnd = intl.formatMessage({ id: 'Terra.itemDisplay.textStyleMeaningEnd' }, { textStyleMeaning });
} else if (textStyle === TextStyles.STRIKETHROUGH) {
hiddenStyleMeaning = intl.formatMessage({ id: 'Terra.itemDisplay.textStyleMeaningStrikethrough' });
hiddenStyleMeaningEnd = intl.formatMessage({ id: 'Terra.itemDisplay.textStyleMeaningStrikethroughEnd' });
}
return (
<div {...customProps} className={componentClassNames} aria-disabled={isDisabled}>
{displayIcon}
{hiddenStyleMeaning && <VisuallyHiddenText text={hiddenStyleMeaning} />}
<div data-terra-clinical-item-display-text className={textClassNames}>
{textWrapper}
</div>
{hiddenStyleMeaningEnd && <VisuallyHiddenText text={hiddenStyleMeaningEnd} />}
</div>
);
};
ItemDisplay.propTypes = propTypes;
ItemDisplay.defaultProps = defaultProps;
export default injectIntl(ItemDisplay);
export { TextStyles };