import { useLayoutEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import { Typography } from 'antd' import Tooltip from './Tooltip' const { Text } = Typography const childrenToString = (children) => { if (children == null || typeof children === 'boolean') return '' if (typeof children === 'string' || typeof children === 'number') { return String(children) } if (Array.isArray(children)) { return children.map(childrenToString).join('') } if (typeof children === 'object' && children.props) { return childrenToString(children.props.children) } return '' } const splitMiddle = (text) => { const mid = Math.ceil(text.length / 2) return { start: text.slice(0, mid), end: text.slice(mid) } } const ElipsisText = ({ children, style, className, title, code, ...rest }) => { const text = childrenToString(children) const { start, end } = splitMiddle(text) const containerRef = useRef(null) const measureRef = useRef(null) const truncatedRef = useRef(false) const [truncated, setTruncated] = useState(false) useLayoutEffect(() => { const container = containerRef.current const measure = measureRef.current if (!container || !measure) return const update = () => { const available = container.getBoundingClientRect().width if (available < 1) return const textWidth = measure.getBoundingClientRect().width const next = Boolean(end) && textWidth > available if (truncatedRef.current === next) return truncatedRef.current = next setTruncated(next) } update() const frame = requestAnimationFrame(update) const resizeObserver = new ResizeObserver(update) resizeObserver.observe(container) const intersectionObserver = new IntersectionObserver(update) intersectionObserver.observe(container) return () => { cancelAnimationFrame(frame) resizeObserver.disconnect() intersectionObserver.disconnect() } }, [text, end]) const showTruncated = truncated && Boolean(end) const RootTag = code ? 'code' : 'span' const content = ( {text} {text} {start} ... {end} ) return ( {truncated ? {content} : content} ) } ElipsisText.propTypes = { children: PropTypes.node, style: PropTypes.object, className: PropTypes.string, title: PropTypes.string, code: PropTypes.bool } export default ElipsisText