UNPKG

@fluentui/react

Version:

Reusable React components for building web experiences.

176 lines 8.71 kB
import { __extends } from "tslib"; import * as React from 'react'; import { Async, EventGroup, classNamesFunction } from '../../Utilities'; import { initializeComponentRef } from '@fluentui/utilities'; import { DocumentCardContext } from './DocumentCard.base'; import { WindowContext } from '@fluentui/react-window-provider'; import { getWindowEx } from '../../utilities/dom'; var getClassNames = classNamesFunction(); var TRUNCATION_VERTICAL_OVERFLOW_THRESHOLD = 5; /** * {@docCategory DocumentCard} */ export var DocumentCardTitleBase = /** @class */ (function (_super) { __extends(DocumentCardTitleBase, _super); function DocumentCardTitleBase(props) { var _this = _super.call(this, props) || this; _this._titleElement = React.createRef(); // Truncate logic here way can't handle the case that chars with different widths are mixed very well. // Let _shrinkTitle take care of that. _this._truncateTitle = function () { if (!_this._needMeasurement) { return; } _this._async.requestAnimationFrame(_this._truncateWhenInAnimation); }; _this._truncateWhenInAnimation = function () { var originalTitle = _this.props.title; var element = _this._titleElement.current; if (element) { var style = getComputedStyle(element); if (style.width && style.lineHeight && style.height) { var clientWidth = element.clientWidth, scrollWidth = element.scrollWidth; _this._clientWidth = clientWidth; var lines = Math.floor((parseInt(style.height, 10) + TRUNCATION_VERTICAL_OVERFLOW_THRESHOLD) / parseInt(style.lineHeight, 10)); element.style.whiteSpace = ''; // Use overflow to predict truncated length. // Take an example.The text is: A text with A very long text that need to be truncated.ppt // if container is like // |A text with A very| long text that need to be truncated.ppt // The scroll width is 58, (take two | out of length) // The client width is 18 // the overflow rate is scrollWidth/clientWidth which should be close to length(overflowText)/length(visualText) // And the length of remaining text should be truncated is (original Length)/(58/18) -3 = 15. // So that the logic can predict truncated text well. // first piece will be `A text `, * second piece will be `ated.ppt` // |A text ...ated.ppt| var overFlowRate = scrollWidth / (parseInt(style.width, 10) * lines); if (overFlowRate > 1) { var truncatedLength = originalTitle.length / overFlowRate - 3; /** Saved for separator */ return _this.setState({ truncatedTitleFirstPiece: originalTitle.slice(0, truncatedLength / 2), truncatedTitleSecondPiece: originalTitle.slice(originalTitle.length - truncatedLength / 2), }); } } } }; _this._shrinkTitle = function () { var _a; var truncatedTitleFirstPiece = (_a = _this.state, _a.truncatedTitleFirstPiece), truncatedTitleSecondPiece = _a.truncatedTitleSecondPiece; if (truncatedTitleFirstPiece && truncatedTitleSecondPiece) { var titleElement = _this._titleElement.current; if (!titleElement) { return; } if (titleElement.scrollHeight > titleElement.clientHeight + TRUNCATION_VERTICAL_OVERFLOW_THRESHOLD || titleElement.scrollWidth > titleElement.clientWidth) { _this.setState({ truncatedTitleFirstPiece: truncatedTitleFirstPiece.slice(0, truncatedTitleFirstPiece.length - 1), truncatedTitleSecondPiece: truncatedTitleSecondPiece.slice(1), }); } } }; initializeComponentRef(_this); _this._async = new Async(_this); _this._events = new EventGroup(_this); _this._clientWidth = undefined; _this.state = { truncatedTitleFirstPiece: undefined, truncatedTitleSecondPiece: undefined, }; return _this; } DocumentCardTitleBase.prototype.componentDidUpdate = function (prevProps) { var _this = this; if (this.props.title !== prevProps.title) { this.setState({ truncatedTitleFirstPiece: undefined, truncatedTitleSecondPiece: undefined, }); } if (prevProps.shouldTruncate !== this.props.shouldTruncate) { var win = getWindowEx(this.context); if (this.props.shouldTruncate) { this._truncateTitle(); this._async.requestAnimationFrame(this._shrinkTitle); this._events.on(win, 'resize', this._updateTruncation); } else { this._events.off(win, 'resize', this._updateTruncation); } } else if (this._needMeasurement) { this._async.requestAnimationFrame(function () { _this._truncateWhenInAnimation(); _this._shrinkTitle(); }); } }; DocumentCardTitleBase.prototype.componentDidMount = function () { if (this.props.shouldTruncate) { this._truncateTitle(); var win = getWindowEx(this.context); this._events.on(win, 'resize', this._updateTruncation); } }; DocumentCardTitleBase.prototype.componentWillUnmount = function () { this._events.dispose(); this._async.dispose(); }; DocumentCardTitleBase.prototype.render = function () { var _a, _b; var _this = this; var title = (_a = this.props, _a.title), shouldTruncate = _a.shouldTruncate, showAsSecondaryTitle = _a.showAsSecondaryTitle, styles = _a.styles, theme = _a.theme, className = _a.className; var truncatedTitleFirstPiece = (_b = this.state, _b.truncatedTitleFirstPiece), truncatedTitleSecondPiece = _b.truncatedTitleSecondPiece; this._classNames = getClassNames(styles, { theme: theme, className: className, showAsSecondaryTitle: showAsSecondaryTitle, }); if (shouldTruncate && truncatedTitleFirstPiece && truncatedTitleSecondPiece) { return (React.createElement(DocumentCardContext.Consumer, null, function (_a) { var role = _a.role, tabIndex = _a.tabIndex; return (React.createElement("div", { className: _this._classNames.root, ref: _this._titleElement, title: title, tabIndex: tabIndex, role: role }, truncatedTitleFirstPiece, "\u2026", truncatedTitleSecondPiece)); })); } else { return (React.createElement(DocumentCardContext.Consumer, null, function (_a) { var role = _a.role, tabIndex = _a.tabIndex; return (React.createElement("div", { className: _this._classNames.root, ref: _this._titleElement, title: title, tabIndex: tabIndex, role: role, style: _this._needMeasurement ? { whiteSpace: 'nowrap' } : undefined }, title)); })); } }; Object.defineProperty(DocumentCardTitleBase.prototype, "_needMeasurement", { /** * In measuring, it will render a same style text with whiteSpace: 'nowrap', to get overflow rate. * So that the logic can predict truncated text well. */ get: function () { return !!this.props.shouldTruncate && this._clientWidth === undefined; }, enumerable: false, configurable: true }); DocumentCardTitleBase.prototype._updateTruncation = function () { var _this = this; if (this._timerId) { return; } this._timerId = this._async.setTimeout(function () { delete _this._timerId; _this._clientWidth = undefined; _this.setState({ truncatedTitleFirstPiece: undefined, truncatedTitleSecondPiece: undefined, }); }, 250); }; DocumentCardTitleBase.contextType = WindowContext; return DocumentCardTitleBase; }(React.Component)); //# sourceMappingURL=DocumentCardTitle.base.js.map