Last active
January 10, 2017 20:20
-
-
Save jacobp100/0b7b0f4a7b9b9f053e2b19657a58cf37 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import { createComponent, Component } from 'react'; | |
import { Dimensions } from 'react-native'; | |
/* | |
Matches components based on screen min/max width/height queries. Uses component from the first size | |
descriptor that matches the screen. | |
Depends upon https://github.com/facebook/react-native/pull/9701 | |
type Size = { | |
component: Component, | |
?minWidth: number, | |
?maxWidth: number, | |
?minHeight: number, | |
?maxHeight: number, | |
?orientation: "landscape" | "portrait", | |
} | |
type queryMatcher = (...sizes: Size[]) => Component | |
# Example | |
const ExampleComponent = queryMatcher( | |
{ maxWidth: 500, component: Thumbnail }, | |
{ component: FullView }, | |
); | |
<ExampleComponent passedProp="passed-value" /> | |
*/ | |
const sizeMatches = (width, height) => (size) => ( | |
('minWidth' in size ? size.minWidth >= width : true) && | |
('maxWidth' in size ? size.maxWidth <= width : true) && | |
('minHeight' in size ? size.minHeight >= height : true) && | |
('maxHeight' in size ? size.maxHeight <= height : true) && | |
(('orientation' in size && size.orientation === 'landscape') ? (width > height) : true) && | |
(('orientation' in size && size.orientation === 'portrait') ? (width < height) : true) | |
); | |
export default (...sizes) => { | |
if (process.env.NODE_ENV === ' production') { | |
sizes.forEach((size) => { | |
if (!size.component) { | |
throw new Error('Expected all sizes to have component'); | |
} | |
if (size.minWidth && size.maxWidth && size.maxWidth < size.minWidth) { | |
throw new Error('Expected size minWidth < maxWidth'); | |
} | |
if (size.minHeight && size.maxHeight && size.maxHeight < size.minHeight) { | |
throw new Error('Expected size minHeight < maxHeight'); | |
} | |
if (size.orientation && size.orientation !== 'landscape' && size.orientation !== 'portrait') { | |
throw new Error('Expected size orientation to be "landscape" or "portrait"'); | |
} | |
}); | |
} | |
return class MediaQuery extends Component { | |
constructor() { | |
super(); | |
const { width, height } = Dimensions.get('window'); | |
this.state = { width, height }; | |
this.dimensionSubscription = null; | |
} | |
componentDidMount() { | |
this.dimensionSubscription = Dimensions.addListener((dimensions) => { | |
const { width, height } = dimensions.window; | |
this.setState({ width, height }); | |
}); | |
} | |
componentWillUnmount() { | |
if (this.dimensionSubscription) this.dimensionSubscription.remove(); | |
this.dimensionSubscription = null; | |
} | |
render() { | |
const { width, height } = this.state; | |
const size = sizes.find(sizeMatches(width, height)); | |
if (!size) throw new Error(`Failed to find matching media query for ${width}x${height}`); | |
return createComponent(size.component, this.props); | |
} | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment