Created
August 22, 2016 09:23
-
-
Save slorber/27006e27997464c9f737ac22a8a89a94 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
import React, { PropTypes } from 'react'; | |
import $ from 'jquery'; | |
import _ from 'lodash'; | |
import shallowCompare from 'react-addons-shallow-compare'; | |
const ResponsiveContainer = React.createClass({ | |
propTypes: { | |
containerClassName: React.PropTypes.string, | |
component: React.PropTypes.func.isRequired, | |
mapDimensionsToProps: React.PropTypes.func.isRequired | |
}, | |
getInitialState() { | |
return {responsiveProps: undefined} | |
}, | |
shouldComponentUpdate(nextProps, nextState) { | |
return shallowCompare(this, nextProps, nextState); | |
}, | |
componentDidMount() { | |
this.handleResize = _.throttle(this.handleResize,200); | |
$(window).on("resize",this.handleResize); | |
this.updateDimensions(); | |
}, | |
componentWillUnmount() { | |
$(window).off("resize",this.handleResize); | |
}, | |
componentDidUpdate() { | |
this.updateDimensions(); | |
}, | |
handleResize() { | |
this.updateDimensions(); | |
}, | |
updateDimensions() { | |
const container = this._container; | |
if (!container) { | |
return; // I think it happens when hot reloading code it's weird (?) | |
} | |
const newDimensions = { | |
containerWidth: $(container).width(), | |
containerHeight: $(container).height() | |
}; | |
// TODO a bit dirty optimization logic, reimplement with proper shouldComponentUpdate? | |
if ( !_.isEqual(this.dimensions,newDimensions) ) { | |
this.dimensions = newDimensions; | |
const newResponsiveProps = this.props.mapDimensionsToProps(newDimensions); | |
if ( !_.isEqual(this.state.responsiveProps,newResponsiveProps) ) { | |
this.setState({responsiveProps: newResponsiveProps}); | |
} | |
} | |
}, | |
maybeRenderChildren() { | |
if ( this.state.responsiveProps ) { | |
const Comp = this.props.component; | |
return <Comp | |
{..._.omit(this.props,["component","containerClassName","mapDimensionsToProps"])} | |
{...this.state.responsiveProps} | |
/>; | |
} | |
}, | |
render() { | |
return ( | |
<div ref={c => this._container = c} className={this.props.containerClassName}> | |
{this.maybeRenderChildren()} | |
</div> | |
) | |
} | |
}); | |
exports.injectColumnNumber = ({minColumnWidth,minColumnNumber,maxColumnNumber,containerClassName}) => { | |
const mapDimensionsToProps = ({containerWidth}) => { | |
let columnNumber = Math.trunc( containerWidth / minColumnWidth ); | |
if ( minColumnNumber && columnNumber < minColumnNumber ) columnNumber = minColumnNumber; | |
if ( maxColumnNumber && columnNumber > maxColumnNumber ) columnNumber = maxColumnNumber; | |
return { | |
columnNumber: columnNumber | |
} | |
}; | |
return Component => React.createClass({ | |
render() { | |
return <ResponsiveContainer | |
{...this.props} | |
component={Component} | |
containerClassName={containerClassName} | |
mapDimensionsToProps={mapDimensionsToProps} | |
/> | |
} | |
}); | |
}; | |
exports.injectContainerWidthRange = ({containerClassName,propName,config}) => { | |
if ( Object.keys(config).length === 0 ) { | |
throw new Error("ranges are not provided"); | |
} | |
let ranges = Object.keys(config).map( key => ({name: key, width: config[key]}) ); | |
ranges = _.sortBy(ranges,range => range.width); | |
if ( ranges[0].width !== 0 ) { | |
throw new Error("There should be at least a named range starting with width = 0"); | |
} | |
const mapDimensionsToProps = ({containerWidth}) => { | |
const width = containerWidth; | |
const range =_.findLast(ranges,range => width >= range.width); | |
const result = {}; | |
const finalPropName = propName || "containerWidthRange"; | |
result[finalPropName] = range.name; | |
return result; | |
}; | |
return Component => React.createClass({ | |
render() { | |
return <ResponsiveContainer | |
{...this.props} | |
component={Component} | |
containerClassName={containerClassName} | |
mapDimensionsToProps={mapDimensionsToProps} | |
/> | |
} | |
}); | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment