diff --git a/src/components/minHeight/__tests__/__snapshots__/minHeight.test.js.snap b/src/components/minHeight/__tests__/__snapshots__/minHeight.test.js.snap new file mode 100644 index 000000000..563a10f6f --- /dev/null +++ b/src/components/minHeight/__tests__/__snapshots__/minHeight.test.js.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MinHeight Component should render a non-connected component: non-connected 1`] = ` +
+ lorem ipsum +
+`; diff --git a/src/components/minHeight/__tests__/minHeight.test.js b/src/components/minHeight/__tests__/minHeight.test.js new file mode 100644 index 000000000..007a63c09 --- /dev/null +++ b/src/components/minHeight/__tests__/minHeight.test.js @@ -0,0 +1,35 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { MinHeight } from '../minHeight'; + +describe('MinHeight Component', () => { + it('should render a non-connected component', () => { + const props = {}; + + const component = shallow(lorem ipsum); + expect(component).toMatchSnapshot('non-connected'); + }); + + it('should set minHeight in relation to contents and props', () => { + const props = {}; + const component = shallow(lorem ipsum); + + expect(component.instance().setMinHeight).toBeDefined(); + + // initial height should be zero + expect(component.instance().updatedMinHeight).toEqual(0); + + // set the container size arbitrarily + component.instance().containerRef.current = { clientHeight: 100 }; + component.instance().componentDidUpdate(); + expect(component.instance().updatedMinHeight).toEqual(100); + + // set a minimum minHeight + component.setProps({ minHeight: 200 }); + expect(component.instance().updatedMinHeight).toEqual(200); + + // disable "on update" minHeight adjustments + component.setProps({ autoUpdate: false, minHeight: 300 }); + expect(component.instance().updatedMinHeight).toEqual(200); + }); +}); diff --git a/src/components/minHeight/minHeight.js b/src/components/minHeight/minHeight.js new file mode 100644 index 000000000..f1ec83cd2 --- /dev/null +++ b/src/components/minHeight/minHeight.js @@ -0,0 +1,82 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +/** + * Set a min-height to prevent page jump component. + * + * @augments React.Component + */ +class MinHeight extends React.Component { + containerRef = React.createRef(); + + updatedMinHeight = 0; + + componentDidMount() { + this.setMinHeight(); + } + + componentDidUpdate() { + const { autoUpdate } = this.props; + + if (autoUpdate) { + this.setMinHeight(); + } + } + + /** + * Set minHeight on mount or update. + */ + setMinHeight() { + const { updatedMinHeight } = this; + const { minHeight: overrideMinHeight } = this.props; + // const { clientHeight = 0 } = this.containerRef.current || {}; + const clientHeight = this.containerRef?.current?.clientHeight || 0; + + if (clientHeight !== updatedMinHeight) { + this.updatedMinHeight = clientHeight; + } + + if (overrideMinHeight > this.updatedMinHeight) { + this.updatedMinHeight = overrideMinHeight; + } + } + + /** + * Render a min-height div with children. + * + * @returns {Node} + */ + render() { + const { updatedMinHeight } = this; + const { children } = this.props; + + return ( +
+ {children} +
+ ); + } +} + +/** + * Prop types. + * + * @type {{minHeight: number, autoUpdate: boolean, children: Node}} + */ +MinHeight.propTypes = { + autoUpdate: PropTypes.bool, + children: PropTypes.node.isRequired, + minHeight: PropTypes.number +}; + +/** + * Default props. + * + * @type {{minHeight: number, autoUpdate: boolean}} + */ +MinHeight.defaultProps = { + autoUpdate: true, + minHeight: 0 +}; + +export { MinHeight as default, MinHeight };