Moving close button for Privacy modal to Message

This allow any Message to have a configurable close button. It also
makes the styling more robust
This commit is contained in:
Jeff Avallone 2019-01-19 13:41:42 -05:00
parent f9b34ebd94
commit fcf9a354f4
10 changed files with 83 additions and 87 deletions

View File

@ -16,16 +16,9 @@ exports[`Header closing the Privacy Policy modal 1`] = `
shouldFocusAfterRender={true} shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true} shouldReturnFocusAfterClose={true}
> >
<LoadNamespace(PrivacyPolicy) /> <LoadNamespace(PrivacyPolicy)
<button onClose={[Function]}
className="modalClose"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/> />
</button>
</Modal> </Modal>
<header <header
className="header" className="header"
@ -95,16 +88,9 @@ exports[`Header closing the Privacy Policy modal 2`] = `
shouldFocusAfterRender={true} shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true} shouldReturnFocusAfterClose={true}
> >
<LoadNamespace(PrivacyPolicy) /> <LoadNamespace(PrivacyPolicy)
<button onClose={[Function]}
className="modalClose"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/> />
</button>
</Modal> </Modal>
<header <header
className="header" className="header"
@ -174,16 +160,9 @@ exports[`Header opening the Privacy Policy modal 1`] = `
shouldFocusAfterRender={true} shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true} shouldReturnFocusAfterClose={true}
> >
<LoadNamespace(PrivacyPolicy) /> <LoadNamespace(PrivacyPolicy)
<button onClose={[Function]}
className="modalClose"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/> />
</button>
</Modal> </Modal>
<header <header
className="header" className="header"
@ -253,16 +232,9 @@ exports[`Header rendering 1`] = `
shouldFocusAfterRender={true} shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true} shouldReturnFocusAfterClose={true}
> >
<LoadNamespace(PrivacyPolicy) /> <LoadNamespace(PrivacyPolicy)
<button onClose={[Function]}
className="modalClose"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/> />
</button>
</Modal> </Modal>
<header <header
className="header" className="header"
@ -332,16 +304,9 @@ exports[`Header rendering with no banner 1`] = `
shouldFocusAfterRender={true} shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true} shouldReturnFocusAfterClose={true}
> >
<LoadNamespace(PrivacyPolicy) /> <LoadNamespace(PrivacyPolicy)
<button onClose={[Function]}
className="modalClose"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/> />
</button>
</Modal> </Modal>
<header <header
className="header" className="header"

View File

@ -5,7 +5,6 @@ import { Link } from 'gatsby';
import { withNamespaces, Trans } from 'react-i18next'; import { withNamespaces, Trans } from 'react-i18next';
import GitlabIcon from 'react-feather/dist/icons/gitlab'; import GitlabIcon from 'react-feather/dist/icons/gitlab';
import CloseIcon from 'react-feather/dist/icons/x-square';
import LocaleSwitcher from 'components/LocaleSwitcher'; import LocaleSwitcher from 'components/LocaleSwitcher';
import InstallPrompt from 'components/InstallPrompt'; import InstallPrompt from 'components/InstallPrompt';
@ -46,12 +45,7 @@ class Header extends React.PureComponent {
<Modal <Modal
isOpen={ showModal } isOpen={ showModal }
onRequestClose={ this.handleClose }> onRequestClose={ this.handleClose }>
<PrivacyPolicy /> <PrivacyPolicy onClose={ this.handleClose } />
<button
className={ style.modalClose }
onClick={ this.handleClose }>
<CloseIcon />
</button>
</Modal> </Modal>
<header <header
className={ style.header } className={ style.header }

View File

@ -66,27 +66,3 @@
} }
} }
} }
.modalClose {
position: absolute;
top: 3rem;
right: 2rem;
line-height: 2.8rem;
padding: 1rem;
margin: 0;
border: 0 none;
background: transparent;
color: inherit;
&:hover svg,
&:active svg {
color: var(--color-white);
}
& svg {
display: inline-block;
width: 2.8rem;
height: 2.8rem;
vertical-align: middle;
}
}

View File

@ -21,6 +21,36 @@ exports[`Message rendering 1`] = `
</div> </div>
`; `;
exports[`Message rendering with a close button 1`] = `
<div
className="message"
>
<div
className="header"
>
<h2>
Testing
</h2>
<button
onClick={[MockFunction]}
>
<XSquare
color="currentColor"
size="24"
/>
Close
</button>
</div>
<div
className="content"
>
<p>
Message content
</p>
</div>
</div>
`;
exports[`Message rendering with icon 1`] = ` exports[`Message rendering with icon 1`] = `
<div <div
className="message" className="message"

View File

@ -6,6 +6,7 @@ import style from './style.module.css';
import InfoIcon from 'react-feather/dist/icons/info'; import InfoIcon from 'react-feather/dist/icons/info';
import ErrorIcon from 'react-feather/dist/icons/alert-octagon'; import ErrorIcon from 'react-feather/dist/icons/alert-octagon';
import WarningIcon from 'react-feather/dist/icons/alert-triangle'; import WarningIcon from 'react-feather/dist/icons/alert-triangle';
import CloseIcon from 'react-feather/dist/icons/x-square';
const iconTypes = { const iconTypes = {
info: InfoIcon, info: InfoIcon,
@ -23,7 +24,7 @@ const renderIcon = (type, icon) => {
return <Icon />; return <Icon />;
}; };
const Message = ({ type, icon, heading, children }) => ( const Message = ({ type, icon, heading, onClose, children }) => (
<div className={ [ <div className={ [
style.message, style.message,
type && style[type] type && style[type]
@ -31,6 +32,9 @@ const Message = ({ type, icon, heading, children }) => (
<div className={ style.header }> <div className={ style.header }>
{ renderIcon(type, icon) } { renderIcon(type, icon) }
<h2>{ heading }</h2> <h2>{ heading }</h2>
{ onClose && <button onClick={ onClose }>
<CloseIcon /> Close
</button> }
</div> </div>
<div className={ style.content }> <div className={ style.content }>
{ children } { children }
@ -49,6 +53,7 @@ Message.propTypes = {
PropTypes.func PropTypes.func
]), ]),
heading: PropTypes.string.isRequired, heading: PropTypes.string.isRequired,
onClose: PropTypes.func,
children: PropTypes.oneOfType([ children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),
PropTypes.node PropTypes.node

View File

@ -24,6 +24,22 @@
width: 2.8rem; width: 2.8rem;
vertical-align: bottom; vertical-align: bottom;
} }
& button {
padding: 0;
margin: 0;
border: 0 none;
background: transparent;
color: var(--color-tan);
cursor: pointer;
float: right;
font-size: 0;
&:hover,
&:active {
color: var(--color-white);
}
}
} }
.content { .content {
@ -56,7 +72,7 @@
& .header { & .header {
background: var(--color-orange); background: var(--color-orange);
& svg { & > svg {
background: var(--color-black); background: var(--color-black);
color: var(--color-orange); color: var(--color-orange);
} }
@ -68,7 +84,7 @@
background: var(--color-blue); background: var(--color-blue);
color: var(--color-white); color: var(--color-white);
& svg { & > svg {
background: var(--color-white); background: var(--color-white);
color: var(--color-blue); color: var(--color-blue);
} }

View File

@ -31,4 +31,13 @@ describe('Message', () => {
); );
expect(component).toMatchSnapshot(); expect(component).toMatchSnapshot();
}); });
test('rendering with a close button', () => {
const component = shallow(
<Message heading="Testing" onClose={ jest.fn() }>
<p>Message content</p>
</Message>
);
expect(component).toMatchSnapshot();
});
}); });

View File

@ -3,6 +3,7 @@
exports[`PrivacyPolicy rendering 1`] = ` exports[`PrivacyPolicy rendering 1`] = `
<Message <Message
heading="TRANSLATE(Privacy Policy)" heading="TRANSLATE(Privacy Policy)"
onClose={[MockFunction]}
type="info" type="info"
> >
<WithMergedOptions(TransComponent) <WithMergedOptions(TransComponent)

View File

@ -4,8 +4,8 @@ import { withNamespaces, Trans } from 'react-i18next';
import Message from 'components/Message'; import Message from 'components/Message';
export const PrivacyPolicy = ({ t }) => ( export const PrivacyPolicy = ({ t, ...props }) => (
<Message type="info" heading={ t('Privacy Policy') }> <Message type="info" heading={ t('Privacy Policy') } { ...props }>
<Trans i18nKey="Privacy policy copy"> <Trans i18nKey="Privacy policy copy">
<p> <p>
Regexper and the tools used to create it are all open source. If you are Regexper and the tools used to create it are all open source. If you are

View File

@ -7,7 +7,7 @@ import { PrivacyPolicy } from 'components/PrivacyPolicy';
describe('PrivacyPolicy', () => { describe('PrivacyPolicy', () => {
test('rendering', () => { test('rendering', () => {
const component = shallow( const component = shallow(
<PrivacyPolicy t={ mockT } /> <PrivacyPolicy onClose={ jest.fn() } t={ mockT } />
); );
expect(component).toMatchSnapshot(); expect(component).toMatchSnapshot();
}); });