react-resize-detector
Version:
React resize detector
303 lines (296 loc) • 14.9 kB
JavaScript
;Object.defineProperty(exports,'__esModule',{value:true});var React=require('react'),reactDom=require('react-dom'),debounce=require('lodash.debounce'),throttle=require('lodash.throttle');function _interopDefaultLegacy(e){return e&&typeof e==='object'&&'default'in e?e:{'default':e}}var React__default=/*#__PURE__*/_interopDefaultLegacy(React);var debounce__default=/*#__PURE__*/_interopDefaultLegacy(debounce);var throttle__default=/*#__PURE__*/_interopDefaultLegacy(throttle);/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}var patchResizeHandler = function (resizeCallback, refreshMode, refreshRate, refreshOptions) {
switch (refreshMode) {
case 'debounce':
return debounce__default['default'](resizeCallback, refreshRate, refreshOptions);
case 'throttle':
return throttle__default['default'](resizeCallback, refreshRate, refreshOptions);
default:
return resizeCallback;
}
};
var isFunction = function (fn) { return typeof fn === 'function'; };
var isSSR = function () { return typeof window === 'undefined'; };
var isDOMElement = function (element) { return element instanceof Element || element instanceof HTMLDocument; };
var createNotifier = function (onResize, setSize, handleWidth, handleHeight) { return function (_a) {
var width = _a.width, height = _a.height;
setSize(function (prev) {
if (prev.width === width && prev.height === height) {
// skip if dimensions haven't changed
return prev;
}
if ((prev.width === width && !handleHeight) || (prev.height === height && !handleWidth)) {
// process `handleHeight/handleWidth` props
return prev;
}
if (onResize && isFunction(onResize)) {
onResize(width, height);
}
return { width: width, height: height };
});
}; };var ResizeDetector = /** @class */ (function (_super) {
__extends(ResizeDetector, _super);
function ResizeDetector(props) {
var _this = _super.call(this, props) || this;
_this.cancelHandler = function () {
if (_this.resizeHandler && _this.resizeHandler.cancel) {
// cancel debounced handler
_this.resizeHandler.cancel();
_this.resizeHandler = null;
}
};
_this.attachObserver = function () {
var targetRef = _this.props.targetRef;
if (isSSR()) {
return;
}
if (targetRef && targetRef.current) {
_this.targetRef.current = targetRef.current;
}
var element = _this.getElement();
if (!element) {
// can't find element to observe
return;
}
if (_this.observableElement && _this.observableElement === element) {
// element is already observed
return;
}
_this.observableElement = element;
_this.resizeObserver.observe(element);
};
_this.getElement = function () {
var _a = _this.props, querySelector = _a.querySelector, targetDomEl = _a.targetDomEl;
if (isSSR())
return null;
// in case we pass a querySelector
if (querySelector)
return document.querySelector(querySelector);
// in case we pass a DOM element
if (targetDomEl && isDOMElement(targetDomEl))
return targetDomEl;
// in case we pass a React ref using React.createRef()
if (_this.targetRef && isDOMElement(_this.targetRef.current))
return _this.targetRef.current;
// the worse case when we don't receive any information from the parent and the library doesn't add any wrappers
// we have to use a deprecated `findDOMNode` method in order to find a DOM element to attach to
var currentElement = reactDom.findDOMNode(_this);
if (!currentElement)
return null;
var renderType = _this.getRenderType();
switch (renderType) {
case 'renderProp':
return currentElement;
case 'childFunction':
return currentElement;
case 'child':
return currentElement;
case 'childArray':
return currentElement;
default:
return currentElement.parentElement;
}
};
_this.createResizeHandler = function (entries) {
var _a = _this.props, _b = _a.handleWidth, handleWidth = _b === void 0 ? true : _b, _c = _a.handleHeight, handleHeight = _c === void 0 ? true : _c, onResize = _a.onResize;
if (!handleWidth && !handleHeight)
return;
var notifyResize = createNotifier(onResize, _this.setState.bind(_this), handleWidth, handleHeight);
entries.forEach(function (entry) {
var _a = (entry && entry.contentRect) || {}, width = _a.width, height = _a.height;
var shouldSetSize = !_this.skipOnMount && !isSSR();
if (shouldSetSize) {
notifyResize({ width: width, height: height });
}
_this.skipOnMount = false;
});
};
_this.getRenderType = function () {
var _a = _this.props, render = _a.render, children = _a.children;
if (isFunction(render)) {
// DEPRECATED. Use `Child Function Pattern` instead
return 'renderProp';
}
if (isFunction(children)) {
return 'childFunction';
}
if (React.isValidElement(children)) {
return 'child';
}
if (Array.isArray(children)) {
// DEPRECATED. Wrap children with a single parent
return 'childArray';
}
// DEPRECATED. Use `Child Function Pattern` instead
return 'parent';
};
var skipOnMount = props.skipOnMount, refreshMode = props.refreshMode, _a = props.refreshRate, refreshRate = _a === void 0 ? 1000 : _a, refreshOptions = props.refreshOptions;
_this.state = {
width: undefined,
height: undefined
};
_this.skipOnMount = skipOnMount;
_this.targetRef = React.createRef();
_this.observableElement = null;
if (isSSR()) {
return _this;
}
_this.resizeHandler = patchResizeHandler(_this.createResizeHandler, refreshMode, refreshRate, refreshOptions);
_this.resizeObserver = new window.ResizeObserver(_this.resizeHandler);
return _this;
}
ResizeDetector.prototype.componentDidMount = function () {
this.attachObserver();
};
ResizeDetector.prototype.componentDidUpdate = function () {
this.attachObserver();
};
ResizeDetector.prototype.componentWillUnmount = function () {
if (isSSR()) {
return;
}
this.resizeObserver.disconnect();
this.cancelHandler();
};
ResizeDetector.prototype.render = function () {
var _a = this.props, render = _a.render, children = _a.children, _b = _a.nodeType, WrapperTag = _b === void 0 ? 'div' : _b;
var _c = this.state, width = _c.width, height = _c.height;
var childProps = { width: width, height: height, targetRef: this.targetRef };
var renderType = this.getRenderType();
var typedChildren;
switch (renderType) {
case 'renderProp':
return render && render(childProps);
case 'childFunction':
typedChildren = children;
return typedChildren(childProps);
case 'child':
// @TODO bug prone logic
typedChildren = children;
if (typedChildren.type && typeof typedChildren.type === 'string') {
// child is a native DOM elements such as div, span etc
var nativeProps = __rest(childProps, ["targetRef"]);
return React.cloneElement(typedChildren, nativeProps);
}
// class or functional component otherwise
return React.cloneElement(typedChildren, childProps);
case 'childArray':
typedChildren = children;
return typedChildren.map(function (el) { return !!el && React.cloneElement(el, childProps); });
default:
return React__default['default'].createElement(WrapperTag, null);
}
};
return ResizeDetector;
}(React.PureComponent));function withResizeDetector(ComponentInner, options) {
var ResizeDetectorHOC = /** @class */ (function (_super) {
__extends(ResizeDetectorHOC, _super);
function ResizeDetectorHOC() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.ref = React.createRef();
return _this;
}
ResizeDetectorHOC.prototype.render = function () {
var _a = this.props, forwardedRef = _a.forwardedRef, rest = __rest(_a, ["forwardedRef"]);
var targetRef = forwardedRef || this.ref;
return (React__default['default'].createElement(ResizeDetector, __assign({}, options, { targetRef: targetRef }),
React__default['default'].createElement(ComponentInner, __assign({ targetRef: targetRef }, rest))));
};
return ResizeDetectorHOC;
}(React.Component));
function forwardRefWrapper(props, ref) {
return React__default['default'].createElement(ResizeDetectorHOC, __assign({}, props, { forwardedRef: ref }));
}
var name = ComponentInner.displayName || ComponentInner.name;
forwardRefWrapper.displayName = "withResizeDetector(" + name + ")";
return React.forwardRef(forwardRefWrapper);
}function useResizeDetector(props) {
if (props === void 0) { props = {}; }
var _a = props.skipOnMount, skipOnMount = _a === void 0 ? false : _a, refreshMode = props.refreshMode, _b = props.refreshRate, refreshRate = _b === void 0 ? 1000 : _b, refreshOptions = props.refreshOptions, _c = props.handleWidth, handleWidth = _c === void 0 ? true : _c, _d = props.handleHeight, handleHeight = _d === void 0 ? true : _d, targetRef = props.targetRef, onResize = props.onResize;
var skipResize = React.useRef(null);
var ref = targetRef || React.useRef(null);
var resizeHandler = React.useRef(null);
React.useEffect(function () {
if (skipResize.current === null) {
skipResize.current = skipOnMount;
}
}, [skipOnMount]);
var _e = React.useState({
width: undefined,
height: undefined
}), size = _e[0], setSize = _e[1];
React.useEffect(function () {
if (isSSR()) {
return;
}
var notifyResize = createNotifier(onResize, setSize, handleWidth, handleHeight);
var resizeCallback = function (entries) {
if (!handleWidth && !handleHeight)
return;
entries.forEach(function (entry) {
var _a = (entry && entry.contentRect) || {}, width = _a.width, height = _a.height;
var shouldSetSize = !skipResize.current && !isSSR();
if (shouldSetSize) {
notifyResize({ width: width, height: height });
}
skipResize.current = false;
});
};
resizeHandler.current = patchResizeHandler(resizeCallback, refreshMode, refreshRate, refreshOptions);
var resizeObserver = new window.ResizeObserver(resizeHandler.current);
if (ref.current) {
resizeObserver.observe(ref.current);
}
return function () {
resizeObserver.disconnect();
var patchedResizeHandler = resizeHandler.current;
if (patchedResizeHandler && patchedResizeHandler.cancel) {
patchedResizeHandler.cancel();
}
};
}, [refreshMode, refreshRate, refreshOptions, handleWidth, handleHeight, onResize]);
return __assign({ ref: ref }, size);
}exports.default=ResizeDetector;exports.useResizeDetector=useResizeDetector;exports.withResizeDetector=withResizeDetector;//# sourceMappingURL=index.js.map