import { __decorate, __extends, __metadata } from "tslib";
import { Component, Prop, Watch, Inject } from 'vue-property-decorator';
import { hiddenContentStyle } from '@uifabric/styling';
import { StickyPositionType } from './Sticky.types';
import BaseComponent from '../BaseComponent';
var Sticky = /** @class */ (function (_super) {
    __extends(Sticky, _super);
    function Sticky() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.hiddenContentStyle = hiddenContentStyle;
        _this.isStickyTop = false;
        _this.isStickyBottom = false;
        _this.distanceFromTop = 0;
        _this.activeElement = null;
        return _this;
    }
    Sticky.prototype.render = function (h) {
        var _a = this, canStickyTop = _a.canStickyTop, canStickyBottom = _a.canStickyBottom, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom, stickyClassName = _a.stickyClassName;
        var $stickyTop = canStickyTop && h('div', {
            ref: 'stickyContentTop',
            style: { pointerEvents: isStickyTop ? 'auto' : 'none' },
            attrs: {
                'aria-hidden': !isStickyTop,
            },
        }, [
            h('div', { style: this.getStickyPlaceholderHeight(isStickyTop) }),
        ]);
        var $stickyBottom = canStickyBottom && h('div', {
            ref: 'stickyContentBottom',
            style: { pointerEvents: isStickyBottom ? 'auto' : 'none' },
            attrs: {
                'aria-hidden': !isStickyBottom,
            },
        }, [
            h('div', { style: this.getStickyPlaceholderHeight(isStickyBottom) }),
        ]);
        var $placeHolder = h('div', {
            ref: 'placeHolder',
            style: this.getNonStickyPlaceholderHeightAndWidth(),
        }, [
            (isStickyTop || isStickyBottom) && h('span', {
                style: hiddenContentStyle,
            }, this.$slots.default),
            h('div', {
                ref: 'nonStickyContent',
                class: isStickyTop || isStickyBottom ? stickyClassName : undefined,
                style: this.getContentStyles(isStickyTop || isStickyBottom),
                attrs: {
                    'aria-hidden': isStickyTop || isStickyBottom,
                },
            }, this.$slots.default),
        ]);
        return h('div', { ref: 'root' }, [
            $stickyTop,
            $stickyBottom,
            $placeHolder,
        ]);
    };
    Sticky.prototype.root = function () {
        return this.$refs.root;
    };
    Object.defineProperty(Sticky.prototype, "canStickyTop", {
        get: function () {
            return this.stickyPosition === StickyPositionType.Both || this.stickyPosition === StickyPositionType.Header;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Sticky.prototype, "canStickyBottom", {
        get: function () {
            return this.stickyPosition === StickyPositionType.Both || this.stickyPosition === StickyPositionType.Footer;
        },
        enumerable: false,
        configurable: true
    });
    Sticky.prototype.syncScroll = function (container) {
        var nonStickyContent = this.$refs.nonStickyContent;
        if (nonStickyContent && this.isScrollSynced) {
            nonStickyContent.scrollLeft = container.scrollLeft;
        }
    };
    ;
    Sticky.prototype.mounted = function () {
        var scrollablePane = this.context.scrollablePane;
        if (!scrollablePane) {
            return;
        }
        scrollablePane.subscribe(this._onScrollEvent);
        scrollablePane.addSticky(this);
    };
    Sticky.prototype.beforeDestroy = function () {
        var scrollablePane = this.context.scrollablePane;
        if (!scrollablePane) {
            return;
        }
        scrollablePane.unsubscribe(this._onScrollEvent);
        scrollablePane.removeSticky(this);
    };
    Sticky.prototype.onDistanceFromTopChanged = function (newVal, oldVal) {
        var scrollablePane = this.context.scrollablePane;
        if (!scrollablePane) {
            return;
        }
        if (newVal !== oldVal) {
            scrollablePane.sortSticky(this, true /* sortAgain */);
            // Sync Sticky scroll position with content container on each update
            scrollablePane.syncScrollSticky(this);
        }
    };
    Sticky.prototype.onIsStickyTopChanged = function (newVal, oldVal) {
        var scrollablePane = this.context.scrollablePane;
        if (!scrollablePane) {
            return;
        }
        if (newVal !== oldVal) {
            if (this.activeElement) {
                this.activeElement.focus();
            }
            scrollablePane.updateStickyRefHeights();
            // Sync Sticky scroll position with content container on each update
            scrollablePane.syncScrollSticky(this);
        }
    };
    Sticky.prototype.onIsStickyBottomChanged = function (newVal, oldVal) {
        var scrollablePane = this.context.scrollablePane;
        if (!scrollablePane) {
            return;
        }
        if (newVal !== oldVal) {
            if (this.activeElement) {
                this.activeElement.focus();
            }
            scrollablePane.updateStickyRefHeights();
            // Sync Sticky scroll position with content container on each update
            scrollablePane.syncScrollSticky(this);
        }
    };
    Sticky.prototype.addSticky = function (stickyContent) {
        if (this.$refs.nonStickyContent) {
            stickyContent.appendChild(this.$refs.nonStickyContent);
        }
    };
    Sticky.prototype.resetSticky = function () {
        if (this.$refs.nonStickyContent && this.$refs.placeHolder) {
            this.$refs.placeHolder.appendChild(this.$refs.nonStickyContent);
        }
    };
    Sticky.prototype.setDistanceFromTop = function (container) {
        var distanceFromTop = this._getNonStickyDistanceFromTop(container);
        this.distanceFromTop = distanceFromTop;
    };
    Sticky.prototype.getContentStyles = function (isSticky) {
        return {
            backgroundColor: this.stickyBackgroundColor || this._getBackground(),
            overflow: isSticky ? 'hidden' : '',
        };
    };
    Sticky.prototype.getStickyPlaceholderHeight = function (isSticky) {
        var height = this.$refs.nonStickyContent ? this.$refs.nonStickyContent.offsetHeight : 0;
        return {
            visibility: isSticky ? 'hidden' : 'visible',
            height: isSticky ? 0 : height,
        };
    };
    Sticky.prototype.getNonStickyPlaceholderHeightAndWidth = function () {
        var _a = this, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom;
        if (isStickyTop || isStickyBottom) {
            var height = 0;
            var width = 0;
            // Why is placeHolder width needed?
            // ScrollablePane content--container is reponsible for providing scrollbars depending on content overflow.
            // If the overflow is caused by content of sticky component when it is in non-sticky state,
            // ScrollablePane content--conatiner will provide horizontal scrollbar.
            // If the component becomes sticky, i.e., when state.isStickyTop || state.isStickyBottom becomes true,
            // it's actual content is no more inside ScrollablePane content--container.
            // ScrollablePane content--conatiner will see no need for horizontal scrollbar. (Assuming no other content is causing overflow)
            // The complete content of sticky component will not be viewable.
            // It is necessary to provide a placeHolder of a certain width (height is already being set) in the content--container,
            // to get a horizontal scrollbar & be able to view the complete content of sticky component.
            if (this.$refs.nonStickyContent && this.$refs.nonStickyContent.firstElementChild) {
                height = this.$refs.nonStickyContent.offsetHeight;
                // What value should be substituted for placeHolder width?
                // Assumption:
                //    1. Content inside <Sticky> should always be wrapped in a single div.
                //        <Sticky><div id={'firstElementChild'}>{intended_content}</div><Sticky/>
                //    2. -ve padding, margin, etc. are not be used.
                //    3. scrollWidth of a parent is greater than or equal to max of scrollWidths of it's children and same holds for children.
                // placeHolder width should be computed in the best possible way to prevent overscroll/underscroll.
                width =
                    this.$refs.nonStickyContent.firstElementChild.scrollWidth +
                        (this.$refs.nonStickyContent.firstElementChild.offsetWidth - this.$refs.nonStickyContent.firstElementChild.clientWidth);
            }
            return {
                height: height,
                width: width,
            };
        }
        else {
            return {};
        }
    };
    Sticky.prototype._onScrollEvent = function (container, footerStickyContainer) {
        if (this.$refs.root && this.$refs.nonStickyContent) {
            var distanceFromTop = this._getNonStickyDistanceFromTop(container);
            var isStickyTop = false;
            var isStickyBottom = false;
            if (this.canStickyTop) {
                var distanceToStickTop = 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 <= distanceFromTop) {
                isStickyBottom =
                    distanceFromTop - Math.floor(container.scrollTop) >= this._getStickyDistanceFromTopForFooter(container, footerStickyContainer);
            }
            if (document.activeElement &&
                this.$refs.nonStickyContent.contains(document.activeElement) &&
                (this.isStickyTop !== isStickyTop || this.isStickyBottom !== isStickyBottom)) {
                this.activeElement = document.activeElement;
            }
            else {
                this.activeElement = undefined;
            }
            this.isStickyTop = this.canStickyTop && isStickyTop;
            this.isStickyBottom = isStickyBottom;
            this.distanceFromTop = distanceFromTop;
        }
    };
    ;
    Sticky.prototype._getStickyDistanceFromTop = function () {
        var distance = 0;
        if (this.$refs.stickyContentTop) {
            distance = this.$refs.stickyContentTop.offsetTop;
        }
        return distance;
    };
    ;
    Sticky.prototype._getStickyDistanceFromTopForFooter = function (container, footerStickyVisibleContainer) {
        var distance = 0;
        if (this.$refs.stickyContentBottom) {
            distance = container.clientHeight - footerStickyVisibleContainer.offsetHeight + this.$refs.stickyContentBottom.offsetTop;
        }
        return distance;
    };
    ;
    Sticky.prototype._getNonStickyDistanceFromTop = function (container) {
        var distance = 0;
        var currElem = this.$refs.root;
        if (currElem) {
            while (currElem && currElem.offsetParent !== container) {
                distance += currElem.offsetTop;
                currElem = currElem.offsetParent;
            }
            if (currElem && currElem.offsetParent === container) {
                distance += currElem.offsetTop;
            }
        }
        return distance;
    };
    ;
    // Gets background of nearest parent element that has a declared background-color attribute
    Sticky.prototype._getBackground = function () {
        if (!this.$refs.root) {
            return undefined;
        }
        var curr = this.$refs.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');
    };
    __decorate([
        Inject({ from: 'context', default: undefined }),
        __metadata("design:type", Object)
    ], Sticky.prototype, "context", void 0);
    __decorate([
        Prop({ type: String, default: null }),
        __metadata("design:type", String)
    ], Sticky.prototype, "stickyClassName", void 0);
    __decorate([
        Prop({ type: String, default: null }),
        __metadata("design:type", String)
    ], Sticky.prototype, "stickyBackgroundColor", void 0);
    __decorate([
        Prop({ type: Number, default: StickyPositionType.Both }),
        __metadata("design:type", Number)
    ], Sticky.prototype, "stickyPosition", void 0);
    __decorate([
        Prop({ type: Boolean, default: true }),
        __metadata("design:type", Boolean)
    ], Sticky.prototype, "isScrollSynced", void 0);
    __decorate([
        Watch('distanceFromTop'),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Number, Number]),
        __metadata("design:returntype", void 0)
    ], Sticky.prototype, "onDistanceFromTopChanged", null);
    __decorate([
        Watch('isStickyTop'),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Boolean, Boolean]),
        __metadata("design:returntype", void 0)
    ], Sticky.prototype, "onIsStickyTopChanged", null);
    __decorate([
        Watch('isStickyBottom'),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Boolean, Boolean]),
        __metadata("design:returntype", void 0)
    ], Sticky.prototype, "onIsStickyBottomChanged", null);
    Sticky = __decorate([
        Component({})
    ], Sticky);
    return Sticky;
}(BaseComponent));
export { Sticky };
function _isOffsetHeightDifferent(a, b) {
    return (a && b && a && b && a.offsetHeight !== b.offsetHeight);
}
//# sourceMappingURL=Sticky.js.map