import * as tslib_1 from "tslib";
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { BaseComponent, createRef } from '../../Utilities';
import { StickyPositionType } from './Sticky.types';
var Sticky = /** @class */ (function (_super) {
    tslib_1.__extends(Sticky, _super);
    function Sticky(props) {
        var _this = _super.call(this, props) || this;
        _this._root = createRef();
        _this._stickyContentTop = createRef();
        _this._stickyContentBottom = createRef();
        _this._nonStickyContent = createRef();
        _this._onScrollEvent = function (container, footerStickyContainer) {
            if (_this.root && _this.nonStickyContent) {
                _this.distanceFromTop = _this._getNonStickyDistanceFromTop(container);
                var isStickyTop = false;
                var isStickyBottom = false;
                if (_this.props.isScrollSynced) {
                    _this._syncScroll(container);
                }
                if (_this.canStickyTop) {
                    var distanceToStickTop = _this.distanceFromTop - _this._getStickyDistanceFromTop();
                    isStickyTop = distanceToStickTop < container.scrollTop;
                }
                // Can sticky bottom if the scrollablePane - total sticky footer height is smaller than the sticky's distance from the top of the pane
                if (_this.canStickyBottom && container.clientHeight - footerStickyContainer.offsetHeight <= _this.distanceFromTop) {
                    isStickyBottom =
                        _this.distanceFromTop - container.scrollTop >
                            _this._getStickyDistanceFromTopForFooter(container, footerStickyContainer);
                }
                _this.setState({
                    isStickyTop: _this.canStickyTop && isStickyTop,
                    isStickyBottom: isStickyBottom
                });
            }
        };
        _this._syncScroll = function (container) {
            if (_this.root) {
                var scrollLeft = 0;
                var scrollTop = 0;
                var curr = _this.root;
                while (curr !== container) {
                    scrollLeft += curr.scrollLeft;
                    scrollTop += curr.scrollTop;
                    curr = curr.parentElement;
                }
                if (_this.stickyContentTop) {
                    _this.stickyContentTop.scrollLeft = scrollLeft;
                    _this.stickyContentTop.scrollTop = scrollTop;
                }
            }
        };
        _this._getStickyDistanceFromTop = function () {
            var distance = 0;
            if (_this.stickyContentTop) {
                distance = _this.stickyContentTop.offsetTop;
            }
            return distance;
        };
        _this._getStickyDistanceFromTopForFooter = function (container, footerStickyVisibleContainer) {
            var distance = 0;
            if (_this.stickyContentBottom) {
                distance =
                    container.clientHeight - footerStickyVisibleContainer.offsetHeight + _this.stickyContentBottom.offsetTop;
            }
            return distance;
        };
        _this._getNonStickyDistanceFromTop = function (container) {
            var distance = 0;
            var currElem = _this.root;
            if (currElem) {
                while (currElem.offsetParent !== container) {
                    distance += currElem.offsetTop;
                    currElem = currElem.offsetParent;
                }
                if (currElem.offsetParent === container) {
                    distance += currElem.offsetTop;
                }
            }
            return distance;
        };
        _this.state = {
            isStickyTop: false,
            isStickyBottom: false
        };
        _this.distanceFromTop = 0;
        return _this;
    }
    Object.defineProperty(Sticky.prototype, "root", {
        get: function () {
            return this._root.current;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Sticky.prototype, "stickyContentTop", {
        get: function () {
            return this._stickyContentTop.current;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Sticky.prototype, "stickyContentBottom", {
        get: function () {
            return this._stickyContentBottom.current;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Sticky.prototype, "nonStickyContent", {
        get: function () {
            return this._nonStickyContent.current;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Sticky.prototype, "canStickyTop", {
        get: function () {
            return (this.props.stickyPosition === StickyPositionType.Both || this.props.stickyPosition === StickyPositionType.Header);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Sticky.prototype, "canStickyBottom", {
        get: function () {
            return (this.props.stickyPosition === StickyPositionType.Both || this.props.stickyPosition === StickyPositionType.Footer);
        },
        enumerable: true,
        configurable: true
    });
    Sticky.prototype.componentDidMount = function () {
        if (!this.context.scrollablePane) {
            throw new TypeError('Expected Sticky to be mounted within ScrollablePane');
        }
        var scrollablePane = this.context.scrollablePane;
        scrollablePane.subscribe(this._onScrollEvent);
        scrollablePane.addSticky(this);
    };
    Sticky.prototype.componentWillUnmount = function () {
        var scrollablePane = this.context.scrollablePane;
        scrollablePane.unsubscribe(this._onScrollEvent);
        scrollablePane.removeSticky(this);
    };
    Sticky.prototype.componentDidUpdate = function (prevProps, prevState) {
        var scrollablePane = this.context.scrollablePane;
        if (prevState.isStickyTop !== this.state.isStickyTop || prevState.isStickyBottom !== this.state.isStickyBottom) {
            scrollablePane.updateStickyRefHeights();
        }
    };
    Sticky.prototype.shouldComponentUpdate = function (nextProps, nextState) {
        var _a = this.state, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom;
        return (isStickyTop !== nextState.isStickyTop ||
            isStickyBottom !== nextState.isStickyBottom ||
            this.props.stickyPosition !== nextProps.stickyPosition ||
            this.props.children !== nextProps.children);
    };
    Sticky.prototype.render = function () {
        var _a = this.state, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom;
        return (React.createElement("div", { ref: this._root },
            this.canStickyTop && (React.createElement("div", { className: this.props.stickyClassName, ref: this._stickyContentTop, "aria-hidden": !isStickyTop, style: this._getStickyContainerStyle() },
                React.createElement("div", { style: this._getStickyPlaceholderHeight(isStickyTop) }))),
            this.canStickyBottom && (React.createElement("div", { className: this.props.stickyClassName, ref: this._stickyContentBottom, "aria-hidden": !isStickyBottom, style: this._getStickyContainerStyle() },
                React.createElement("div", { style: this._getStickyPlaceholderHeight(isStickyBottom) }))),
            React.createElement("div", { style: this._getNonStickyPlaceholderHeight() }),
            React.createElement("div", { ref: this._nonStickyContent, className: isStickyTop || isStickyBottom ? this.props.stickyClassName : undefined, style: this._getContentStyles(isStickyTop || isStickyBottom) }, this.props.children)));
    };
    Sticky.prototype.addSticky = function (stickyContent) {
        if (this.nonStickyContent) {
            stickyContent.appendChild(this.nonStickyContent);
        }
    };
    Sticky.prototype.resetSticky = function () {
        if (this.nonStickyContent && this.root) {
            this.root.appendChild(this.nonStickyContent);
        }
    };
    Sticky.prototype.setDistanceFromTop = function (container) {
        this.distanceFromTop = this._getNonStickyDistanceFromTop(container);
    };
    Sticky.prototype._getContentStyles = function (isSticky) {
        return {
            backgroundColor: this.props.stickyBackgroundColor || this._getBackground()
        };
    };
    Sticky.prototype._getStickyContainerStyle = function () {
        var isScrollSynced = this.props.isScrollSynced;
        return {
            overflow: isScrollSynced ? 'hidden' : 'auto'
        };
    };
    Sticky.prototype._getStickyPlaceholderHeight = function (isSticky) {
        var height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0;
        return {
            visibility: isSticky ? 'hidden' : 'visible',
            height: isSticky ? 0 : height
        };
    };
    Sticky.prototype._getNonStickyPlaceholderHeight = function () {
        var _a = this.state, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom;
        if (isStickyTop || isStickyBottom) {
            var height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0;
            return {
                height: height
            };
        }
        else {
            return {
                position: 'absolute'
            };
        }
    };
    // Gets background of nearest parent element that has a declared background-color attribute
    Sticky.prototype._getBackground = function () {
        if (!this.root) {
            return undefined;
        }
        var curr = this.root;
        while (window.getComputedStyle(curr).getPropertyValue('background-color') === 'rgba(0, 0, 0, 0)' ||
            window.getComputedStyle(curr).getPropertyValue('background-color') === 'transparent') {
            if (curr.tagName === 'HTML') {
                // Fallback color if no element has a declared background-color attribute
                return undefined;
            }
            if (curr.parentElement) {
                curr = curr.parentElement;
            }
        }
        return window.getComputedStyle(curr).getPropertyValue('background-color');
    };
    Sticky.defaultProps = {
        stickyPosition: StickyPositionType.Both,
        isScrollSynced: true
    };
    Sticky.contextTypes = {
        scrollablePane: PropTypes.object
    };
    return Sticky;
}(BaseComponent));
export { Sticky };
//# sourceMappingURL=Sticky.js.map