office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
94 lines • 4.76 kB
JavaScript
import * as tslib_1 from "tslib";
import * as React from 'react';
import { BaseDecorator } from './BaseDecorator';
import { findScrollableParent, getRect, createRef, getWindow } from '../../Utilities';
var RESIZE_DELAY = 500;
var MAX_RESIZE_ATTEMPTS = 3;
export function withViewport(ComposedComponent) {
return /** @class */ (function (_super) {
tslib_1.__extends(WithViewportComponent, _super);
function WithViewportComponent(props) {
var _this = _super.call(this, props) || this;
_this._root = createRef();
/* 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 = findScrollableParent(viewportElement);
var scrollRect = getRect(scrollElement);
var clientRect = 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._resizeAttempts = 0;
_this.state = {
viewport: {
width: 0,
height: 0
}
};
return _this;
}
WithViewportComponent.prototype.componentDidMount = function () {
var skipViewportMeasures = this.props.skipViewportMeasures;
this._onAsyncResize = this._async.debounce(this._onAsyncResize, RESIZE_DELAY, {
leading: false
});
var window = getWindow();
var viewportElement = this._root.current;
// ResizeObserver seems always fire even window is not resized. This is
// particularly bad when skipViewportMeasures is set when optimizing fixed layout lists.
// It will measure and update and re-render the entire list after list is fully rendered.
// So fallback to listen to resize event when skipViewportMeasures is set.
if (!skipViewportMeasures && window && window.ResizeObserver) {
this._viewportResizeObserver = new window.ResizeObserver(this._onAsyncResize);
this._viewportResizeObserver.observe(viewportElement);
}
else {
this._events.on(window, 'resize', this._onAsyncResize);
}
if (!skipViewportMeasures) {
this._updateViewport();
}
};
WithViewportComponent.prototype.componentWillUnmount = function () {
this._events.dispose();
if (this._viewportResizeObserver) {
this._viewportResizeObserver.disconnect();
}
};
WithViewportComponent.prototype.render = function () {
var viewport = this.state.viewport;
var skipViewportMeasures = this.props.skipViewportMeasures;
var isViewportVisible = skipViewportMeasures || (viewport.width > 0 && viewport.height > 0);
return (React.createElement("div", { className: "ms-Viewport", ref: this._root, style: { minWidth: 1, minHeight: 1 } }, isViewportVisible && (React.createElement(ComposedComponent, tslib_1.__assign({ ref: this._updateComposedComponentRef, viewport: viewport }, this.props)))));
};
WithViewportComponent.prototype.forceUpdate = function () {
this._updateViewport(true);
};
WithViewportComponent.prototype._onAsyncResize = function () {
this._updateViewport();
};
return WithViewportComponent;
}(BaseDecorator));
}
//# sourceMappingURL=withViewport.js.map