Skip to content

Commit

Permalink
feat(responsive): Add query prop to allow targeting of media query ch…
Browse files Browse the repository at this point in the history
…aracteristics
  • Loading branch information
ryanoglesby08 committed Nov 28, 2017
1 parent 9ea7b15 commit 441401e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 14 deletions.
29 changes: 18 additions & 11 deletions src/components/ResponsiveReactMedia/ResponsiveReactMedia.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,52 +12,59 @@ const breakpoints = {
}

/**
* Define content within viewport breakpoints
* Respond to the device's characteristics, such as the browser viewport size.
*
* <span class="docs--badge__new">new!</span> <span class="docs--badge__version">v0.30.0</span>
*/
// TODO: What about other media query properties such as screen, etc...
const Responsive = ({ minWidth, maxWidth, children, ...rest }) => {
const Responsive = ({ minWidth, maxWidth, query, children, ...rest }) => {
if (!minWidth && !maxWidth) {
warn('Responsive', 'Responsive needs a minWidth or maxWith prop')
}

// Do it this way to not create an object with keys that have the value "undefined", which causes the generated media-query to be invalid
// Do it this way to not create an object where some keys have the value "undefined", which causes the generated media-query to be invalid.
// (min-width: 300px) and (max-width: undefined) is bad :(
// (min-width: 300px) is good :)
const query = {}
const mediaQuery = {}
if (minWidth) {
query.minWidth = breakpoints[minWidth]
mediaQuery.minWidth = breakpoints[minWidth]
}
if (maxWidth) {
query.maxWidth = breakpoints[maxWidth] - 1
mediaQuery.maxWidth = breakpoints[maxWidth] - 1
}

return (
<Media {...rest} query={query}>
<Media {...rest} query={{ ...mediaQuery, ...query }}>
{children}
</Media>
)
}

Responsive.propTypes = {
/**
* Set browser min-width media query.
* Set the min-width media query.
*/
minWidth: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
/**
* Set browser max-width media query.
* Set the max-width media query.
*/
maxWidth: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
/**
* The content. Can be text, any HTML element, or any component.
* An object containing any valid CSS media query characteristics. It will be converted to a CSS media query.
* Use `query` if you need characteristics other than `minWidth` and `maxWidth`.
*
* Any `minWidth` or `maxWidth` values here will override the props by the same name.
*/
query: PropTypes.object,
/**
* The content. Can be text, any HTML element, a function, or any component.
*/
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
}

Responsive.defaultProps = {
minWidth: undefined,
maxWidth: undefined,
query: {},
}

export default Responsive
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,20 @@ describe('Responsive with react-media', () => {
expect(responsive).toMatchSnapshot()
})

it('warns when mixWidth and maxWidth are not defined', () => {
// TODO: Maybe this warning should not exist? What is you just want to query for screen vs print or something?
it('warns when min width and max width are not defined', () => {
doShallow({ minWidth: undefined, maxWidth: undefined })

expect(warn).toHaveBeenCalled()
})

it('can have a minWidth or maxWidth', () => {
it('translates min and max width to pixel breakpoints', () => {
const responsive = doShallow({ minWidth: 'sm', maxWidth: 'md' })

expect(responsive).toHaveProp('query', { minWidth: 576, maxWidth: 767 })
})

it('does not include undefined query properties', () => {
it('does not generate a query with undefined min or max widths', () => {
let responsive = doShallow({ minWidth: 'sm' })

let query = responsive.props().query
Expand All @@ -45,6 +46,21 @@ describe('Responsive with react-media', () => {
expect(query.hasOwnProperty('minWidth')).toBeFalsy() // eslint-disable-line no-prototype-builtins
})

it('accepts other media query characteristics', () => {
const responsive = doShallow({ query: { screen: true, orientation: 'portrait' } })

expect(responsive).toHaveProp(
'query',
expect.objectContaining({ screen: true, orientation: 'portrait' })
)
})

it('allows overriding the min and max width with a query', () => {
const responsive = doShallow({ query: { minWidth: 100, maxWidth: 2000 } })

expect(responsive).toHaveProp('query', { minWidth: 100, maxWidth: 2000 })
})

it('passes additional attributes to the Media component', () => {
const responsive = doShallow({ defaultMatches: false })

Expand Down

0 comments on commit 441401e

Please sign in to comment.