From 74f0e7fae7f7d1f7b1c7c2d3814b76e4a3d9a38e Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Wed, 7 Oct 2020 16:36:03 -0400 Subject: [PATCH] fix(minHeight): issues/403 resize events reset height (#447) --- .../minHeight/__tests__/minHeight.test.js | 50 ++++++++++++++++- src/components/minHeight/minHeight.js | 56 ++++++++++++++++++- 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/components/minHeight/__tests__/minHeight.test.js b/src/components/minHeight/__tests__/minHeight.test.js index 007a63c09..b4649881d 100644 --- a/src/components/minHeight/__tests__/minHeight.test.js +++ b/src/components/minHeight/__tests__/minHeight.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { mount, shallow } from 'enzyme'; import { MinHeight } from '../minHeight'; describe('MinHeight Component', () => { @@ -32,4 +32,52 @@ describe('MinHeight Component', () => { component.setProps({ autoUpdate: false, minHeight: 300 }); expect(component.instance().updatedMinHeight).toEqual(200); }); + + it('should set minHeight on resize', () => { + const props = {}; + const component = shallow(lorem ipsum); + + expect(component.instance().onResizeContainer).toBeDefined(); + + // initial height and width should be zero + expect(component.instance().updatedMinHeight).toEqual(0); + expect(component.instance().updatedContainerWidth).toEqual(0); + + // set the container size arbitrarily and force handleResize to fire + component.instance().containerRef.current = { clientHeight: 100, clientWidth: 200 }; + global.dispatchEvent(new Event('resize')); + expect(component.instance().updatedMinHeight).toEqual(100); + expect(component.instance().updatedContainerWidth).toEqual(200); + + // set the container size arbitrarily and force handleResize to fire + component.instance().containerRef.current = { clientHeight: 1000, clientWidth: 1337 }; + global.dispatchEvent(new Event('resize')); + expect(component.instance().updatedMinHeight).toEqual(1000); + expect(component.instance().updatedContainerWidth).toEqual(1337); + }); + + it('should attempt to handle a ResizeObserver', () => { + const observe = jest.fn(); + const unobserve = jest.fn(); + + window.ResizeObserver = jest.fn().mockImplementation(() => ({ + observe, + unobserve + })); + + const props = {}; + const component = mount(lorem ipsum); + expect(observe).toHaveBeenCalledTimes(1); + + component.unmount(); + expect(unobserve).toHaveBeenCalledTimes(1); + }); + + it('should run componentWillUnmount method successfully', () => { + const props = {}; + const component = mount(lorem ipsum); + const componentWillUnmount = jest.spyOn(component.instance(), 'componentWillUnmount'); + component.unmount(); + expect(componentWillUnmount).toHaveBeenCalled(); + }); }); diff --git a/src/components/minHeight/minHeight.js b/src/components/minHeight/minHeight.js index f1ec83cd2..cc7263cf7 100644 --- a/src/components/minHeight/minHeight.js +++ b/src/components/minHeight/minHeight.js @@ -1,18 +1,25 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { helpers } from '../../common'; /** * Set a min-height to prevent page jump component. * * @augments React.Component + * @fires onResizeContainer */ class MinHeight extends React.Component { containerRef = React.createRef(); updatedMinHeight = 0; + updatedContainerWidth = 0; + + resizeObserver = helpers.noop; + componentDidMount() { this.setMinHeight(); + this.setResizeObserver(); } componentDidUpdate() { @@ -23,14 +30,40 @@ class MinHeight extends React.Component { } } + componentWillUnmount() { + this.resizeObserver(); + } + + /** + * On resize adjust graph display. + * + * @event onResizeContainer + */ + onResizeContainer = () => { + const { updatedContainerWidth } = this; + const clientWidth = this.containerRef?.current?.clientWidth || 0; + + if (clientWidth !== updatedContainerWidth) { + this.updatedContainerWidth = clientWidth; + this.setMinHeight(true); + } + }; + /** * Set minHeight on mount or update. + * + * @param {boolean} resetMinHeight */ - setMinHeight() { + setMinHeight(resetMinHeight) { const { updatedMinHeight } = this; const { minHeight: overrideMinHeight } = this.props; - // const { clientHeight = 0 } = this.containerRef.current || {}; - const clientHeight = this.containerRef?.current?.clientHeight || 0; + const { current: domElement = {} } = this.containerRef; + + if (resetMinHeight && domElement.style) { + domElement.style.minHeight = 0; + } + + const clientHeight = domElement?.clientHeight || 0; if (clientHeight !== updatedMinHeight) { this.updatedMinHeight = clientHeight; @@ -41,6 +74,23 @@ class MinHeight extends React.Component { } } + /** + * Set ResizeObserver for scenarios when min-height needs to be updated. + */ + setResizeObserver() { + const containerElement = this.containerRef.current; + const { ResizeObserver } = window; + + if (containerElement && ResizeObserver) { + const resizeObserver = new ResizeObserver(this.onResizeContainer); + resizeObserver.observe(containerElement); + this.resizeObserver = () => resizeObserver.unobserve(containerElement); + } else { + window.addEventListener('resize', this.onResizeContainer); + this.resizeObserver = () => window.removeEventListener('resize', this.onResizeContainer); + } + } + /** * Render a min-height div with children. *