UNPKG

zent

Version:

一套前端设计语言和基于React的实现

237 lines (236 loc) 9.16 kB
import { __assign, __extends } from "tslib"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Component, createRef } from 'react'; import cx from 'classnames'; import identity from '../utils/identity'; import Pop from '../pop'; import { WindowResizeHandler } from '../utils/component/WindowResizeHandler'; import { getLineHeight } from '../utils/dom/getLineHeight'; import { containsEmoji } from '../utils/unicode/isEmoji'; import { containsCJK } from '../utils/unicode/isCJK'; var WORDBREAK_STYLES = { wordBreak: 'break-all', overflowWrap: 'break-word', }; var ClampLines = (function (_super) { __extends(ClampLines, _super); function ClampLines(props) { var _this = _super.call(this, props) || this; _this.element = null; _this.innerElement = createRef(); _this.resizeObserver = null; _this.containerWidth = NaN; _this.handleWindowResize = function () { _this.setState({ holdsFullText: false }, _this.clampLines); }; _this.handleContainerResize = function (entries) { var _a = entries[0], contentBoxSize = _a.contentBoxSize, contentRect = _a.contentRect; var width = NaN; if (contentBoxSize) { width = Array.isArray(contentBoxSize) ? contentBoxSize[0].inlineSize : contentBoxSize.inlineSize; } else { width = contentRect.width; } if (!Number.isNaN(_this.containerWidth) && width !== _this.containerWidth) { _this.setState({ holdsFullText: false }, _this.clampLines); } _this.containerWidth = width; }; _this.onContainerRefChange = function (node) { _this.element = node; _this.observe(node); }; _this.onNoClampContainerRefChange = function (node) { _this.observe(node); }; _this.state = { holdsFullText: false, textSuited: '', }; return _this; } ClampLines.prototype.componentDidUpdate = function (prevProps) { var _this = this; if (prevProps.text !== this.props.text || prevProps.mode !== this.props.mode || prevProps.lines !== this.props.lines) { this.setState({ holdsFullText: false }, function () { _this.clampLines(); }); } }; ClampLines.prototype.componentDidMount = function () { this.clampLines(); }; ClampLines.prototype.componentWillUnmount = function () { var observer = this.getResizeObserver(); if (observer) { observer.disconnect(); } }; ClampLines.prototype.getResizeObserver = function () { if (!this.resizeObserver && window.ResizeObserver) { this.resizeObserver = new window.ResizeObserver(this.handleContainerResize); } return this.resizeObserver; }; ClampLines.prototype.observe = function (node) { var observer = this.getResizeObserver(); if (!observer || !this.props.resizable) { return; } this.containerWidth = NaN; observer.disconnect(); if (node) { observer.observe(node); } }; ClampLines.prototype.clampLines = function () { if (!this.innerElement.current || !this.element) { return; } this.props.mode === 'performance' ? this._clampLinesFast() : this._clampLinesAccurate(); }; ClampLines.prototype._clampLinesFast = function () { var text = this.props.text; var lineHeight = inferContentLineHeight(this.element, text); var maxHeight = lineHeight * this.props.lines; this.innerElement.current.textContent = text; if (this.element.clientHeight <= maxHeight) { this.setState({ textSuited: text, holdsFullText: true, }); return; } var chars = Array.from(text); var start = 0; var middle = 0; var end = chars.length; while (start < end) { middle = Math.floor((start + end) / 2); this.innerElement.current.textContent = slice(chars, 0, middle) + this.getEllipsis(); var height = this.element.clientHeight; if (height > maxHeight) { end = middle; } else { start = middle + 1; } } var overflowIndex = end - 1; var textSuited = slice(chars, 0, overflowIndex) + this.getEllipsis(); this.innerElement.current.textContent = textSuited; this.setState({ textSuited: textSuited, holdsFullText: false, }); }; ClampLines.prototype._clampLinesAccurate = function () { var miniLineHeight = getLineHeight(this.element); var text = this.props.text; var chars = Array.from(text); var lines = this.props.lines; var prevIndex = 0; var prevStr = chars[prevIndex]; var textSuited = ''; this.innerElement.current.textContent = prevStr; var prevHeight = this.element.clientHeight; var i = 1; for (; i < chars.length && lines > 0; i++) { var str = prevStr + chars[i]; this.innerElement.current.textContent = str; var height = this.element.clientHeight; if (height - prevHeight >= miniLineHeight) { lines--; } if (lines > 0) { prevHeight = height; prevIndex = i; prevStr = str; } else { while (prevIndex) { prevStr = slice(chars, 0, prevIndex--); var str_1 = prevStr + this.getEllipsis(); this.innerElement.current.textContent = str_1; if (prevHeight === this.element.clientHeight) { textSuited = str_1; break; } } } } if (lines > 0) { this.setState({ textSuited: text, holdsFullText: true, }); } else { this.setState({ textSuited: textSuited, holdsFullText: false, }); } }; ClampLines.prototype.getEllipsis = function () { return !this.state.holdsFullText ? this.props.ellipsis : ''; }; ClampLines.prototype.renderResizable = function () { if (this.props.resizable && !window.ResizeObserver) { return _jsx(WindowResizeHandler, { onResize: this.handleWindowResize }, void 0); } return null; }; ClampLines.prototype.renderClampedText = function () { var className = this.props.className; var classString = cx('zent-clamp-lines', className); return (_jsxs("div", __assign({ className: classString, style: WORDBREAK_STYLES, "data-zv": '10.0.17' }, { children: [_jsxs("div", __assign({ ref: this.onContainerRefChange, "data-zv": '10.0.17' }, { children: [_jsx("span", __assign({ ref: this.innerElement, "data-zv": '10.0.17' }, { children: this.state.textSuited }), void 0), this.props.extra] }), void 0), this.renderResizable()] }), void 0)); }; ClampLines.prototype.render = function () { var _a = this.props, text = _a.text, className = _a.className, showPop = _a.showPop, popWidth = _a.popWidth, trigger = _a.trigger, renderPop = _a.renderPop; if (!text) { return null; } if (this.state.holdsFullText) { return (_jsxs("div", __assign({ ref: this.onNoClampContainerRefChange, className: className, style: WORDBREAK_STYLES, "data-zv": '10.0.17' }, { children: [text, this.renderResizable()] }), void 0)); } if (showPop) { return (_jsx(Pop, __assign({ trigger: trigger, content: _jsx("div", __assign({ style: __assign({ maxWidth: popWidth }, WORDBREAK_STYLES), "data-zv": '10.0.17' }, { children: renderPop(text) }), void 0) }, { children: this.renderClampedText() }), void 0)); } return this.renderClampedText(); }; ClampLines.defaultProps = { className: '', lines: 2, ellipsis: '...', showPop: true, popWidth: 250, trigger: 'hover', renderPop: identity, resizable: false, mode: 'performance', extra: null, }; return ClampLines; }(Component)); export { ClampLines }; function slice(chars, start, end) { return chars.slice(start, end).join(''); } function inferContentLineHeight(node, str) { var emojiHeight = containsEmoji(str) ? getLineHeight(node, '🇨🇳') : -Infinity; var cjkHeight = containsCJK(str) ? getLineHeight(node, '世界') : -Infinity; var asciiHeight = getLineHeight(node); return Math.max(emojiHeight, cjkHeight, asciiHeight); } export default ClampLines;