Skip to content

Instantly share code, notes, and snippets.

@jacobp100
Last active January 10, 2017 20:20
Show Gist options
  • Save jacobp100/0b7b0f4a7b9b9f053e2b19657a58cf37 to your computer and use it in GitHub Desktop.
Save jacobp100/0b7b0f4a7b9b9f053e2b19657a58cf37 to your computer and use it in GitHub Desktop.
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