wix-style-react
Version:
wix-style-react
298 lines (296 loc) • 9.71 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _debounce = _interopRequireDefault(require("lodash/debounce"));
var _shallowequal = _interopRequireDefault(require("shallowequal"));
var _EllipsisSt = require("./Ellipsis.st.css");
var _Tooltip = _interopRequireDefault(require("../../Tooltip"));
var _ZIndex = require("../../ZIndex");
var _TooltipCommon = require("../PropTypes/TooltipCommon");
var _jsxFileName = "/home/builduser/work/a9c1ac8876d5057c/packages/wix-style-react/dist/cjs/common/Ellipsis/Ellipsis.js";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var isTestEnv = process.env.NODE_ENV === 'test';
class TextComponent extends _react.default.PureComponent {
constructor() {
super(...arguments);
this.requestedRecalculationMount = null;
this.requestedRecalculationUpdate = [];
this._getEllipsisClasses = () => {
var {
ellipsis,
maxLines
} = this.props;
var ellipsisLines = maxLines > 1 ? 'multiline' : 'singleLine';
return className => ellipsis ? (0, _EllipsisSt.st)(_EllipsisSt.classes.text, {
ellipsisLines
}, className) : className;
};
}
componentDidMount() {
if (!this.props.textRendered) {
/**
* The requestAnimationFrame implementation is meant for browser only race condition bug fix.
* It does not get reproduced in test environment due JSDOM being not a browser.
* So we skip the requestAnimationFrame part in order not to have delays in calculations.
*/
if (isTestEnv) {
return this.props.onTextRendered();
}
this.requestedRecalculationMount = requestAnimationFrame(() => {
this.props.onTextRendered();
});
}
}
componentDidUpdate() {
if (!this.props.textRendered) {
/**
* The requestAnimationFrame implementation is meant for browser only race condition bug fix.
* It does not get reproduced in test environment due JSDOM being not a browser.
* So we skip the requestAnimationFrame part in order not to have delays in calculations.
*/
if (isTestEnv) {
return this.props.onTextRendered();
}
this.requestedRecalculationUpdate.push(requestAnimationFrame(() => {
this.props.onTextRendered();
}));
}
}
componentWillUnmount() {
if (this.requestedRecalculationMount) {
cancelAnimationFrame(this.requestedRecalculationMount);
}
if (this.requestedRecalculationUpdate.length !== 0) {
this.requestedRecalculationUpdate.forEach(id => cancelAnimationFrame(id));
}
}
render() {
var {
render,
maxLines,
textElementRef
} = this.props;
return render({
ref: textElementRef,
ellipsisClasses: this._getEllipsisClasses(),
ellipsisInlineStyle: {
[_EllipsisSt.vars.maxLines]: maxLines
}
});
}
}
class Ellipsis extends _react.default.PureComponent {
constructor(props) {
super(props);
/**
* Once text component has rendered,
* Update text content and tooltip active state
* @private
*/
this._onTextRendered = () => {
var {
isActive,
textContent
} = this.state;
var newState = {
textRendered: true
};
var newTextContent = this._getTextContent();
if (newTextContent !== textContent) {
newState.textContent = newTextContent;
}
var shouldBeActive = this._checkShouldBeActive();
if (shouldBeActive !== isActive) {
newState.isActive = shouldBeActive;
}
this.setState(newState);
};
/**
* An ellipsis is considered active when either the text's scroll width/height is wider than it's container or itself.
* @private
*/
this._updateIsActive = () => {
var {
isActive
} = this.state;
var shouldBeActive = this._checkShouldBeActive();
if (shouldBeActive !== isActive) {
this.setState({
isActive: shouldBeActive
});
}
};
this._getTextContent = () => {
var {
current: textElement
} = this.ref;
return textElement && textElement.textContent;
};
this._checkShouldBeActive = () => this._isOverflowingHorizontally() || this._isOverflowingVertically();
this._isOverflowingHorizontally = () => {
var {
current: textElement
} = this.ref;
var {
ellipsis
} = this.props;
return ellipsis && textElement && (textElement.scrollWidth - textElement.parentNode.offsetWidth > 1 || textElement.offsetWidth < textElement.scrollWidth);
};
this._isOverflowingVertically = () => {
var {
current: textElement
} = this.ref;
var {
ellipsis,
maxLines
} = this.props;
return maxLines > 1 && ellipsis && textElement && (textElement.scrollHeight - textElement.parentNode.offsetHeight > 1 || textElement.offsetHeight < textElement.scrollHeight);
};
/**
* A callback for resizing the window, must be debounced in order to improve performance.
* @private
*/
this._debouncedUpdate = (0, _debounce.default)(this._updateIsActive, 100);
this.state = {
isActive: false,
textContent: null,
textRendered: false
};
this.ref = /*#__PURE__*/_react.default.createRef();
}
componentDidMount() {
window.addEventListener('resize', this._debouncedUpdate);
}
_renderText() {
var {
render,
ellipsis,
maxLines
} = this.props;
var {
textRendered
} = this.state;
return /*#__PURE__*/_react.default.createElement(TextComponent, {
render,
ellipsis,
maxLines,
textRendered,
onTextRendered: this._onTextRendered,
textElementRef: this.ref,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 204,
columnNumber: 7
}
});
}
render() {
var {
appendTo,
wrapperClassName,
disabled,
enterDelay,
exitDelay,
fixed,
flip,
maxWidth,
moveArrowTo,
onHide,
onShow,
placement,
showTooltip,
textAlign,
zIndex,
size
} = this.props;
var {
isActive,
textContent
} = this.state;
return showTooltip && isActive ? /*#__PURE__*/_react.default.createElement(_Tooltip.default, {
className: (0, _EllipsisSt.st)(_EllipsisSt.classes.tooltip, wrapperClassName),
content: textContent,
appendTo,
disabled,
enterDelay,
exitDelay,
fixed,
flip,
maxWidth,
moveArrowTo,
onHide,
onShow,
placement,
textAlign,
zIndex,
size,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 234,
columnNumber: 7
}
}, this._renderText()) : this._renderText();
}
static getDerivedStateFromProps(props, state) {
var {
render,
ellipsis,
maxLines
} = props;
var textPropsChanged = state.prevRender !== render || state.prevEllipsis !== ellipsis || state.prevMaxLines !== maxLines;
if (!textPropsChanged) {
return null;
}
// Text changed, initialize textRendered state
return {
textRendered: false,
prevRender: render,
prevEllipsis: ellipsis,
prevMaxLines: maxLines
};
}
componentDidUpdate(prevProps) {
var {
textRendered
} = this.state;
if (textRendered && !(0, _shallowequal.default)(prevProps, this.props)) {
this._updateIsActive();
}
}
componentWillUnmount() {
this._debouncedUpdate.cancel();
window.removeEventListener('resize', this._debouncedUpdate);
}
}
Ellipsis.propTypes = _objectSpread({
/** When true, text that is longer than it's container will be truncated to a single line followed by ellipsis. Otherwise the text will break into several lines. */
ellipsis: _propTypes.default.bool,
/** True by default, set it to false in order to show ellipsis without a tooltip. */
showTooltip: _propTypes.default.bool,
/** A className to be applied to the Ellipsis wrapper. */
wrapperClassName: _propTypes.default.string,
/** The render function, use it to render a text you want to truncate with ellipsis. */
render: _propTypes.default.func,
/** maxLines truncates text at a specific number of lines. */
maxLines: _propTypes.default.number
}, _TooltipCommon.TooltipCommonProps);
Ellipsis.defaultProps = {
ellipsis: false,
appendTo: 'window',
flip: false,
fixed: false,
placement: 'top',
zIndex: (0, _ZIndex.ZIndex)('Tooltip'),
enterDelay: 0,
exitDelay: 0,
showTooltip: true
};
var _default = exports.default = Ellipsis;
//# sourceMappingURL=Ellipsis.js.map