var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import React from 'react';
import shallowEqual from 'shallowequal';
import warning from 'warning';
import * as LayoutEvents from '../../lib/LayoutEvents.js';
import { isFunction } from '../../lib/utils.js';
import { ZIndex } from '../../internal/ZIndex/index.js';
import { CommonWrapper } from '../../internal/CommonWrapper/index.js';
import { rootNode } from '../../lib/rootNode/index.js';
import { getDOMRect } from '../../lib/dom/getDOMRect.js';
import { createPropsGetter } from '../../lib/createPropsGetter.js';
import { withRenderEnvironment } from '../../lib/renderEnvironment/index.js';
import { getStyles } from './Sticky.styles.js';
var MAX_REFLOW_RETRIES = 5;
export var StickyDataTids = {
    root: 'Sticky__root',
};
/**
 * `Sticky` позволяет закреплять элемент интерфейса в определенной позиции на экране при прокрутке страницы.
 * Это полезно для создания "прилипающих" элементов, которые остаются видимыми при прокрутке содержимого.
 */
var Sticky = /** @class */ (function (_super) {
    __extends(Sticky, _super);
    function Sticky() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.getProps = createPropsGetter(Sticky_1.defaultProps);
        _this.state = {
            fixed: false,
            deltaHeight: 0,
            stopped: false,
            relativeTop: 0,
        };
        _this.layoutSubscription = { remove: null };
        _this.reflowCounter = 0;
        _this.refWrapper = function (ref) {
            _this.wrapper = ref;
        };
        _this.refInner = function (ref) {
            _this.inner = ref;
        };
        /**
         * Пересчитать габариты и позицию залипшего элемента
         *
         * @public
         */
        _this.reflow = function () {
            var _a;
            if (!((_a = _this.globalObject.document) === null || _a === void 0 ? void 0 : _a.documentElement)) {
                warning(false, 'There is no "documentElement" in document');
                return;
            }
            var windowHeight = _this.globalObject.innerHeight || _this.globalObject.document.documentElement.clientHeight;
            if (!_this.wrapper || !_this.inner) {
                return;
            }
            var _b = getDOMRect(_this.wrapper), top = _b.top, bottom = _b.bottom, left = _b.left, width = _b.width;
            var height = getDOMRect(_this.inner).height;
            var _c = _this.props, getStop = _c.getStop, side = _c.side;
            var _d = _this.state, prevFixed = _d.fixed, _e = _d.height, prevHeight = _e === void 0 ? height : _e;
            var offset = _this.getProps().offset;
            var fixed = side === 'top' ? Math.ceil(top) < offset : Math.floor(bottom) > windowHeight - offset;
            _this.setState({ fixed: fixed, left: left });
            if (fixed && !prevFixed) {
                _this.setState({ width: width, height: height });
            }
            if (fixed) {
                _this.setState({ width: width });
                var stop_1 = getStop && getStop();
                if (stop_1) {
                    var deltaHeight = prevHeight - height;
                    var stopRect = getDOMRect(stop_1);
                    var outerHeight_1 = height + offset;
                    var stopped = false;
                    var relativeTop = 0;
                    if (side === 'top') {
                        stopped = stopRect.top - outerHeight_1 < 0;
                        relativeTop = stopRect.top - prevHeight - top;
                    }
                    else {
                        stopped = stopRect.bottom + outerHeight_1 > windowHeight;
                        relativeTop = stopRect.bottom - top;
                    }
                    _this.setState({ relativeTop: relativeTop, deltaHeight: deltaHeight, stopped: stopped });
                }
            }
        };
        return _this;
    }
    Sticky_1 = Sticky;
    Sticky.prototype.componentDidMount = function () {
        this.reflow();
        this.layoutSubscription = LayoutEvents.addListener(this.reflow, this.globalObject);
    };
    Sticky.prototype.componentWillUnmount = function () {
        if (this.layoutSubscription.remove) {
            this.layoutSubscription.remove();
        }
    };
    Sticky.prototype.componentDidUpdate = function (prevProps, prevState) {
        if (!shallowEqual(prevProps, this.props) || !shallowEqual(prevState, this.state)) {
            if (this.reflowCounter < MAX_REFLOW_RETRIES) {
                this.reflow();
                this.reflowCounter += 1;
                return;
            }
        }
        this.reflowCounter = 0;
    };
    Sticky.prototype.render = function () {
        this.styles = getStyles(this.emotion);
        return this.renderMain();
    };
    Sticky.prototype.renderMain = function () {
        var _a;
        var children = this.props.children;
        var side = this.props.side;
        var offset = this.getProps().offset;
        var _b = this.state, fixed = _b.fixed, stopped = _b.stopped, relativeTop = _b.relativeTop, deltaHeight = _b.deltaHeight, width = _b.width, height = _b.height, left = _b.left;
        var innerStyle = {};
        if (fixed) {
            if (stopped) {
                innerStyle.top = relativeTop;
                innerStyle[side === 'top' ? 'marginTop' : 'marginBottom'] = deltaHeight;
            }
            else {
                innerStyle.width = width;
                innerStyle[side] = offset;
                innerStyle.left = left;
            }
        }
        if (isFunction(children)) {
            children = children(fixed);
        }
        return (React.createElement(CommonWrapper, __assign({ rootNodeRef: this.setRootNode }, this.props),
            React.createElement("div", { "data-tid": StickyDataTids.root, ref: this.refWrapper, className: this.styles.wrapper() },
                React.createElement(ZIndex, { priority: "Sticky", applyZIndex: fixed, className: this.cx(this.styles.inner(), (_a = {},
                        _a[this.styles.fixed()] = fixed && !stopped,
                        _a[this.styles.stopped()] = stopped,
                        _a)), style: innerStyle, wrapperRef: this.refInner },
                    React.createElement("div", { className: this.styles.container() }, children)),
                fixed && !stopped ? React.createElement("div", { style: { width: width, height: height } }) : null)));
    };
    var Sticky_1;
    Sticky.__KONTUR_REACT_UI__ = 'Sticky';
    Sticky.displayName = 'Sticky';
    Sticky.defaultProps = { offset: 0 };
    Sticky = Sticky_1 = __decorate([
        withRenderEnvironment,
        rootNode
    ], Sticky);
    return Sticky;
}(React.Component));
export { Sticky };
//# sourceMappingURL=Sticky.js.map