UNPKG

@yandex/ui

Version:

Yandex UI components

110 lines (109 loc) 5.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.withZIndex = void 0; var tslib_1 = require("tslib"); var react_1 = tslib_1.__importStar(require("react")); var getDisplayName_1 = require("../lib/getDisplayName"); var mergeRefs_1 = require("../lib/mergeRefs"); var ZINDEX_FACTOR = 1000; var ZINDEXES_STACK = {}; var defaultProps = { zIndexGroupLevel: 0, }; var withZIndex = function (WrappedComponent) { var _a; return _a = /** @class */ (function (_super) { tslib_1.__extends(WithZIndex, _super); function WithZIndex() { var _this = _super !== null && _super.apply(this, arguments) || this; /** * Текущий `z-index` компонента */ _this.currentZIndex = 0; /** * Контейнер с ссылкой на DOM элемент компонента. */ _this.innerRef = react_1.createRef(); return _this; } WithZIndex.prototype.componentDidMount = function () { if (this.props.visible) { this.updateZIndexPosition(); } }; WithZIndex.prototype.componentDidUpdate = function (prevProps) { if (prevProps.visible !== this.props.visible) { this.updateZIndexPosition(); } }; WithZIndex.prototype.componentWillUnmount = function () { if (this.currentZIndex !== 0) { this.releaseZIndex(this.props.zIndexGroupLevel, this.currentZIndex); } }; WithZIndex.prototype.render = function () { var _a = this.props, zIndexGroupLevel = _a.zIndexGroupLevel, props = tslib_1.__rest(_a, ["zIndexGroupLevel"]); return (react_1.default.createElement(WrappedComponent, tslib_1.__assign({}, props, { innerRef: mergeRefs_1.mergeAllRefs(this.innerRef, this.props.innerRef) }))); }; /** * Обновлять стили, отвечающие за позиционирование у DOM элемента компонента. */ WithZIndex.prototype.updateZIndexPosition = function () { var _this = this; requestAnimationFrame(function () { var _a = _this.props, visible = _a.visible, zIndexGroupLevel = _a.zIndexGroupLevel; if (visible && _this.currentZIndex === 0) { _this.currentZIndex = _this.captureZIndex(zIndexGroupLevel); } else if (!visible) { _this.currentZIndex = _this.releaseZIndex(zIndexGroupLevel, _this.currentZIndex); } // имеет смысл обновлять zIndex только у видимого элемента if (visible) { // Обновляем стили сразу у DOM узла, а не через setState, // т.к. это не вызывает лишний раз re-render и повышает производительность. if (_this.innerRef.current !== null) { _this.innerRef.current.style.zIndex = String(_this.currentZIndex); } else { // пробуем проставить zIndex в следующем кадре, если в текущем ref еще не существует _this.updateZIndexPosition(); } } }); }; /** * Занимает наименьший свободный z-index в стеке для своего уровня и возвращает его. * * @param zIndexGroupLevel Уровень в стеке для которого необходимо занять `z-index` */ WithZIndex.prototype.captureZIndex = function (zIndexGroupLevel) { var zIndexes = ZINDEXES_STACK[zIndexGroupLevel]; if (zIndexes === undefined) { zIndexes = [(zIndexGroupLevel + 1) * ZINDEX_FACTOR]; ZINDEXES_STACK[zIndexGroupLevel] = zIndexes; } var nextZIndex = zIndexes[zIndexes.length - 1] + 1; zIndexes.push(nextZIndex); return nextZIndex; }; /** * Освобождает `z-index` в стеке и возвращает нулевую позицию. * * @param zIndexGroupLevel Уровень в стеке для которого необходимо освободить `z-index` * @param currentZIndex Текущий `z-index` компонента */ WithZIndex.prototype.releaseZIndex = function (zIndexGroupLevel, currentZIndex) { var zIndexes = ZINDEXES_STACK[zIndexGroupLevel]; if (zIndexes !== undefined && zIndexes.length > 1) { zIndexes.splice(zIndexes.indexOf(currentZIndex), 1); } return 0; }; return WithZIndex; }(react_1.PureComponent)), _a.displayName = "withZIndex(" + getDisplayName_1.getDisplayName(WrappedComponent) + ")", _a.defaultProps = defaultProps, _a; }; exports.withZIndex = withZIndex;