A Pen by Dave Atchley on CodePen.
-
-
Save datchley/a62c15b34b8d342f31f2cf440bc05fa8 to your computer and use it in GitHub Desktop.
Responsive: Higher Order Component to pass width/height to Components as props
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
<div id="app"></div> | |
<br/> | |
<label for="container-height">Height (px):</label> | |
<input name="container-height" size="10" id="container-height" type="text" value="80"/> | |
<button type="button" onClick="changeContainerHeight()">Adjust</button> |
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
/* | |
* Utility functions | |
*/ | |
const requestAnimationFrame = window.requestAnimationFrame || (fn=>setTimeout(fn,30)); | |
function changeContainerHeight() { | |
const cont = document.querySelector('.app-container'); | |
const input = document.querySelector('#container-height'); | |
cont.style.height = input.value + 'px'; | |
} | |
/* | |
* HOC to allow Components to receive their width/height as | |
* props on render. | |
*/ | |
const Responsive = (WrappedComponent) => class _Responsive extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { width: null, height: null }; | |
this.rafCallback = this.getUpdatedSize.bind(this); | |
} | |
getUpdatedSize() { | |
const node = ReactDOM.findDOMNode(this._comp); | |
let height = node.offsetHeight; | |
let width = node.offsetWidth; | |
if (height != this.state.height || width != this.state.width) { | |
this.setState({ | |
height, | |
width | |
}); | |
} | |
requestAnimationFrame(this.rafCallback); | |
} | |
componentDidMount() { | |
requestAnimationFrame(this.rafCallback); | |
} | |
componentWillUnmount() { | |
cancelInterval(this._interval); | |
} | |
render() { | |
return <WrappedComponent ref={(ref) => this._comp = ref} {...this.props} dimensions={{...this.state}} />; | |
} | |
}; | |
/* | |
* Price Component, which should have responsive text sizing | |
* based on it's container's height. | |
*/ | |
@Responsive | |
class Price extends React.Component { | |
render() { | |
const { prefix, price, suffix, subtext, subtextPosition = "bottom" } = this.props; | |
const [ dollars, cents = '00' ] = price.split('.'); | |
const subcls = ["subtext", subtextPosition].join(' '); | |
return ( | |
<div ref={(ref)=>this._container = ref} className={"price"}> | |
<div className={"price-container"}> | |
<div className={"prefix"}>{ prefix }</div> | |
<div className={"symbol"}>$</div> | |
<span className={"dollars"}>{ dollars }</span> | |
<div className={"cents"}> | |
{ cents } | |
<span className={"suffix"}>{ suffix }</span> | |
</div> | |
</div> | |
<div className={subcls}>{ subtext }</div> | |
</div> | |
); | |
} | |
componentDidUpdate() { | |
this.resizeFont(); | |
} | |
resizeFont() { | |
window.requestAnimationFrame(() => { | |
const { width, height } = this.props.dimensions; | |
const factor = this.props.subtext && this.props.subtextPosition == 'bottom' ? .7 : .9; | |
this._container.style.fontSize = (height * factor).toFixed(2) + 'px'; | |
}); | |
} | |
} | |
ReactDOM.render( | |
<div className={"app-container"}> | |
<Price prefix="from" | |
price="29.99" | |
suffix="/mo" | |
subtext="for 12 months when bundled" | |
subtextPosition="right"/> | |
</div>, | |
document.getElementById('app') | |
); |
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
<script src="https://fb.me/react-15.1.0.min.js"></script> | |
<script src="https://fb.me/react-dom-15.1.0.min.js"></script> |
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
.app-container { | |
height: 80px; | |
background-color: rgba(0,0,0,.2); | |
overflow: hidden; | |
} | |
.price { | |
width: auto; | |
height: 100%; | |
font-size: 85%; | |
text-align: center; | |
} | |
.price-container { | |
display: inline-block; | |
position: relative; | |
height: auto; | |
text-align: center; | |
-webkit-transition: font-size .3s ease; | |
-moz-transition: font-size .3s ease; | |
-o-transition: font-size .3s ease; | |
transition: font-size .3s ease; | |
} | |
.prefix, | |
.symbol, | |
.cents { | |
position: absolute; | |
display: inline-block; | |
} | |
.symbol { | |
left: -0.6em; | |
top: .5em; | |
opacity: .5; | |
font-size: 30%; | |
} | |
.prefix { | |
left: -2.2em; | |
bottom: 0.6em; | |
font-size: 30%; | |
color: #999; | |
} | |
.cents { | |
left: 100%; | |
top: .4em; | |
opacity: .5; | |
font-size: 33%; | |
.suffix { | |
font-size: 80%; | |
} | |
} | |
.subtext { | |
text-align: center; | |
font-size: 20%; | |
opacity: .3; | |
&.bottom { | |
margin-top: -5px; | |
} | |
&.right { | |
display: inline-block; | |
} | |
&.hidden { | |
display: none; | |
} | |
} | |
.dollars { | |
font-size: 100%; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment