office-ui-fabric-react
Version:
Reusable React components for building experiences for Microsoft 365.
139 lines • 6.56 kB
JavaScript
import { __assign, __extends } from "tslib";
import * as React from 'react';
import { BaseDecorator } from './BaseDecorator';
import { findScrollableParent, getRect, getWindow, Async, EventGroup } from '../../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.
*/
export function withViewport(ComposedComponent) {
return /** @class */ (function (_super) {
__extends(WithViewportComponent, _super);
function WithViewportComponent(props) {
var _this = _super.call(this, props) || this;
_this._root = React.createRef();
_this._registerResizeObserver = function () {
var win = 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 = 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._async = new Async(_this);
_this._events = new EventGroup(_this);
_this._resizeAttempts = 0;
_this.state = {
viewport: {
width: 0,
height: 0,
},
};
return _this;
}
WithViewportComponent.prototype.componentDidMount = function () {
var _this = this;
var _a = this.props, delayFirstMeasure = _a.delayFirstMeasure, disableResizeObserver = _a.disableResizeObserver, skipViewportMeasures = _a.skipViewportMeasures;
var win = 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);
}
if (delayFirstMeasure) {
this._async.setTimeout(function () {
_this._updateViewport();
}, RESIZE_DELAY);
}
else {
this._updateViewport();
}
}
};
WithViewportComponent.prototype.componentDidUpdate = function (previousProps) {
var previousSkipViewportMeasures = previousProps.skipViewportMeasures;
var _a = this.props, disableResizeObserver = _a.disableResizeObserver, skipViewportMeasures = _a.skipViewportMeasures;
var win = 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, __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 = getWindow(this._root.current);
return win && win.ResizeObserver;
};
return WithViewportComponent;
}(BaseDecorator));
}
//# sourceMappingURL=withViewport.js.map