Created
May 16, 2017 11:57
-
-
Save hejrobin/1158952d0b7a12a8dd7ad653c483aebf to your computer and use it in GitHub Desktop.
ES6 Component for conditional render contexts.
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
/* @flow */ | |
/** | |
* @type ComponentProperties | |
*/ | |
type ComponentProperties = { [ key : any ] : any } | |
/** | |
* @type ComponentNodeTree | |
*/ | |
type ComponentNodeTree = React$Element<any> | |
/* @dependencies */ | |
import React, { Component } from 'react' | |
import PropTypes from 'prop-types' | |
/** | |
* @type RenderContextDefaults | |
*/ | |
type RenderContextDefaults = { | |
children? : ComponentNodeTree, | |
refuteMatch : bool, | |
assert : bool | |
} | |
/** | |
* @type RenderContextProperties | |
*/ | |
type RenderContextProperties = { | |
children? : ComponentNodeTree, | |
mediaQuery : string, | |
refuteMatch : bool, | |
assert : bool | |
} | |
/** | |
* @type RenderContextState | |
*/ | |
type RenderContextState = { | |
mediaQueryMatch : bool | |
} | |
/** | |
* @const string TINY_SCREEN | |
*/ | |
export const TINY_SCREEN = "only screen and (max-width: 384px)" | |
/** | |
* @const string SMALL_SCREEN | |
*/ | |
export const SMALL_SCREEN = "only screen and (min-width: 385px) and (max-width: 768px)" | |
/** | |
* @const string MEDIUM_SCREEN | |
*/ | |
export const MEDIUM_SCREEN = "only screen and (min-width: 769px) and (max-width: 1151px)" | |
/** | |
* @const string LARGE_SCREEN | |
*/ | |
export const LARGE_SCREEN = "only screen and (min-width: 1152px)" | |
/** | |
* Full width surface component, wrapper for decks, cards and other UI components. | |
* | |
* @prop string componentClassNames | |
* @prop ComponentProperties componentProperties | |
*/ | |
export default class RenderContext extends Component<RenderContextDefaults, RenderContextProperties, RenderContextState> { | |
/** | |
* @var RenderContextState state | |
*/ | |
state : RenderContextState = { | |
mediaQueryMatch : true | |
} | |
/** | |
* @var bool screenChange | |
*/ | |
screenChange : bool = false | |
/** | |
* @static ComponentProperties propTypes | |
*/ | |
static propTypes : ComponentProperties = { | |
mediaQuery : PropTypes.string.isRequired, | |
refuteMatch : PropTypes.bool, | |
assert : PropTypes.bool | |
} | |
/** | |
* @static ComponentProperties defaultProps | |
*/ | |
static defaultProps : ComponentProperties = { | |
children : null, // @NOTE Fix for return type in flow | |
refuteMatch : false, | |
assert : undefined | |
} | |
/** | |
* Updates scroll state of navbar. | |
* | |
* @param SyntheticEvent event | |
* | |
* @return void | |
*/ | |
handleScreenChangeEvent = ( event : SyntheticEvent ) : void => { | |
if ( this.screenChange === false ) { | |
window.requestAnimationFrame(() => { | |
const mediaQueryMatch : bool = this.validateMediaQueryMatch(); | |
this.setState({ mediaQueryMatch }); | |
this.screenChange = false; | |
}); | |
this.screenChange = true; | |
} | |
} | |
/** | |
* Validates whether or not current render context matches media query. | |
* | |
* @return bool | |
*/ | |
validateMediaQueryMatch() : bool { | |
let mediaQueryMatch : bool = window.matchMedia(this.props.mediaQuery).matches; | |
if ( this.props.refuteMatch === true ) { | |
mediaQueryMatch = ( ! mediaQueryMatch ) | |
} | |
return mediaQueryMatch; | |
} | |
/** | |
* Attaches screen changes events. | |
* | |
* @return void | |
*/ | |
componentWillMount() : void { | |
window.addEventListener('resize', this.handleScreenChangeEvent); | |
window.addEventListener('orientationchange', this.handleScreenChangeEvent); | |
const mediaQueryMatch : bool = this.validateMediaQueryMatch(); | |
this.setState({ mediaQueryMatch }); | |
} | |
/** | |
* Detaches screen changes events. | |
* | |
* @return void | |
*/ | |
componentWillUnount() : void { | |
window.removeEventListener('resize', this.handleScreenChangeEvent); | |
window.removeEventListener('orientationchange', this.handleScreenChangeEvent); | |
} | |
/** | |
* @prop bool validContext | |
*/ | |
get validContext() : bool { | |
if ( this.props.assert !== undefined ) { | |
return ( this.state.mediaQueryMatch === true && this.props.assert === true ); | |
} | |
return ( this.state.mediaQueryMatch === true ); | |
} | |
/** | |
* @return ComponentNodeTree | |
*/ | |
render() : ComponentNodeTree | null { | |
if ( this.validContext === true && this.props.children ) { | |
return this.props.children; | |
} | |
return null; | |
} | |
} |
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
/* @flow */ | |
/** | |
* @type ComponentProperties | |
*/ | |
type ComponentProperties = { [ key : any ] : any } | |
/** | |
* @type ComponentNodeTree | |
*/ | |
type ComponentNodeTree = React$Element<any> | |
/* @dependencies */ | |
import React, { Component } from 'react' | |
import PropTypes from 'prop-types' | |
import RenderContext, { TINY_SCREEN } from './rendercontext' | |
export SomeComponent extends Component { | |
render() : ComponentNodeTree { | |
return ( | |
<article className="component some__component"> | |
<RenderContext mediaQuery={TINY_SCREEN}> | |
<p>Visible for tiny screens!</p> | |
</RenderContext> | |
<RenderContext mediaQuery={TINY_SCREEN} refuteMatch> | |
<p>Visible for any screen except tiny screen!</p> | |
</RenderContext> | |
<RenderContext mediaQuery={TINY_SCREEN} assign={getCurrentUser().isLoggedIn}> | |
<p>Visible for tiny screens if assign-property is true.</p> | |
</RenderContext> | |
</article> | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment