import { __assign, __decorate, __extends, __metadata } from "tslib";
import { Component, Prop, Watch } from 'vue-property-decorator';
import BaseComponent from '../BaseComponent';
import { findScrollableParent, getWindow, findIndex, getParent } from '@uifabric-vue/utilities';
var RESIZE_DELAY = 16;
var MIN_SCROLL_UPDATE_DELAY = 100;
var MAX_SCROLL_UPDATE_DELAY = 500;
var IDLE_DEBOUNCE_DELAY = 200;
// The amount of time to wait before declaring that the list isn't scrolling
var DONE_SCROLLING_WAIT = 500;
var DEFAULT_ITEMS_PER_PAGE = 10;
var DEFAULT_PAGE_HEIGHT = 30;
var DEFAULT_RENDERED_WINDOWS_BEHIND = 2;
var DEFAULT_RENDERED_WINDOWS_AHEAD = 2;
var PAGE_KEY_PREFIX = 'page-';
var SPACER_KEY_PREFIX = 'spacer-';
var EMPTY_RECT = {
    top: -1,
    bottom: -1,
    left: -1,
    right: -1,
    width: 0,
    height: 0,
};
// Naming expensive measures so that they're named in profiles.
var measurePageRect = function (element) { return element.getBoundingClientRect(); };
var _measureSurfaceRect = measurePageRect;
var _measureScrollRect = measurePageRect;
/**
 * The List renders virtualized pages of items. Each page's item count is determined by the getItemCountForPage callback if
 * provided by the caller, or 10 as default. Each page's height is determined by the getPageHeight callback if provided by
 * the caller, or by cached measurements if available, or by a running average, or a default fallback.
 *
 * The algorithm for rendering pages works like this:
 *
 * 1. Predict visible pages based on "current measure data" (page heights, surface position, visible window)
 * 2. If changes are necessary, apply changes (add/remove pages)
 * 3. For pages that are added, measure the page heights if we need to using getBoundingClientRect
 * 4. If measurements don't match predictions, update measure data and goto step 1 asynchronously
 *
 * Measuring too frequently can pull performance down significantly. To compensate, we cache measured values so that
 * we can avoid re-measuring during operations that should not alter heights, like scrolling.
 *
 * To optimize glass rendering performance, onShouldVirtualize can be set. When onShouldVirtualize return false,
 * List will run in fast mode (not virtualized) to render all items without any measurements to improve page load time. And we
 * start doing measurements and rendering in virtualized mode when items grows larger than this threshold.
 *
 * However, certain operations can make measure data stale. For example, resizing the list, or passing in new props,
 * or forcing an update change cause pages to shrink/grow. When these operations occur, we increment a measureVersion
 * number, which we associate with cached measurements and use to determine if a remeasure should occur.
 */
