"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = require("react");
var BaseDecorator_1 = require("./BaseDecorator");
var Utilities_1 = require("../../Utilities");
var RESIZE_DELAY = 500;
var MAX_RESIZE_ATTEMPTS = 3;
/**
 * A decorator to update decorated component on viewport or window resize events.
 *
 * @param ComposedComponent decorated React component reference.
 */
function withViewport(ComposedComponent) {
    return /** @class */ (function (_super) {
        tslib_1.__extends(WithViewportComponent, _super);
        function WithViewportComponent(props) {
            var _this = _super.call(this, props) || this;
            _this._root = React.createRef();
            _this._registerResizeObserver = function () {
                var win = Utilities_1.getWindow(_this._root.current);
                _this._viewportResizeObserver = new win.ResizeObserver(_this._onAsyncResize);
                _this._viewportResizeObserver.observe(_this._root.current);
            };
            _this._unregisterResizeObserver = function () {
                if (_this._viewportResizeObserver) {
                    _this._viewportResizeObserver.disconnect();
                    delete _this._viewportResizeObserver;
                }
            };
            /* Note: using lambda here because decorators don't seem to work in decorators. */
            _this._updateViewport = function (withForceUpdate) {
                var viewport = _this.state.viewport;
                var viewportElement = _this._root.current;
                var scrollElement = Utilities_1.findScrollableParent(viewportElement);
                var scrollRect = Utilities_1.getRect(scrollElement);
                var clientRect = Utilities_1.getRect(viewportElement);
                var updateComponent = function () {
                    if (withForceUpdate && _this._composedComponentInstance) {
                        _this._composedComponentInstance.forceUpdate();
                    }
                };
                var isSizeChanged = (clientRect && clientRect.width) !== viewport.width || (scrollRect && scrollRect.height) !== viewport.height;
                if (isSizeChanged && _this._resizeAttempts < MAX_RESIZE_ATTEMPTS && clientRect && scrollRect) {
                    _this._resizeAttempts++;
                    _this.setState({
                        viewport: {
                            width: clientRect.width,
                            height: scrollRect.height,
                        },
                    }, function () {
                        _this._updateViewport(withForceUpdate);
                    });
                }
                else {
                    _this._resizeAttempts = 0;
                    updateComponent();
                }
            };
            _this._async = new Utilities_1.Async(_this);
            _this._events = new Utilities_1.EventGroup(_this);
            _this._resizeAttempts = 0;
            _this.state = {
                viewport: {
                    width: 0,
                    height: 0,
                },
            };
            return _this;
        }
        WithViewportComponent.prototype.componentDidMount = function () {
            var _a = this.props, skipViewportMeasures = _a.skipViewportMeasures, disableResizeObserver = _a.disableResizeObserver;
            var win = Utilities_1.getWindow(this._root.current);
            this._onAsyncResize = this._async.debounce(this._onAsyncResize, RESIZE_DELAY, {
                leading: false,
            });
            if (!skipViewportMeasures) {
                if (!disableResizeObserver && this._isResizeObserverAvailable()) {
                    this._registerResizeObserver();
                }
                else {
                    this._events.on(win, 'resize', this._onAsyncResize);
                }
                this._updateViewport();
            }
        };
        WithViewportComponent.prototype.componentDidUpdate = function (previousProps) {
            var previousSkipViewportMeasures = previousProps.skipViewportMeasures;
            var _a = this.props, skipViewportMeasures = _a.skipViewportMeasures, disableResizeObserver = _a.disableResizeObserver;
            var win = Utilities_1.getWindow(this._root.current);
            if (skipViewportMeasures !== previousSkipViewportMeasures) {
                if (!skipViewportMeasures) {
                    if (!disableResizeObserver && this._isResizeObserverAvailable()) {
                        if (!this._viewportResizeObserver) {
                            this._registerResizeObserver();
                        }
                    }
                    else {
                        this._events.on(win, 'resize', this._onAsyncResize);
                    }
                    this._updateViewport();
                }
                else {
                    this._unregisterResizeObserver();
                    this._events.off(win, 'resize', this._onAsyncResize);
                }
            }
        };
        WithViewportComponent.prototype.componentWillUnmount = function () {
            this._events.dispose();
            this._async.dispose();
            this._unregisterResizeObserver();
        };
        WithViewportComponent.prototype.render = function () {
            var viewport = this.state.viewport;
            var newViewport = viewport.width > 0 && viewport.height > 0 ? viewport : undefined;
            return (React.createElement("div", { className: "ms-Viewport", ref: this._root, style: { minWidth: 1, minHeight: 1 } },
                React.createElement(ComposedComponent, tslib_1.__assign({ ref: this._updateComposedComponentRef, viewport: newViewport }, this.props))));
        };
        WithViewportComponent.prototype.forceUpdate = function () {
            this._updateViewport(true);
        };
        WithViewportComponent.prototype._onAsyncResize = function () {
            this._updateViewport();
        };
        WithViewportComponent.prototype._isResizeObserverAvailable = function () {
            var win = Utilities_1.getWindow(this._root.current);
            return win && win.ResizeObserver;
        };
        return WithViewportComponent;
    }(BaseDecorator_1.BaseDecorator));
}
exports.withViewport = withViewport;
//# sourceMappingURL=withViewport.js.map