UNPKG

react-resize-reporter

Version:

Lightweight React Component that reports width and height changes when its parent resizes.

122 lines 4.98 kB
import React, { PureComponent } from 'react'; import { checkParent } from './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 */ export class ResizeReporter extends PureComponent { constructor() { super(...arguments); this.containerRef = React.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') { 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.createElement("div", Object.assign({ "aria-hidden": true, "aria-label": "react-resize-reporter", tabIndex: -1 }, restProps, { ref: this.containerRef }), React.createElement("div", { style: scrollerStyles, onScroll: this.onScroll }, React.createElement("div", { style: expandDetectorStyles })), React.createElement("div", { style: scrollerStyles, onScroll: this.onScroll }, React.createElement("div", { style: shrinkDetectorStyles })), children)); } } export default ResizeReporter; //# sourceMappingURL=scroll.js.map