@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
85 lines (84 loc) • 3.81 kB
JavaScript
'use client';
import LinkAccessibleRole from '@ui5/webcomponents/dist/types/LinkAccessibleRole.js';
import { useI18nBundle, useStylesheet } from '@ui5/webcomponents-react-base';
import { clsx } from 'clsx';
import { forwardRef, useId, useState } from 'react';
import { CLOSE_POPOVER, SHOW_FULL_TEXT, SHOW_LESS, SHOW_MORE } from '../../i18n/i18n-defaults.js';
import { Link } from '../../webComponents/index.js';
import { ResponsivePopover } from '../../webComponents/ResponsivePopover/index.js';
import { Text } from '../../webComponents/Text/index.js';
import { classNames, styleData } from './ExpandableText.module.css.js';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
/**
* The `ExpandableText` component can be used to display long texts inside a table, list or form.
*
* Initially, only the first characters from the text are shown with a "Show More" link which allows the full text to be displayed. The `showOverflowInPopover` property determines if the full text will be displayed expanded in place (default) or in a popover (`showOverflowInPopover: true`). If the text is expanded a "Show Less" link is displayed, which allows collapsing the text field.
*
* @since 1.23.0
*/
const ExpandableText = /*#__PURE__*/forwardRef((props, ref) => {
const {
children,
showOverflowInPopover,
maxCharacters = 100,
renderWhitespace,
className,
...rest
} = props;
useStylesheet(styleData, ExpandableText.displayName);
const [collapsed, setCollapsed] = useState(true);
const [popoverOpen, setPopoverOpen] = useState(false);
const uniqueId = useId();
const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
const trimmedChildren = renderWhitespace ? children : children?.replace(/\s+/g, ' ').trim();
const isOverflow = trimmedChildren?.length >= maxCharacters;
const strippedChildren = isOverflow && (collapsed || showOverflowInPopover) ? trimmedChildren?.slice(0, maxCharacters) : children;
const handleClick = () => {
if (showOverflowInPopover) {
setPopoverOpen(prev => !prev);
}
setCollapsed(prev => !prev);
};
const closePopover = () => {
setCollapsed(true);
setPopoverOpen(false);
};
return /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsxs("span", {
className: clsx(classNames.expandableText, className),
...rest,
ref: ref,
children: [/*#__PURE__*/_jsx(Text, {
className: clsx(classNames.text, renderWhitespace && classNames.renderWhitespace),
children: strippedChildren
}), isOverflow && /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsx("span", {
className: classNames.ellipsis,
children: showOverflowInPopover || collapsed ? '… ' : ' '
}), /*#__PURE__*/_jsx(Link, {
accessibleName: showOverflowInPopover ? collapsed ? i18nBundle.getText(SHOW_FULL_TEXT) : i18nBundle.getText(CLOSE_POPOVER) : undefined,
accessibleRole: LinkAccessibleRole.Button,
accessibilityAttributes: showOverflowInPopover ? {
hasPopup: 'dialog'
} : {
expanded: !collapsed
},
onClick: handleClick,
id: `${uniqueId}-link`,
children: collapsed ? i18nBundle.getText(SHOW_MORE) : i18nBundle.getText(SHOW_LESS)
})]
})]
}), showOverflowInPopover && popoverOpen && /*#__PURE__*/_jsx(ResponsivePopover, {
opener: `${uniqueId}-link`,
open: true,
onClose: closePopover,
className: classNames.popover,
children: /*#__PURE__*/_jsx(Text, {
className: clsx(classNames.text, renderWhitespace && classNames.renderWhitespace),
children: children
})
})]
});
});
ExpandableText.displayName = 'ExpandableText';
export { ExpandableText };