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
@@ -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"
+1 -7
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 }
-24
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;
}
}
@@ -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"
+6 -1
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
+18 -2
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);
} }
+9
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();
});
}); });
@@ -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)
+2 -2
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
+1 -1
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();
}); });