From 2b56a7bd96b901afa734111fb6d86d882409b646 Mon Sep 17 00:00:00 2001 From: Gustavo Liedke <g.liedke@comicrelief.com> Date: Mon, 8 Jul 2019 11:51:02 +0100 Subject: [PATCH 1/4] feat: Single message copy as children props BREAKING CHANGE: Single message uses children as props --- .../Molecules/SingleMessage/SingleMessage.js | 50 +++---------------- .../Molecules/SingleMessage/SingleMessage.md | 21 +++++--- .../SingleMessage/SingleMessage.test.js | 43 ++++++++-------- src/theme/shared/fonts.css | 1 + 4 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/components/Molecules/SingleMessage/SingleMessage.js b/src/components/Molecules/SingleMessage/SingleMessage.js index ced0779e3..52495a9e2 100644 --- a/src/components/Molecules/SingleMessage/SingleMessage.js +++ b/src/components/Molecules/SingleMessage/SingleMessage.js @@ -2,8 +2,6 @@ import React from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; import Picture from '../../Atoms/Picture/Picture'; -import Text from '../../Atoms/Text/Text'; -import Link from '../../Atoms/Link/Link'; const Container = styled.div` display: flex; @@ -21,17 +19,11 @@ const Copy = styled.div` `; const SingleMessage = ({ - title, - text, - copyFirst, - textColor, - ctaText, - ctaLink, - ctaColor, - ctaTarget, backgroundColor, + copyFirst, imageSet, - imageAltText + imageAltText, + children }) => { return ( <Container backgroundColor={backgroundColor} copyFirst={copyFirst}> @@ -42,49 +34,23 @@ const SingleMessage = ({ width="100%" height="100%" /> - <Copy> - <Text tag="h2" size="xxl" color={textColor}> - {title} - </Text> - {text ? ( - <Text tag="p" size="m" color={textColor}> - {text} - </Text> - ) : null} - {ctaLink ? ( - <Link color={ctaColor} href={ctaLink} target={ctaTarget}> - {ctaText} - </Link> - ) : null} - </Copy> + <Copy>{children}</Copy> </Container> ); }; SingleMessage.propTypes = { - title: PropTypes.string.isRequired, - text: PropTypes.string, - copyFirst: PropTypes.bool, - textColor: PropTypes.string, - ctaText: PropTypes.string, - ctaLink: PropTypes.string, - ctaColor: PropTypes.string, - ctaTarget: PropTypes.string, backgroundColor: PropTypes.string, + copyFirst: PropTypes.bool, // eslint-disable-next-line react/forbid-prop-types imageSet: PropTypes.object, - imageAltText: PropTypes.string + imageAltText: PropTypes.string, + children: PropTypes.node.isRequired }; SingleMessage.defaultProps = { - text: null, - copyFirst: false, - textColor: 'inherit', - ctaText: null, - ctaLink: null, - ctaColor: null, - ctaTarget: null, backgroundColor: 'white', + copyFirst: false, imageSet: null, imageAltText: '' }; diff --git a/src/components/Molecules/SingleMessage/SingleMessage.md b/src/components/Molecules/SingleMessage/SingleMessage.md index b062c6bad..6c80a2486 100644 --- a/src/components/Molecules/SingleMessage/SingleMessage.md +++ b/src/components/Molecules/SingleMessage/SingleMessage.md @@ -2,18 +2,23 @@ Single Message ```js const data = require('../../../styleguide/data/data').default; +import Text from '../../Atoms/Text/Text'; +import Link from '../../Atoms/Link/Link'; <SingleMessage - title={data.title} - text={data.text} - textColor="white" - ctaText={data.ctaText} - ctaLink="/" - ctaColor="red" - ctaTarget="self" backgroundColor="purple" imageSet={data.pictures} imageAltText="" copyFirst={false} -/>; +> + <Text tag="h1" color="white" size="xxl"> + title + </Text> + <Text tag="p" color="white"> + description + </Text> + <Link href="/" color="white"> + CTA + </Link> +</SingleMessage>; ``` diff --git a/src/components/Molecules/SingleMessage/SingleMessage.test.js b/src/components/Molecules/SingleMessage/SingleMessage.test.js index 2794ae2b6..c6b7be6ed 100644 --- a/src/components/Molecules/SingleMessage/SingleMessage.test.js +++ b/src/components/Molecules/SingleMessage/SingleMessage.test.js @@ -3,22 +3,27 @@ import 'jest-styled-components'; import renderWithTheme from '../../../hoc/shallowWithTheme'; import SingleMessage from './SingleMessage'; import data from '../../../styleguide/data/data'; +import Text from '../../Atoms/Text/Text'; +import Link from '../../Atoms/Link/Link'; it('renders correctly', () => { const tree = renderWithTheme( <SingleMessage - title={data.title} - text={data.text} - textColor="white" - ctaText={data.ctaText} - ctaLink="/" - ctaColor="red" - ctaTarget="self" backgroundColor="purple" imageSet={data.pictures} imageAltText="" copyFirst={false} - /> + > + <Text tag="h1" color="white" size="xxl"> + title + </Text> + <Text tag="p" color="white"> + description + </Text> + <Link href="/" color="white"> + CTA + </Link> + </SingleMessage> ).toJSON(); expect(tree).toMatchInlineSnapshot(` @@ -30,7 +35,6 @@ it('renders correctly', () => { .c4 { color: #FFFFFF; - font-size: 1.2rem; text-transform: inherit; } @@ -50,13 +54,7 @@ it('renders correctly', () => { font-weight: 700; border-radius: 30px; cursor: point; - background-color: #f04257; - background: #f04257; - color: #FFFFFF; - } - - .c5:hover { - background: #00beca; + background-color: #FFFFFF; } .c0 { @@ -111,27 +109,26 @@ it('renders correctly', () => { <div className="c2" > - <h2 + <h1 className="c3" color="white" size="xxl" > - What your money does - </h2> + title + </h1> <p className="c4" color="white" - size="m" > - When you donate to Comic Relief or Sport Relief, you’re supporting vulnerable people and communities in the UK and internationally. + description </p> <a className="c5" - color="red" + color="white" href="/" target="_self" > - Find out how + CTA </a> </div> </div> diff --git a/src/theme/shared/fonts.css b/src/theme/shared/fonts.css index 306c53ab2..d46e9a886 100644 --- a/src/theme/shared/fonts.css +++ b/src/theme/shared/fonts.css @@ -17,6 +17,7 @@ h4, h5 { text-transform: uppercase; font-family: 'Anton', Impact, sans-serif; + margin-top: 0; } p, From b261a35a2f7e63ef9d902ff2b4c278aaf2369a93 Mon Sep 17 00:00:00 2001 From: Gustavo Liedke <g.liedke@comicrelief.com> Date: Mon, 8 Jul 2019 15:39:53 +0100 Subject: [PATCH 2/4] Add fullWidth copy only variations --- src/components/Atoms/Picture/Picture.js | 2 +- .../Atoms/RadioButton/RadioButton.js | 6 +- .../Molecules/SingleMessage/SingleMessage.js | 65 ++++++++++++++++--- .../Molecules/SingleMessage/SingleMessage.md | 39 +++++++++++ 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/src/components/Atoms/Picture/Picture.js b/src/components/Atoms/Picture/Picture.js index ad57b8b3f..5374df74f 100644 --- a/src/components/Atoms/Picture/Picture.js +++ b/src/components/Atoms/Picture/Picture.js @@ -58,7 +58,7 @@ const Picture = ({ images, alt, theme, width, height, objectFit }) => { }; Picture.propTypes = { - images: PropTypes.object.isRequired, + images: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, alt: PropTypes.string, objectFit: PropTypes.oneOf([ 'none', diff --git a/src/components/Atoms/RadioButton/RadioButton.js b/src/components/Atoms/RadioButton/RadioButton.js index b04bd48a2..848ea9a25 100644 --- a/src/components/Atoms/RadioButton/RadioButton.js +++ b/src/components/Atoms/RadioButton/RadioButton.js @@ -62,7 +62,7 @@ const Label = styled.label.attrs(({ label }) => ({ const RadioButton = ({ label, name, value, ...rest }) => { return ( - <Label htmlFor={label}> + <Label htmlFor={label.toLowerCase()}> <StyledInput type="radio" {...rest} @@ -71,9 +71,7 @@ const RadioButton = ({ label, name, value, ...rest }) => { id={value} /> <span /> - <Text weight="bold" for={label}> - {label} - </Text> + <Text weight="bold">{label}</Text> </Label> ); }; diff --git a/src/components/Molecules/SingleMessage/SingleMessage.js b/src/components/Molecules/SingleMessage/SingleMessage.js index 52495a9e2..8ffc17bb1 100644 --- a/src/components/Molecules/SingleMessage/SingleMessage.js +++ b/src/components/Molecules/SingleMessage/SingleMessage.js @@ -1,10 +1,11 @@ import React from 'react'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import PropTypes from 'prop-types'; import Picture from '../../Atoms/Picture/Picture'; const Container = styled.div` display: flex; + position: relative; flex-direction: column; background: ${({ theme, backgroundColor }) => theme.color(backgroundColor)}; @media ${({ theme }) => theme.breakpoint('small')} { @@ -16,6 +17,39 @@ const Container = styled.div` const Copy = styled.div` padding: 20px; flex: 0 0 50%; + ${props => + props.fullImage && + css` + position: absolute; + width: 100%; + right: 0; + top: 50%; + transform: translateY(-50%); + ${ + props.copyFirst + ? css` + left: 0; + ` + : null + } + @media ${({ theme }) => theme.breakpoint('small')} { + width: 50%; + } + `}; + ${props => + props.hasImage + ? css` + flex: 0 0 50%; + ` + : css` + flex: 0 0 60%; + margin: auto; + padding: 100px 20px; + `} +`; + +const Image = styled.div` + width: 100%; `; const SingleMessage = ({ @@ -23,18 +57,27 @@ const SingleMessage = ({ copyFirst, imageSet, imageAltText, - children + children, + fullImage }) => { + const hasImage = imageSet || false; + return ( <Container backgroundColor={backgroundColor} copyFirst={copyFirst}> - <Picture - alt={imageAltText} - images={imageSet} - objectFit="cover" - width="100%" - height="100%" - /> - <Copy>{children}</Copy> + {imageSet ? ( + <Image> + <Picture + alt={imageAltText} + images={imageSet} + objectFit="cover" + width="100%" + height="100%" + /> + </Image> + ) : null} + <Copy fullImage={fullImage} hasImage={hasImage} copyFirst={copyFirst}> + {children} + </Copy> </Container> ); }; @@ -42,6 +85,7 @@ const SingleMessage = ({ SingleMessage.propTypes = { backgroundColor: PropTypes.string, copyFirst: PropTypes.bool, + fullImage: PropTypes.bool, // eslint-disable-next-line react/forbid-prop-types imageSet: PropTypes.object, imageAltText: PropTypes.string, @@ -51,6 +95,7 @@ SingleMessage.propTypes = { SingleMessage.defaultProps = { backgroundColor: 'white', copyFirst: false, + fullImage: false, imageSet: null, imageAltText: '' }; diff --git a/src/components/Molecules/SingleMessage/SingleMessage.md b/src/components/Molecules/SingleMessage/SingleMessage.md index 6c80a2486..52bad0fed 100644 --- a/src/components/Molecules/SingleMessage/SingleMessage.md +++ b/src/components/Molecules/SingleMessage/SingleMessage.md @@ -22,3 +22,42 @@ import Link from '../../Atoms/Link/Link'; </Link> </SingleMessage>; ``` + +Single Message fullImage + +```js +const data = require('../../../styleguide/data/data').default; +import Text from '../../Atoms/Text/Text'; +import Link from '../../Atoms/Link/Link'; + +<SingleMessage + backgroundColor="purple" + imageSet={data.pictures} + imageAltText="" + copyFirst={false} + fullImage={true} +> + <Text tag="h1" color="white" size="xxl"> + title + </Text> + <Text tag="p" color="white"> + description + </Text> + <Link href="/" color="white"> + CTA + </Link> +</SingleMessage>; +``` + +Single Message with no Image + +```js +import Text from '../../Atoms/Text/Text'; + +<SingleMessage backgroundColor="purple" copyFirst={false}> + <Text tag="p" color="white" size="xxl"> + “The creativity that goes into helping people have a better life is + extraordinary.” + </Text> +</SingleMessage>; +``` From 2d1ac6a17f38e02d06dfa864b2875b7046071055 Mon Sep 17 00:00:00 2001 From: Gustavo Liedke <g.liedke@comicrelief.com> Date: Mon, 8 Jul 2019 15:48:19 +0100 Subject: [PATCH 3/4] update tests --- .../Atoms/RadioButton/RadioButton.test.js | 6 +- .../SingleMessage/SingleMessage.test.js | 266 +++++++++++++----- 2 files changed, 205 insertions(+), 67 deletions(-) diff --git a/src/components/Atoms/RadioButton/RadioButton.test.js b/src/components/Atoms/RadioButton/RadioButton.test.js index 6af6f5ba5..1b58547cc 100644 --- a/src/components/Atoms/RadioButton/RadioButton.test.js +++ b/src/components/Atoms/RadioButton/RadioButton.test.js @@ -75,7 +75,7 @@ it('renders correctly', () => { <label className="c0" - htmlFor="Male" + htmlFor="male" > <input className="c1" @@ -88,7 +88,6 @@ it('renders correctly', () => { <span className="c2" color="inherit" - for="Male" > Male </span> @@ -155,7 +154,7 @@ it('renders correctly', () => { <label className="c0" - htmlFor="Female" + htmlFor="female" > <input className="c1" @@ -168,7 +167,6 @@ it('renders correctly', () => { <span className="c2" color="inherit" - for="Female" > Female </span> diff --git a/src/components/Molecules/SingleMessage/SingleMessage.test.js b/src/components/Molecules/SingleMessage/SingleMessage.test.js index c6b7be6ed..0f57deff8 100644 --- a/src/components/Molecules/SingleMessage/SingleMessage.test.js +++ b/src/components/Molecules/SingleMessage/SingleMessage.test.js @@ -27,34 +27,203 @@ it('renders correctly', () => { ).toJSON(); expect(tree).toMatchInlineSnapshot(` - .c3 { - color: #FFFFFF; - font-size: 2.075rem; - text-transform: inherit; - } + .c4 { + color: #FFFFFF; + font-size: 2.075rem; + text-transform: inherit; + } - .c4 { - color: #FFFFFF; - text-transform: inherit; - } + .c5 { + color: #FFFFFF; + text-transform: inherit; + } - .c1 { - display: block; - width: 100%; - height: 100%; - object-fit: cover; - } + .c2 { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + } + + .c6 { + display: inline-block; + padding: 16px 30px; + text-align: center; + -webkit-text-decoration: none; + text-decoration: none; + font-weight: 700; + border-radius: 30px; + cursor: point; + background-color: #FFFFFF; + } + + .c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + position: relative; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + background: #7d2ca9; + } + + .c3 { + padding: 20px; + -webkit-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + -webkit-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + } + + .c1 { + width: 100%; + } + + @media (min-width:740px) { + .c0 { + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + } + + <div + className="c0" + > + <div + className="c1" + > + <picture> + <source + media="(min-width: 1440px)" + srcSet="picture-3.jpg" + /> + <source + media="(min-width: 1024px)" + srcSet="picture-2.jpg" + /> + <source + srcSet="picture-1.jpg" + /> + <img + alt="" + className="c2" + height="100%" + src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" + width="100%" + /> + </picture> + </div> + <div + className="c3" + > + <h1 + className="c4" + color="white" + size="xxl" + > + title + </h1> + <p + className="c5" + color="white" + > + description + </p> + <a + className="c6" + color="white" + href="/" + target="_self" + > + CTA + </a> + </div> + </div> + `); +}); + +it('renders Single Message with no Image correctly', () => { + const tree = renderWithTheme( + <SingleMessage backgroundColor="purple" copyFirst={false}> + <Text tag="p" color="white"> + description + </Text> + </SingleMessage> + ).toJSON(); + + expect(tree).toMatchInlineSnapshot(` + .c2 { + color: #FFFFFF; + text-transform: inherit; + } - .c5 { - display: inline-block; - padding: 16px 30px; - text-align: center; - -webkit-text-decoration: none; - text-decoration: none; - font-weight: 700; - border-radius: 30px; - cursor: point; - background-color: #FFFFFF; + .c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + position: relative; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + background: #7d2ca9; + } + + .c1 { + padding: 20px; + -webkit-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + -webkit-flex: 0 0 60%; + -ms-flex: 0 0 60%; + flex: 0 0 60%; + margin: auto; + padding: 100px 20px; + } + + @media (min-width:740px) { + .c0 { + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + } + + <div + className="c0" + > + <div + className="c1" + > + <p + className="c2" + color="white" + > + description + </p> + </div> + </div> + `); +}); + +it('renders fullWidth Single Message correctly', () => { + const tree = renderWithTheme( + <SingleMessage backgroundColor="purple" copyFirst={false}> + <Text tag="p" color="white"> + description + </Text> + </SingleMessage> + ).toJSON(); + + expect(tree).toMatchInlineSnapshot(` + .c2 { + color: #FFFFFF; + text-transform: inherit; } .c0 { @@ -62,17 +231,23 @@ it('renders correctly', () => { display: -webkit-flex; display: -ms-flexbox; display: flex; + position: relative; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; background: #7d2ca9; } - .c2 { + .c1 { padding: 20px; -webkit-flex: 0 0 50%; -ms-flex: 0 0 50%; flex: 0 0 50%; + -webkit-flex: 0 0 60%; + -ms-flex: 0 0 60%; + flex: 0 0 60%; + margin: auto; + padding: 100px 20px; } @media (min-width:740px) { @@ -86,50 +261,15 @@ it('renders correctly', () => { <div className="c0" > - <picture> - <source - media="(min-width: 1440px)" - srcSet="picture-3.jpg" - /> - <source - media="(min-width: 1024px)" - srcSet="picture-2.jpg" - /> - <source - srcSet="picture-1.jpg" - /> - <img - alt="" - className="c1" - height="100%" - src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" - width="100%" - /> - </picture> <div - className="c2" + className="c1" > - <h1 - className="c3" - color="white" - size="xxl" - > - title - </h1> <p - className="c4" + className="c2" color="white" > description </p> - <a - className="c5" - color="white" - href="/" - target="_self" - > - CTA - </a> </div> </div> `); From a5de3cd2349fd9d4a6878ad620ca682d3b38df85 Mon Sep 17 00:00:00 2001 From: Gustavo Liedke <g.liedke@comicrelief.com> Date: Mon, 8 Jul 2019 16:21:33 +0100 Subject: [PATCH 4/4] fix types --- src/components/Atoms/Picture/Picture.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/Atoms/Picture/Picture.js b/src/components/Atoms/Picture/Picture.js index 5374df74f..a05229129 100644 --- a/src/components/Atoms/Picture/Picture.js +++ b/src/components/Atoms/Picture/Picture.js @@ -1,6 +1,3 @@ -/* eslint-disable react/forbid-prop-types */ -/* eslint-disable react/prop-types */ -/* fix theme, breakpoint and object types */ import React from 'react'; import styled, { withTheme } from 'styled-components'; import PropTypes from 'prop-types'; @@ -58,7 +55,10 @@ const Picture = ({ images, alt, theme, width, height, objectFit }) => { }; Picture.propTypes = { - images: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, + images: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.shape({ picture: PropTypes.string }) + ]).isRequired, alt: PropTypes.string, objectFit: PropTypes.oneOf([ 'none', @@ -68,7 +68,10 @@ Picture.propTypes = { 'scale-down' ]), width: PropTypes.string, - height: PropTypes.string + height: PropTypes.string, + theme: PropTypes.shape({ + breakpoint: PropTypes.func + }).isRequired }; Picture.defaultProps = {