UNPKG

@carbon/ibm-products

Version:

Carbon for IBM Products

118 lines (113 loc) 4.66 kB
/** * Copyright IBM Corp. 2020, 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js'; import React__default, { useRef, useState } from 'react'; import PropTypes from '../../_virtual/index.js'; import cx from 'classnames'; import { getDevtoolsProps } from '../../global/js/utils/devtools.js'; import { pkg } from '../../settings.js'; import { DefinitionTooltip } from '@carbon/react'; import { StringFormatterAlignment, propMappingFunction, deprecated_StringFormatterAlignment } from './utils/enums.js'; import { allPropTypes } from '../../global/js/utils/props-helper.js'; import { useIsomorphicEffect } from '../../global/js/hooks/useIsomorphicEffect.js'; const blockClass = `${pkg.prefix}--string-formatter`; const componentName = 'StringFormatter'; const defaults = { lines: 1, tooltipDirection: StringFormatterAlignment.BOTTOM_START, truncate: false, width: null }; /** * StringFormatter allows for truncating text while displaying a tooltip * overlay on hover or focus with the entirety of the provided copy. */ let StringFormatter = /*#__PURE__*/React__default.forwardRef((_ref, ref) => { let { className, lines = defaults.lines, tooltipDirection = defaults.tooltipDirection, truncate = defaults.truncate, width = defaults.width, value, ...rest } = _ref; const outerRef = useRef(null); const contentRef = useRef(null); const [isTextTruncated, setIsTextTruncated] = useState(false); const mergedRefs = node => { outerRef.current = node; if (typeof ref === 'function') { ref(node); } else if (ref) { ref.current = node; } }; useIsomorphicEffect(() => { const checkTruncation = () => { const element = contentRef.current; if (element) { element.style.webkitLineClamp = truncate ? lines : undefined; element.style.maxWidth = width; const buffer = element.clientHeight / (2 * lines); // add a buffer of at least half of line height/clientHeight. to get a stable outcome. const isOverflowing = element.scrollHeight > element.clientHeight + buffer; setIsTextTruncated(isOverflowing); } }; const resizeObserver = new ResizeObserver(checkTruncation); if (outerRef.current) { resizeObserver.observe(outerRef.current); checkTruncation(); } return () => { resizeObserver.disconnect(); }; }, [lines, value, width, truncate]); const stringFormatterContent = /*#__PURE__*/React__default.createElement("span", { ref: contentRef, className: cx(`${blockClass}--content`, { [`${blockClass}--truncate`]: truncate }) }, value); return /*#__PURE__*/React__default.createElement("span", _extends({}, rest, { className: cx(blockClass, className), ref: mergedRefs }, getDevtoolsProps(componentName)), truncate && isTextTruncated ? /*#__PURE__*/React__default.createElement(DefinitionTooltip, { className: `${blockClass}__tooltip`, align: tooltipDirection, definition: value, openOnHover: true }, stringFormatterContent) : stringFormatterContent); }); StringFormatter = pkg.checkComponentEnabled(StringFormatter, componentName); StringFormatter.displayName = componentName; StringFormatter.validateAlignment = () => (props, propName, componentName) => { const prop = props[propName]; const deprecatedAlignValues = Object.values(deprecated_StringFormatterAlignment); if (deprecatedAlignValues.includes(prop)) { const mappedNewProp = propMappingFunction(prop); console.warn(`"${prop}" is a deprecated value for the "${propName}" prop on the "${componentName}" component. Use "${mappedNewProp}" instead. Allowable values are: ${Object.values(StringFormatterAlignment).join(', ')}.`); } }; StringFormatter.propTypes = { /** * Provide an optional class to be applied to the containing node. */ className: PropTypes.string, /** Number of lines to clamp value. */ lines: PropTypes.number, /** Specify the direction of the tooltip. Can be either top or bottom. */ tooltipDirection: allPropTypes([StringFormatter.validateAlignment(), PropTypes.oneOf(Object.values(deprecated_StringFormatterAlignment), Object.values(StringFormatterAlignment))]), /** Whether or not the value should be truncated. if it exceeds lines. */ truncate: PropTypes.bool, /** Value to format. */ value: PropTypes.string.isRequired, /** Maximum width of value which should include */ width: PropTypes.string }; export { StringFormatter };