var List = /** @class */ (function (_super) {
    __extends(List, _super);
    function List() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.pages = [];
        _this.isScrolling = false;
        _this.measureVersion = 0;
        _this.requiredRect = null;
        _this.materializedRect = null;
        _this.scrollHeight = 0;
        _this.scrollTop = 0;
        _this.requiredWindowsAhead = 0;
        _this.requiredWindowsBehind = 0;
        _this.role = 'list';
        _this.focusedIndex = -1;
        _this.totalEstimates = 0;
        _this.hasCompletedFirstRender = false;
        _this.pageCache = {};
        _this.cachedPageHeights = {};
        _this.estimatedPageHeight = 0;
        return _this;
    }
    List.prototype.render = function (h) {
        var _this = this;
        var _a = this, pages = _a.pages, className = _a.className, css = _a.css, role = _a.role;
        var $pages = pages.map(function (page) { return h('div', {
            key: page.key,
            ref: page.key,
            refInFor: true,
            class: 'ms-List-page',
            style: _this.getPageStyle(page),
        }, page.items && page.items.map(function (item, index) { return h('div', {
            key: index,
            class: 'ms-List-cell',
        }, _this.$scopedSlots.item
            ? _this.$scopedSlots.item({ item: item, index: page.startIndex + index })
            : (item ? item.name : '')); })); });
        return h('div', {
            ref: 'root',
            class: css('ms-List', className),
            attrs: {
                role: pages.length > 0 ? role : undefined,
            },
        }, [
            h('div', {
                ref: 'surface',
                class: 'ms-List-surface',
                attrs: { role: 'presentation' },
            }, $pages),
        ]);
    };
    List.prototype.created = function () {
        this._onScrollingDone = this._async.debounce(this._onScrollingDone, DONE_SCROLLING_WAIT, {
            leading: false,
        });
        this._onAsyncScroll = this._async.debounce(this._onAsyncScroll, MIN_SCROLL_UPDATE_DELAY, {
            leading: false,
            maxWait: MAX_SCROLL_UPDATE_DELAY,
        });
        this._onAsyncIdle = this._async.debounce(this._onAsyncIdle, IDLE_DEBOUNCE_DELAY, {
            leading: false,
        });
    };
    List.prototype.itemsChanged = function (newVal, oldVal) {
        if (newVal !== oldVal)
            this.updatePages();
    };
    List.prototype.shouldUpdate = function (newVal, oldVal) {
        if (!newVal && oldVal)
            this.updatePages();
    };
    List.prototype.mounted = function () {
        this.updatePages();
        this.measureVersion++;
        this.scrollElement = findScrollableParent(this.$refs.root);
        if (this.$refs.root) {
            this.events.on(this.$refs.root, 'focus', this._onFocus, true);
        }
        if (this.scrollElement) {
            this.events.on(this.scrollElement, 'scroll', this._onScroll);
            this.events.on(this.scrollElement, 'scroll', this._onAsyncScroll);
        }
    };
    /**
     * Debounced method to asynchronously update the visible region on a scroll event.
     */
    List.prototype._onAsyncScroll = function () {
        this.updateRenderRects();
        // Only update pages when the visible rect falls outside of the materialized rect.
        if (!this.materializedRect || !_isContainedWithin(this.requiredRect, this.materializedRect)) {
            this.updatePages();
        }
        else {
            // console.log('requiredRect contained in materialized', this._requiredRect, this._materializedRect);
        }
    };
    /**
     * This is an async debounced method that will try and increment the windows we render. If we can increment
     * either, we increase the amount we render and re-evaluate.
     */
    List.prototype._onAsyncIdle = function () {
        var _a = this, renderedWindowsAhead = _a.renderedWindowsAhead, renderedWindowsBehind = _a.renderedWindowsBehind;
        var _b = this, requiredWindowsAhead = _b.requiredWindowsAhead, requiredWindowsBehind = _b.requiredWindowsBehind;
        var windowsAhead = Math.min(renderedWindowsAhead, requiredWindowsAhead + 1);
        var windowsBehind = Math.min(renderedWindowsBehind, requiredWindowsBehind + 1);
        if (windowsAhead !== requiredWindowsAhead || windowsBehind !== requiredWindowsBehind) {
            this.requiredWindowsAhead = windowsAhead;
            this.requiredWindowsBehind = windowsBehind;
            this.updateRenderRects();
            this.updatePages();
        }
        if (renderedWindowsAhead > windowsAhead || renderedWindowsBehind > windowsBehind) {
            // Async increment on next tick.
            this._onAsyncIdle();
        }
    };
    /** Track the last item index focused so that we ensure we keep it rendered. */
    List.prototype._onFocus = function (ev) {
        var target = ev.target;
        while (target !== this.$refs.surface) {
            var indexString = target.getAttribute('data-list-index');
            if (indexString) {
                this.focusedIndex = Number(indexString);
                break;
            }
            target = getParent(target);
        }
    };
    /**
     * Called synchronously to reset the required render range to 0 on scrolling. After async scroll has executed,
     * we will call onAsyncIdle which will reset it back to it's correct value.
     */
    List.prototype._onScroll = function () {
        if (!this.isScrolling && !this.ignoreScrollingState) {
            this.isScrolling = true;
        }
        this.resetRequiredWindows();
        // @ts-ignore
        this._onScrollingDone();
    };
    List.prototype.resetRequiredWindows = function () {
        this.requiredWindowsAhead = 0;
        this.requiredWindowsBehind = 0;
    };
    /**
     * Function to call when the list is done scrolling.
     * This function is debounced.
     */
    List.prototype._onScrollingDone = function () {
        if (!this.ignoreScrollingState) {
            this.isScrolling = false;
        }
    };
    /** Generate the style object for the page. */
    List.prototype.getPageStyle = function (page) {
        var getPageStyle = this.$props.getPageStyle;
        return __assign(__assign({}, (getPageStyle ? getPageStyle(page) : {})), (!page.items
            ? {
                height: page.height + 'px',
            }
            : {}));
    };
    List.prototype._buildPages = function (props) {
        var renderCount = props.renderCount;
        var items = props.items, startIndex = props.startIndex, getPageHeight = props.getPageHeight;
        renderCount = this._getRenderCount(props);
        var materializedRect = __assign({}, EMPTY_RECT);
        var pages = [];
        var itemsPerPage = 1;
        var pageTop = 0;
        var currentSpacer = null;
        var focusedIndex = this.focusedIndex;
        var endIndex = startIndex + renderCount;
        var shouldVirtualize = this.shouldVirtualize(props);
        // First render is very important to track; when we render cells, we have no idea of estimated page height.
        // So we should default to rendering only the first page so that we can get information.
        // However if the user provides a measure function, let's just assume they know the right heights.
        var isFirstRender = this.estimatedPageHeight === 0 && !getPageHeight;
        var allowedRect = this.allowedRect;
        var _loop_1 = function (itemIndex) {
            var pageSpecification = this_1._getPageSpecification(itemIndex, allowedRect);
            var pageHeight = pageSpecification.height;
            var pageData = pageSpecification.data;
            var key = pageSpecification.key;
            itemsPerPage = pageSpecification.itemCount;
            var pageBottom = pageTop + pageHeight - 1;
            var isPageRendered = findIndex(this_1.pages, function (page) { return !!page.items && page.startIndex === itemIndex; }) > -1;
            var isPageInAllowedRange = !allowedRect || (pageBottom >= allowedRect.top && pageTop <= allowedRect.bottom);
            var isPageInRequiredRange = !this_1.requiredRect || (pageBottom >= this_1.requiredRect.top && pageTop <= this_1.requiredRect.bottom);
            var isPageVisible = (!isFirstRender && (isPageInRequiredRange || (isPageInAllowedRange && isPageRendered))) || !shouldVirtualize;
            var isPageFocused = focusedIndex >= itemIndex && focusedIndex < itemIndex + itemsPerPage;
            var isFirstPage = itemIndex === startIndex;
            // console.log('building page', itemIndex, 'pageTop: ' + pageTop, 'inAllowed: ' +
            // isPageInAllowedRange, 'inRequired: ' + isPageInRequiredRange)
            // Only render whats visible, focused, or first page,
            // or when running in fast rendering mode (not in virtualized mode), we render all current items in pages
            if (isPageVisible || isPageFocused || isFirstPage) {
                if (currentSpacer) {
                    pages.push(currentSpacer);
                    currentSpacer = null;
                }
                var itemsInPage = Math.min(itemsPerPage, endIndex - itemIndex);
                var newPage = this_1._createPage(key, items.slice(itemIndex, itemIndex + itemsInPage), itemIndex, undefined, undefined, pageData);
                newPage.top = pageTop;
                newPage.height = pageHeight;
                if (this_1.visibleRect && this_1.visibleRect.bottom) {
                    newPage.isVisible = pageBottom >= this_1.visibleRect.top && pageTop <= this_1.visibleRect.bottom;
                }
                pages.push(newPage);
                if (isPageInRequiredRange && this_1.allowedRect) {
                    _mergeRect(materializedRect, {
                        top: pageTop,
                        bottom: pageBottom,
                        height: pageHeight,
                        left: allowedRect.left,
                        right: allowedRect.right,
                        width: allowedRect.width,
                    });
                }
            }
            else {
                if (!currentSpacer) {
                    currentSpacer = this_1._createPage(SPACER_KEY_PREFIX + itemIndex, undefined, itemIndex, 0, undefined, pageData, true /* isSpacer */);
                }
                currentSpacer.height = (currentSpacer.height || 0) + (pageBottom - pageTop) + 1;
                currentSpacer.itemCount += itemsPerPage;
            }
            pageTop += pageBottom - pageTop + 1;
            // in virtualized mode, we render need to render first page then break and measure,
            // otherwise, we render all items without measurement to make rendering fast
            if (isFirstRender && shouldVirtualize) {
                return "break";
            }
        };
        var this_1 = this;
        for (var itemIndex = startIndex; itemIndex < endIndex; itemIndex += itemsPerPage) {
            var state_1 = _loop_1(itemIndex);
            if (state_1 === "break")
                break;
        }
        if (currentSpacer) {
            currentSpacer.key = SPACER_KEY_PREFIX + 'end';
            pages.push(currentSpacer);
        }
        this.materializedRect = materializedRect;
        // console.log('materialized: ', materializedRect)
        return {
            pages: pages,
            measureVersion: this.measureVersion,
        };
    };
    List.prototype._getPageSpecification = function (itemIndex, visibleRect) {
        var getPageSpecification = this.$props.getPageSpecification;
        if (getPageSpecification) {
            var pageData = getPageSpecification(itemIndex, visibleRect);
            var _a = pageData.itemCount, itemCount = _a === void 0 ? this._getItemCountForPage(itemIndex, visibleRect) : _a;
            var _b = pageData.height, height = _b === void 0 ? this._getPageHeight(itemIndex, visibleRect, itemCount) : _b;
            return {
                itemCount: itemCount,
                height: height,
                data: pageData.data,
                key: pageData.key,
            };
        }
        else {
            var itemCount = this._getItemCountForPage(itemIndex, visibleRect);
            return {
                itemCount: itemCount,
                height: this._getPageHeight(itemIndex, visibleRect, itemCount),
            };
        }
    };
    /**
     * Get the pixel height of a give page. Will use the props getPageHeight first, and if not provided, fallback to
     * cached height, or estimated page height, or default page height.
     */
    List.prototype._getPageHeight = function (itemIndex, visibleRect, itemsPerPage) {
        if (this.getPageHeight) {
            return this.getPageHeight(itemIndex, visibleRect, itemsPerPage);
        }
        else {
            var cachedHeight = this.cachedPageHeights[itemIndex];
            return cachedHeight ? cachedHeight.height : this.estimatedPageHeight || DEFAULT_PAGE_HEIGHT;
        }
    };
    List.prototype._getItemCountForPage = function (itemIndex, visibileRect) {
        var itemsPerPage = this.getItemCountForPage ? this.getItemCountForPage(itemIndex, visibileRect) : DEFAULT_ITEMS_PER_PAGE;
        return itemsPerPage || DEFAULT_ITEMS_PER_PAGE;
    };
    /** Called when a page has been added to the DOM. */
    List.prototype._onPageAdded = function (page) {
        var onPageAdded = this.$props.onPageAdded;
        // console.log('page added', page.startIndex, this.state.pages.map(page => page.key).join(', '));
        if (onPageAdded) {
            onPageAdded(page);
        }
    };
    /** Called when a page has been removed from the DOM. */
    List.prototype._onPageRemoved = function (page) {
        var onPageRemoved = this.$props.onPageRemoved;
        // console.log('  --- page removed', page.startIndex, this.state.pages.map(page => page.key).join(', '));
        if (onPageRemoved) {
            onPageRemoved(page);
        }
    };
    /**
     * Notify consumers that the rendered pages have changed
     * @param oldPages - The old pages
     * @param newPages - The new pages
     * @param props - The props to use
     */
    List.prototype.notifyPageChanges = function (oldPages, newPages, props) {
        if (props === void 0) { props = this.$props; }
        var onPageAdded = props.onPageAdded, onPageRemoved = props.onPageRemoved;
        if (onPageAdded || onPageRemoved) {
            var renderedIndexes = {};
            for (var _i = 0, oldPages_1 = oldPages; _i < oldPages_1.length; _i++) {
                var page = oldPages_1[_i];
                if (page.items) {
                    renderedIndexes[page.startIndex] = page;
                }
            }
            for (var _a = 0, newPages_1 = newPages; _a < newPages_1.length; _a++) {
                var page = newPages_1[_a];
                if (page.items) {
                    if (!renderedIndexes[page.startIndex]) {
                        this._onPageAdded(page);
                    }
                    else {
                        delete renderedIndexes[page.startIndex];
                    }
                }
            }
            for (var index in renderedIndexes) {
                if (renderedIndexes.hasOwnProperty(index)) {
                    this._onPageRemoved(renderedIndexes[index]);
                }
            }
        }
    };
    List.prototype.updatePages = function (props) {
        // console.log('updating pages')
        if (props === void 0) { props = this.$props; }
        if (!this.requiredRect) {
            this.updateRenderRects(props);
        }
        var newListState = this._buildPages(props);
        var oldListPages = this.pages;
        this.notifyPageChanges(oldListPages, newListState.pages);
        this.measureVersion = newListState.measureVersion;
        this.pages = newListState.pages;
        // Multiple updates may have been queued, so the callback will reflect all of them.
        // Re-fetch the current props and states to avoid using a stale props or state captured in the closure.
        var finalProps = this.$props;
        var finalState = this;
        // If we weren't provided with the page height, measure the pages
        if (!finalProps.getPageHeight) {
            // If measured version is invalid since we've updated the DOM
            var heightsChanged = this.updatePageMeasurements(finalState.pages);
            // On first render, we should re-measure so that we don't get a visual glitch.
            if (heightsChanged) {
                this.materializedRect = null;
                if (!this.hasCompletedFirstRender) {
                    this.hasCompletedFirstRender = true;
                    this.updatePages(finalProps);
                }
                else {
                    this._onAsyncScroll();
                }
            }
            else {
                // Enqueue an idle bump.
                this._onAsyncIdle();
            }
        }
        else {
            // Enqueue an idle bump
            this._onAsyncIdle();
        }
        // Notify the caller that rendering the new pages has completed
        if (finalProps.onPagesUpdated) {
            finalProps.onPagesUpdated(finalState.pages);
        }
    };
    List.prototype.updatePageMeasurements = function (pages) {
        var heightChanged = false;
        // when not in virtualize mode, we render all the items without page measurement
        if (!this.shouldVirtualize()) {
            return heightChanged;
        }
        for (var i = 0; i < pages.length; i++) {
            var page = pages[i];
            if (page.items) {
                heightChanged = this.measurePage(page) || heightChanged;
            }
        }
        return heightChanged;
    };
    /**
     * Given a page, measure its dimensions, update cache.
     * @returns True if the height has changed.
     */
    List.prototype.measurePage = function (page) {
        var hasChangedHeight = false;
        // @ts-ignore
        var pageElement = this.$refs[page.key] ? this.$refs[page.key][0] : null;
        var cachedHeight = this.cachedPageHeights[page.startIndex];
        // console.log('   * measure attempt', page.startIndex, cachedHeight)
        if (pageElement && this.shouldVirtualize() && (!cachedHeight || cachedHeight.measureVersion !== this.measureVersion)) {
            var newClientRect = {
                width: pageElement.clientWidth,
                height: pageElement.clientHeight,
            };
            if (newClientRect.height || newClientRect.width) {
                hasChangedHeight = page.height !== newClientRect.height;
                // console.warn(' *** expensive page measure', page.startIndex, page.height, newClientRect.height);
                page.height = newClientRect.height;
                this.cachedPageHeights[page.startIndex] = {
                    height: newClientRect.height,
                    measureVersion: this.measureVersion,
                };
                this.estimatedPageHeight = Math.round((this.estimatedPageHeight * this.totalEstimates + newClientRect.height) / (this.totalEstimates + 1));
                this.totalEstimates++;
            }
        }
        return hasChangedHeight;
    };
    List.prototype._createPage = function (pageKey, items, startIndex, count, style, data, isSpacer) {
        if (startIndex === void 0) { startIndex = -1; }
        if (count === void 0) { count = items ? items.length : 0; }
        if (style === void 0) { style = {}; }
        pageKey = pageKey || PAGE_KEY_PREFIX + startIndex;
        var cachedPage = this.pageCache[pageKey];
        if (cachedPage && cachedPage.page) {
            return cachedPage.page;
        }
        return {
            key: pageKey,
            startIndex: startIndex,
            itemCount: count,
            items: items,
            style: style,
            top: 0,
            height: 0,
            data: data,
            isSpacer: isSpacer || false,
        };
    };
    List.prototype._getRenderCount = function (props) {
        var _a = props || this.$props, items = _a.items, startIndex = _a.startIndex, renderCount = _a.renderCount;
        return renderCount === undefined ? (items ? items.length - startIndex : 0) : renderCount;
    };
    List.prototype.shouldVirtualize = function (props) {
        if (props === void 0) { props = this.$props; }
        var onShouldVirtualize = this.$props.onShouldVirtualize;
        return !onShouldVirtualize || onShouldVirtualize(props);
    };
    /** Calculate the visible rect within the list where top: 0 and left: 0 is the top/left of the list. */
    List.prototype.updateRenderRects = function (props, forceUpdate) {
        props = props || this.$props;
        var renderedWindowsAhead = props.renderedWindowsAhead, renderedWindowsBehind = props.renderedWindowsBehind;
        var pages = this.pages;
        // when not in virtualize mode, we render all items without measurement to optimize page rendering perf
        if (!this.shouldVirtualize(props)) {
            return;
        }
        var surfaceRect = this.surfaceRect || __assign({}, EMPTY_RECT);
        var scrollHeight = this.scrollElement && this.scrollElement.scrollHeight;
        var scrollTop = this.scrollElement ? this.scrollElement.scrollTop : 0;
        // WARNING: EXPENSIVE CALL! We need to know the surface top relative to the window.
        // This needs to be called to recalculate when new pages should be loaded.
        // We check to see how far we've scrolled and if it's further than a third of a page we run it again.
        if (this.$refs.surface &&
            (forceUpdate ||
                !pages ||
                !this.surfaceRect ||
                !scrollHeight ||
                scrollHeight !== this.scrollHeight ||
                Math.abs(this.scrollTop - scrollTop) > this.estimatedPageHeight / 3)) {
            surfaceRect = this.surfaceRect = _measureSurfaceRect(this.$refs.surface);
            this.scrollTop = scrollTop;
        }
        // If the scroll height has changed, something in the container likely resized and
        // we should redo the page heights incase their content resized.
        if (forceUpdate || !scrollHeight || scrollHeight !== this.scrollHeight) {
            this.measureVersion++;
        }
        this.scrollHeight = scrollHeight;
        // If the surface is above the container top or below the container bottom, or if this is not the first
        // render return empty rect.
        // The first time the list gets rendered we need to calculate the rectangle. The width of the list is
        // used to calculate the width of the list items.
        var visibleTop = Math.max(0, -surfaceRect.top);
        var win = getWindow(this.$refs.root);
        var visibleRect = {
            top: visibleTop,
            left: surfaceRect.left,
            bottom: visibleTop + win.innerHeight,
            right: surfaceRect.right,
            width: surfaceRect.width,
            height: win.innerHeight,
        };
        // The required/allowed rects are adjusted versions of the visible rect.
        this.requiredRect = _expandRect(visibleRect, this.requiredWindowsBehind, this.requiredWindowsAhead);
        this.allowedRect = _expandRect(visibleRect, renderedWindowsBehind, renderedWindowsAhead);
        // store the visible rect for later use.
        this.visibleRect = visibleRect;
    };
    __decorate([
        Prop({ type: Array, required: true }),
        __metadata("design:type", Object)
    ], List.prototype, "items", void 0);
    __decorate([
        Prop({ type: Function, default: null }),
        __metadata("design:type", Function)
    ], List.prototype, "getItemCountForPage", void 0);
    __decorate([
        Prop({ type: Function, default: null }),
        __metadata("design:type", Function)
    ], List.prototype, "getPageHeight", void 0);
    __decorate([
        Prop({ type: Number, default: DEFAULT_RENDERED_WINDOWS_AHEAD }),
        __metadata("design:type", Number)
    ], List.prototype, "renderedWindowsAhead", void 0);
    __decorate([
        Prop({ type: Number, default: DEFAULT_RENDERED_WINDOWS_BEHIND }),
        __metadata("design:type", Number)
    ], List.prototype, "renderedWindowsBehind", void 0);
    __decorate([
        Prop({ type: Number, default: 0 }),
        __metadata("design:type", Number)
    ], List.prototype, "startIndex", void 0);
    __decorate([
        Prop({ type: Boolean, default: false }),
        __metadata("design:type", Boolean)
    ], List.prototype, "ignoreScrollingState", void 0);
    __decorate([
        Watch('items'),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object, Object]),
        __metadata("design:returntype", void 0)
    ], List.prototype, "itemsChanged", null);
    __decorate([
        Watch('isScrolling'),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Boolean, Boolean]),
        __metadata("design:returntype", void 0)
    ], List.prototype, "shouldUpdate", null);
    List = __decorate([
        Component({
            components: {},
        })
    ], List);
    return List;
}(BaseComponent));
export { List };
function _expandRect(rect, pagesBefore, pagesAfter) {
    var top = rect.top - pagesBefore * rect.height;
    var height = rect.height + (pagesBefore + pagesAfter) * rect.height;
    return {
        top: top,
        bottom: top + height,
        height: height,
        left: rect.left,
        right: rect.right,
        width: rect.width,
    };
}
function _isContainedWithin(innerRect, outerRect) {
    return (innerRect.top >= outerRect.top &&
        innerRect.left >= outerRect.left &&
        innerRect.bottom <= outerRect.bottom &&
        innerRect.right <= outerRect.right);
}
function _mergeRect(targetRect, newRect) {
    targetRect.top = newRect.top < targetRect.top || targetRect.top === -1 ? newRect.top : targetRect.top;
    targetRect.left = newRect.left < targetRect.left || targetRect.left === -1 ? newRect.left : targetRect.left;
    targetRect.bottom = newRect.bottom > targetRect.bottom || targetRect.bottom === -1 ? newRect.bottom : targetRect.bottom;
    targetRect.right = newRect.right > targetRect.right || targetRect.right === -1 ? newRect.right : targetRect.right;
    targetRect.width = targetRect.right - targetRect.left + 1;
    targetRect.height = targetRect.bottom - targetRect.top + 1;
    return targetRect;
}
//# sourceMappingURL=List.js.map