Skip to content

Commit

Permalink
Add Responsive.Visible and Responsive.Hidden utilities to Dark Matter
Browse files Browse the repository at this point in the history
  • Loading branch information
pixelbandito committed Sep 10, 2019
1 parent e6977c1 commit 778d25b
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/components/Responsive/Hidden/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Responsive.Hidden

**Hide contents based on container width.**

When you use a `Responsive.Container`, it sets up a container width watcher with pre-defined breakpoints.
You can use those breakpoints to hide this component based on container width.
53 changes: 53 additions & 0 deletions src/components/Responsive/Hidden/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import intersection from 'lodash/intersection';

import Context from '../Context';

const Hidden = ({
children,
responsiveContext: hiddenResponsiveContext,
...passedProps
}) => {
const getIsHidden = useCallback(
responsiveContext =>
!!intersection(hiddenResponsiveContext, responsiveContext).length,
[hiddenResponsiveContext]
);

return (
<Context.Consumer>
{responsiveContext => {
const hidden = getIsHidden(responsiveContext);

return React.Children.map(children, child => {
if (!child || hidden) {
return null;
}

if (typeof child === 'string') {
return <span>{child}</span>;
}

return React.cloneElement(child, {
...passedProps,
});
});
}}
</Context.Consumer>
);
};

Hidden.propTypes = {
children: PropTypes.node,
container: PropTypes.string,
responsiveContext: PropTypes.arrayOf(PropTypes.string),
};

Hidden.defaultProps = {
children: null,
container: null,
responsiveContext: [],
};

export default Hidden;
29 changes: 29 additions & 0 deletions src/components/Responsive/Hidden/story.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { storiesOf } from '@storybook/react';

// Rover UI dependencies
import Container from '../Container';

// This component's dependencies
import Readme from './README.md';
import Hidden from './';

storiesOf('Dark Matter/Responsive/Hidden', module)
.addParameters({
readme: {
sidebar: Readme,
},
})
.add('Overview', () => (
<div>
<Container readOnly style={{ resize: 'both' }}>
<div>
<Hidden
responsiveContext={['container-xs-only', 'container-md-only']}
>
I&apos;ll disappear at certain sizes
</Hidden>
</div>
</Container>
</div>
));
52 changes: 52 additions & 0 deletions src/components/Responsive/Hidden/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { mount } from 'enzyme';
import Context from '../Context';
import Hidden from './';

describe('<Hidden />', () => {
it('renders without error', () => {
mount(
<Hidden>
<span>Boom</span>
</Hidden>
);
});

it('hides by breakpoint', () => {
const wrapper = mount(
<Context.Provider
value={[
'container-sm-up',
'container-sm-only',
'container-sm-down',
'container-md-down',
]}
>
<Hidden responsiveContext={['container-sm-down']}>
<span>Boom</span>
</Hidden>
</Context.Provider>
);

expect(wrapper.text()).toEqual('');
});

it("doesn't hide without breakpoint", () => {
const wrapper = mount(
<Context.Provider
value={[
'container-sm-up',
'container-sm-only',
'container-sm-down',
'container-md-down',
]}
>
<Hidden responsiveContext={['container-md-up']}>
<span>Boom</span>
</Hidden>
</Context.Provider>
);

expect(wrapper.text()).toEqual('Boom');
});
});
6 changes: 6 additions & 0 deletions src/components/Responsive/Visible/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Responsive.Visible

**Shows contents based on container width.**

When you use a `Responsive.Container`, it sets up a container width watcher with pre-defined breakpoints.
You can use those breakpoints to show this component based on container width.
53 changes: 53 additions & 0 deletions src/components/Responsive/Visible/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import intersection from 'lodash/intersection';

import Context from '../Context';

const Visible = ({
children,
responsiveContext: VisibleResponsiveContext,
...passedProps
}) => {
const getIsVisible = useCallback(
responsiveContext =>
!!intersection(VisibleResponsiveContext, responsiveContext).length,
[VisibleResponsiveContext]
);

return (
<Context.Consumer>
{responsiveContext => {
const visible = getIsVisible(responsiveContext);

return React.Children.map(children, child => {
if (!child || !visible) {
return null;
}

if (typeof child === 'string') {
return <span>{child}</span>;
}

return React.cloneElement(child, {
...passedProps,
});
});
}}
</Context.Consumer>
);
};

Visible.propTypes = {
children: PropTypes.node,
container: PropTypes.string,
responsiveContext: PropTypes.arrayOf(PropTypes.string),
};

Visible.defaultProps = {
children: null,
container: null,
responsiveContext: [],
};

export default Visible;
29 changes: 29 additions & 0 deletions src/components/Responsive/Visible/story.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { storiesOf } from '@storybook/react';

// Rover UI dependencies
import Container from '../Container';

// This component's dependencies
import Readme from './README.md';
import Visible from './';

storiesOf('Dark Matter/Responsive/Visible', module)
.addParameters({
readme: {
sidebar: Readme,
},
})
.add('Overview', () => (
<div>
<Container readOnly style={{ resize: 'both' }}>
<div>
<Visible
responsiveContext={['container-xs-only', 'container-md-only']}
>
I&apos;ll appear at certain sizes
</Visible>
</div>
</Container>
</div>
));
52 changes: 52 additions & 0 deletions src/components/Responsive/Visible/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { mount } from 'enzyme';
import Context from '../Context';
import Visible from './';

describe('<Visible />', () => {
it('renders without error', () => {
mount(
<Visible>
<span>Boom</span>
</Visible>
);
});

it('shows by breakpoint', () => {
const wrapper = mount(
<Context.Provider
value={[
'container-sm-up',
'container-sm-only',
'container-sm-down',
'container-md-down',
]}
>
<Visible responsiveContext={['container-sm-down']}>
<span>Boom</span>
</Visible>
</Context.Provider>
);

expect(wrapper.text()).toEqual('Boom');
});

it("doesn't show without breakpoint", () => {
const wrapper = mount(
<Context.Provider
value={[
'container-sm-up',
'container-sm-only',
'container-sm-down',
'container-md-down',
]}
>
<Visible responsiveContext={['container-md-up']}>
<span>Boom</span>
</Visible>
</Context.Provider>
);

expect(wrapper.text()).toEqual('');
});
});
2 changes: 2 additions & 0 deletions src/components/Responsive/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import Container from './Container';
import Context from './Context';
import Element from './Element';
import Grid from './Grid';
import Hidden from './Hidden';

const Responsive = {
Container,
Context,
Element,
Grid,
Hidden,
};

export default Responsive;
2 changes: 2 additions & 0 deletions src/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import '../components/Grid/story';
import '../components/Media/story';
import '../components/Responsive/story';
import '../components/Responsive/Grid/story';
import '../components/Responsive/Hidden/story';
import '../components/Responsive/Visible/story';

/*
* NEW & UNCATEGORIZED
Expand Down

0 comments on commit 778d25b

Please sign in to comment.