mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
withDimensions context helper
This commit is contained in:
parent
d81a4b33ae
commit
8dcd160817
1 changed files with 106 additions and 0 deletions
|
|
@ -69,6 +69,112 @@ export const withViewport = Component => {
|
|||
return WithViewportComponent;
|
||||
};
|
||||
|
||||
/**
|
||||
* A higher order component (HOC) that provides dimensions to the wrapped component as a
|
||||
* `dimensions` prop that has the shape `{ width: 600, height: 400}`.
|
||||
*
|
||||
* @param {React.Component} Component to be wrapped by this HOC
|
||||
* @param {Object} options pass in options like maxWidth and maxHeight.
|
||||
*
|
||||
* @return {Object} HOC component which knows its dimensions
|
||||
*/
|
||||
export const withDimensions = (Component, options = {}) => {
|
||||
// The resize event is flooded when the browser is resized. We'll
|
||||
// use a small timeout to throttle changing the viewport since it
|
||||
// will trigger rerendering.
|
||||
const THROTTLE_WAIT_MS = 200;
|
||||
// First render default wait after mounting (small wait for styled paint)
|
||||
const RENDER_WAIT_MS = 100;
|
||||
|
||||
class WithDimensionsComponent extends ReactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.element = null;
|
||||
this.defaultRenderTimeout = null;
|
||||
|
||||
this.state = { width: 0, height: 0 };
|
||||
|
||||
this.handleWindowResize = throttle(this.handleWindowResize.bind(this), THROTTLE_WAIT_MS);
|
||||
this.setDimensions = this.setDimensions.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('resize', this.handleWindowResize);
|
||||
window.addEventListener('orientationchange', this.handleWindowResize);
|
||||
|
||||
this.defaultRenderTimeout = window.setTimeout(() => {
|
||||
this.setDimensions();
|
||||
}, RENDER_WAIT_MS);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.handleWindowResize);
|
||||
window.removeEventListener('orientationchange', this.handleWindowResize);
|
||||
window.clearTimeout(this.defaultRenderTimeout);
|
||||
}
|
||||
|
||||
handleWindowResize() {
|
||||
window.requestAnimationFrame(() => {
|
||||
this.setDimensions();
|
||||
});
|
||||
}
|
||||
|
||||
setDimensions() {
|
||||
this.setState(prevState => {
|
||||
const { clientWidth, clientHeight } = this.element || { clientWidth: 0, clientHeight: 0 };
|
||||
return { width: clientWidth, height: clientHeight };
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
// Dimensions from state (i.e. dimension after previous resize)
|
||||
// These are needed for component rerenders
|
||||
const { width, height } = this.state;
|
||||
|
||||
// Current dimensions from element reference
|
||||
const { clientWidth, clientHeight } = this.element || { clientWidth: 0, clientHeight: 0 };
|
||||
const hasDimensions =
|
||||
(width !== 0 && height !== 0) || (clientWidth !== 0 && clientHeight !== 0);
|
||||
|
||||
// clientWidth and clientHeight
|
||||
const currentDimensions =
|
||||
clientWidth !== 0 && clientHeight !== 0
|
||||
? { width: clientWidth, height: clientHeight }
|
||||
: width !== 0 && height !== 0
|
||||
? { width, height }
|
||||
: {};
|
||||
|
||||
const props = { ...this.props, dimensions: currentDimensions };
|
||||
|
||||
// lazyLoadWithDimensions HOC needs to take all given space
|
||||
// unless max dimensions are provided through options.
|
||||
const { maxWidth, maxHeight } = options;
|
||||
const maxWidthMaybe = maxWidth ? { maxWidth } : {};
|
||||
const maxHeightMaybe = maxHeight ? { maxHeight } : {};
|
||||
const style =
|
||||
maxWidth || maxHeight
|
||||
? { width: '100%', height: '100%', ...maxWidthMaybe, ...maxHeightMaybe }
|
||||
: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0 };
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={element => {
|
||||
this.element = element;
|
||||
}}
|
||||
style={style}
|
||||
>
|
||||
{hasDimensions ? <Component {...props} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
WithDimensionsComponent.displayName = `withDimensions(${Component.displayName ||
|
||||
Component.name})`;
|
||||
|
||||
return WithDimensionsComponent;
|
||||
};
|
||||
|
||||
/**
|
||||
* A higher order component (HOC) that lazy loads the current element and provides
|
||||
* dimensions to the wrapped component as a `dimensions` prop that has
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue