react-resize-reporter
Version:
Lightweight React Component that reports width and height changes when its parent resizes.
145 lines • 6.06 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResizeReporter = void 0;
const react_1 = __importStar(require("react"));
const check_parent_1 = require("./check-parent");
const scrollerStyles = {
overflow: 'hidden',
position: 'absolute',
zIndex: -1000,
top: 0,
right: 0,
width: '100%',
height: '100%',
opacity: 0,
pointerEvents: 'none'
};
const expandDetectorStyles = {
transition: '0s',
animation: 'none'
};
const shrinkDetectorStyles = {
transition: '0s',
animation: 'none',
width: '250%',
height: '250%'
};
/**
* Scroll event based resize detector
*/
class ResizeReporter extends react_1.PureComponent {
constructor() {
super(...arguments);
this.containerRef = react_1.default.createRef();
this.lastWidth = -1;
this.lastHeight = -1;
this.resetPosition = (container, newWidth, newHeight) => {
const $expand = container.firstChild;
const $shrink = $expand.nextSibling;
// ensure expand detector can scroll
// shrink detector uses percentage so it will always be able to scroll
const $expandDetector = $expand.firstChild;
$expandDetector.style.width = newWidth + 1000 + 'px';
$expandDetector.style.height = newHeight + 1000 + 'px';
// after styles are applied
this._setScrollPositionTicket = window.setTimeout(() => {
$expand.scrollLeft = newWidth + 1000;
$expand.scrollTop = newHeight + 1000;
$shrink.scrollLeft = newWidth * 2.5;
$shrink.scrollTop = newHeight * 2.5;
}, 0);
};
this.checkSize = () => {
if (this.containerRef.current) {
const parent = this.containerRef.current.parentElement;
if (parent) {
const newRect = parent.getBoundingClientRect();
const { width: newWidth, height: newHeight } = newRect;
if (this.props.onSizeChanged) {
if (newWidth !== this.lastWidth || newHeight !== this.lastHeight) {
this.props.onSizeChanged(newWidth, newHeight, newRect);
}
}
if (this.props.onWidthChanged && newWidth !== this.lastWidth) {
this.props.onWidthChanged(newWidth, newRect);
}
if (this.props.onHeightChanged && newHeight !== this.lastHeight) {
this.props.onHeightChanged(newHeight, newRect);
}
this.resetPosition(this.containerRef.current, newWidth, newHeight);
this.lastWidth = newWidth;
this.lastHeight = newHeight;
}
}
};
this.onScroll = () => {
if (this._debounceTicket) {
window.clearTimeout(this._debounceTicket);
this._debounceTicket = null;
}
// height and width scrolling happens on next loop
// add timeout even for 0
this._debounceTicket = window.setTimeout(this.checkSize, this.props.debounce || 0);
};
}
componentDidMount() {
if (this.containerRef.current) {
const parent = this.containerRef.current.parentElement;
if (process.env.NODE_ENV !== 'production') {
check_parent_1.checkParent(parent);
}
if (parent) {
if (this.props.reportInit) {
this.checkSize();
}
else {
const rect = parent.getBoundingClientRect();
this.lastWidth = rect.width;
this.lastHeight = rect.height;
this.resetPosition(this.containerRef.current, this.lastWidth, this.lastHeight);
}
}
}
}
componentWillUnmount() {
if (this._debounceTicket) {
window.clearTimeout(this._debounceTicket);
this._debounceTicket = null;
}
if (this._setScrollPositionTicket) {
window.clearTimeout(this._setScrollPositionTicket);
this._setScrollPositionTicket = null;
}
}
render() {
const { reportInit, debounce, onSizeChanged, onWidthChanged, onHeightChanged, children, ...restProps } = this.props;
return (react_1.default.createElement("div", Object.assign({ "aria-hidden": true, "aria-label": "react-resize-reporter", tabIndex: -1 }, restProps, { ref: this.containerRef }),
react_1.default.createElement("div", { style: scrollerStyles, onScroll: this.onScroll },
react_1.default.createElement("div", { style: expandDetectorStyles })),
react_1.default.createElement("div", { style: scrollerStyles, onScroll: this.onScroll },
react_1.default.createElement("div", { style: shrinkDetectorStyles })),
children));
}
}
exports.ResizeReporter = ResizeReporter;
exports.default = ResizeReporter;
//# sourceMappingURL=scroll.js.map