{
height: 100px;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
{
+import React from "react";
+import "jest-styled-components";
+import renderWithTheme from "../../../hoc/shallowWithTheme";
+import ArticleTeaser from "./ArticleTeaser";
+import { defaultData } from "../../../styleguide/data/data";
+it("renders article teaser correctly", () => {
const tree = renderWithTheme(
{
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c1 {
@@ -258,7 +259,7 @@ it('renders article teaser correctly', () => {
`);
});
-it('renders press realese correctly', () => {
+it("renders press realese correctly", () => {
const tree = renderWithTheme(
{
height: 80px;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c1 {
diff --git a/src/components/Molecules/Card/__snapshots__/Card.test.js.snap b/src/components/Molecules/Card/__snapshots__/Card.test.js.snap
index a43d1e642..e97070d1b 100644
--- a/src/components/Molecules/Card/__snapshots__/Card.test.js.snap
+++ b/src/components/Molecules/Card/__snapshots__/Card.test.js.snap
@@ -54,6 +54,7 @@ exports[`renders correctly with no body 1`] = `
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c0 {
diff --git a/src/components/Molecules/CardDs/__snapshots__/CardDs.test.js.snap b/src/components/Molecules/CardDs/__snapshots__/CardDs.test.js.snap
index 7d0c2fb18..24cc4bc38 100644
--- a/src/components/Molecules/CardDs/__snapshots__/CardDs.test.js.snap
+++ b/src/components/Molecules/CardDs/__snapshots__/CardDs.test.js.snap
@@ -13,6 +13,7 @@ exports[`renders correctly 1`] = `
height: auto;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c8 {
diff --git a/src/components/Molecules/Promo/__snapshots__/Promo.test.js.snap b/src/components/Molecules/Promo/__snapshots__/Promo.test.js.snap
index 0f12f43e0..1e94aab69 100644
--- a/src/components/Molecules/Promo/__snapshots__/Promo.test.js.snap
+++ b/src/components/Molecules/Promo/__snapshots__/Promo.test.js.snap
@@ -37,6 +37,7 @@ exports[`renders Promo correctly 1`] = `
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c8 {
@@ -278,6 +279,7 @@ exports[`renders Promo correctly end position 1`] = `
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c8 {
diff --git a/src/components/Molecules/SingleMessage/__snapshots__/SingleMessage.test.js.snap b/src/components/Molecules/SingleMessage/__snapshots__/SingleMessage.test.js.snap
index 2135186af..cc8367312 100644
--- a/src/components/Molecules/SingleMessage/__snapshots__/SingleMessage.test.js.snap
+++ b/src/components/Molecules/SingleMessage/__snapshots__/SingleMessage.test.js.snap
@@ -22,6 +22,7 @@ exports[`renders Single Message with 100% vertical height image correctly 1`] =
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c0 {
@@ -197,6 +198,7 @@ exports[`renders Single Message with Image correctly 1`] = `
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c8 {
@@ -411,6 +413,7 @@ exports[`renders Single Message with double image correctly 1`] = `
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c0 {
@@ -631,6 +634,7 @@ exports[`renders Single Message with full width correctly 1`] = `
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c8 {
@@ -859,6 +863,7 @@ exports[`renders Single Message with full width image and no text correctly 1`]
height: 100%;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c0 {
diff --git a/src/components/Molecules/SingleMessageDS/SingleMessageDs.js b/src/components/Molecules/SingleMessageDS/SingleMessageDs.js
index aadb8e773..2b1dc9fc2 100644
--- a/src/components/Molecules/SingleMessageDS/SingleMessageDs.js
+++ b/src/components/Molecules/SingleMessageDS/SingleMessageDs.js
@@ -27,11 +27,11 @@ const SingleMessageDs = ({
target,
linkIcon,
youTubeId,
+ focalPoint,
...rest
}) => {
const [isOpen, setIsOpen] = useState(false);
- // const openModal = () => setIsOpen(true);
const closeModal = () => setIsOpen(false);
const Media = (
@@ -44,6 +44,7 @@ const SingleMessageDs = ({
objectFit="cover"
width={width}
height={height}
+ focalPoint={focalPoint}
/>
);
@@ -187,7 +188,13 @@ SingleMessageDs.propTypes = {
target: PropTypes.string,
children: PropTypes.node.isRequired,
linkIcon: PropTypes.node,
- youTubeId: PropTypes.string
+ youTubeId: PropTypes.string,
+ focalPoint: PropTypes.shape({
+ focalPointX: PropTypes.number,
+ focalPointY: PropTypes.number,
+ rawImageWidth: PropTypes.number,
+ rawImageHeight: PropTypes.number
+ })
};
SingleMessageDs.defaultProps = {
@@ -203,7 +210,13 @@ SingleMessageDs.defaultProps = {
width: '100%',
height: '100%',
linkIcon: null,
- youTubeId: null
+ youTubeId: null,
+ focalPoint: {
+ focalPointX: null,
+ focalPointY: null,
+ rawImageWidth: null,
+ rawImageHeigh: null
+ }
};
export default SingleMessageDs;
diff --git a/src/components/Molecules/SingleMessageDS/SingleMessageDs.md b/src/components/Molecules/SingleMessageDS/SingleMessageDs.md
index 6d727e241..bd979863a 100644
--- a/src/components/Molecules/SingleMessageDS/SingleMessageDs.md
+++ b/src/components/Molecules/SingleMessageDS/SingleMessageDs.md
@@ -185,4 +185,122 @@ import Download from '../../Atoms/Icons/Download';
;
+```
+
+## FocalPoint example 1
+
+```js
+const focalPointImages = require('../../../styleguide/data/data').focalPointImages;
+import Text from '../../Atoms/Text/Text';
+import Link from '../../Atoms/Link/Link';
+import styled from 'styled-components';
+import spacing from '../../../theme/shared/spacing';
+
+// These will come directly via the CMS query in the proper CRcom
+// context; I've just hardcoded the actual size values from the example
+// image and focal point that focuses on the subject.
+const exampleFocalPoint = {
+ rawImageWidth: 2000,
+ rawImageHeight: 945,
+ focalPointX: 1450,
+ focalPointY: 350
+};
+
+const Title = styled(Text)`
+ letter-spacing: 0.03em;
+ text-transform: uppercase;
+ margin: ${spacing('md')} 0;
+ @media ${({ theme }) => theme.breakpoint('small')} {
+ margin-bottom: ${spacing('m')};
+ }
+`;
+
+
+
+ Heading Line 1 Heading Line 2
+
+
+ Whatever you’ve got planned, the Sport Relief shop has everything you need
+ to get you looking your best while you’re raising some cash. Also
+ available in Sainsbury’s stores and online and in selected Argos stores.
+
+
+
;
+```
+
+## FocalPoint example 2
+
+```js
+const focalPointImagesTwo = require('../../../styleguide/data/data').focalPointImagesTwo;
+import Text from '../../Atoms/Text/Text';
+import Link from '../../Atoms/Link/Link';
+import styled from 'styled-components';
+import spacing from '../../../theme/shared/spacing';
+
+// These will come directly via the CMS query in the proper CRcom
+// context; I've just hardcoded the actual size values from the example
+// image and focal point that focuses on the subject.
+const exampleFocalPoint = {
+ rawImageWidth: 1872,
+ rawImageHeight: 686,
+ focalPointX: 440, // Tall skyscraper on the left
+ focalPointY: 240
+};
+
+const Title = styled(Text)`
+ letter-spacing: 0.03em;
+ text-transform: uppercase;
+ margin: ${spacing('md')} 0;
+ @media ${({ theme }) => theme.breakpoint('small')} {
+ margin-bottom: ${spacing('m')};
+ }
+`;
+
+
+
+ Heading Line 1 Heading Line 2
+
+
+ Whatever you’ve got planned, the Sport Relief shop has everything you need
+ to get you looking your best while you’re raising some cash. Also
+ available in Sainsbury’s stores and online and in selected Argos stores.
+
+
+
;
```
\ No newline at end of file
diff --git a/src/components/Molecules/SingleMessageDS/__snapshots__/SingleMessageDs.test.js.snap b/src/components/Molecules/SingleMessageDS/__snapshots__/SingleMessageDs.test.js.snap
index 202b8079c..e0bea3b90 100644
--- a/src/components/Molecules/SingleMessageDS/__snapshots__/SingleMessageDs.test.js.snap
+++ b/src/components/Molecules/SingleMessageDS/__snapshots__/SingleMessageDs.test.js.snap
@@ -31,6 +31,7 @@ exports[`renders correctly 1`] = `
height: auto;
display: block;
object-fit: cover;
+ object-position: NaN% NaN%;
}
.c12 {
diff --git a/src/styleguide/data/data.js b/src/styleguide/data/data.js
index 41bda798e..1515d89f5 100644
--- a/src/styleguide/data/data.js
+++ b/src/styleguide/data/data.js
@@ -26,4 +26,24 @@ const mobileImages = {
'//https://images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=200&h=150&q=50 200w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=400&h=300&q=50 400w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=800&h=600&q=50 800w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=1200&h=900&q=50 1200w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=1440&h=1080&q=50 1440w'
};
-export { defaultData, mobileImages };
+const focalPointImages = {
+ imageLow:
+ 'http://images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=100&h=50&q=100',
+ image:
+ 'https://images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg',
+ images:
+ '//https://images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=200&h=150&q=50 200w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=400&h=300&q=50 400w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=800&h=600&q=50 800w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=1200&h=900&q=50 1200w,//images.ctfassets.net/zsfivwzfgl3t/54DHIEgtwbr9TDkf70lToB/ffe8d6a8e9bbc224343f475a5c55c832/-CROP-Promo-Des_2000x945-_Kate.jpg?w=1440&h=1080&q=50 1440w'
+};
+
+const focalPointImagesTwo = {
+ imageLow:
+ 'https://images.ctfassets.net/zsfivwzfgl3t/YzhX9IaivFhLPecCoHrOf/0918e3bbbde4d8d0f00ba0d2ca0ab16d/panorama.png?w=100&h=50&q=100',
+ image:
+ 'https://images.ctfassets.net/zsfivwzfgl3t/YzhX9IaivFhLPecCoHrOf/0918e3bbbde4d8d0f00ba0d2ca0ab16d/panorama.png',
+ images:
+ '//https://images.ctfassets.net/zsfivwzfgl3t/YzhX9IaivFhLPecCoHrOf/0918e3bbbde4d8d0f00ba0d2ca0ab16d/panorama.png?w=200&h=150&q=50 200w,//images.ctfassets.net/zsfivwzfgl3t/YzhX9IaivFhLPecCoHrOf/0918e3bbbde4d8d0f00ba0d2ca0ab16d/panorama.png?w=400&h=300&q=50 400w,//images.ctfassets.net/zsfivwzfgl3t/YzhX9IaivFhLPecCoHrOf/0918e3bbbde4d8d0f00ba0d2ca0ab16d/panorama.png?w=800&h=600&q=50 800w,//images.ctfassets.net/zsfivwzfgl3t/YzhX9IaivFhLPecCoHrOf/0918e3bbbde4d8d0f00ba0d2ca0ab16d/panorama.png?w=1200&h=900&q=50 1200w,//images.ctfassets.net/zsfivwzfgl3t/YzhX9IaivFhLPecCoHrOf/0918e3bbbde4d8d0f00ba0d2ca0ab16d/panorama.png?w=1440&h=1080&q=50 1440w'
+};
+
+export {
+ defaultData, mobileImages, focalPointImages, focalPointImagesTwo
+};
diff --git a/src/utils/focalPointCalc.js b/src/utils/focalPointCalc.js
new file mode 100644
index 000000000..78070cd7e
--- /dev/null
+++ b/src/utils/focalPointCalc.js
@@ -0,0 +1,31 @@
+/* A handy to make the percentage math nice and reusable */
+const focalPointCalc = focalPointData => {
+ // Calculate the focal points as percentages of the image dimensions
+ let x = (focalPointData.focalPointX / focalPointData.rawImageWidth) * 100;
+ let y = (focalPointData.focalPointY / focalPointData.rawImageHeight) * 100;
+
+ // Some ugly maths to basically just sweetenen the percentage, resulting
+ // in a slightly higher value (up to * 1.1 around the 25% and 75% points)
+ // to get the position close to what we actually want visually with our
+ // fluid layout and 'cover' object-fit CSS rule
+
+ const maths = true;
+
+ if (maths) {
+ x *= (0.1 / 25) * (25 - Math.abs((x % (2 * 25)) - 25)) + 1;
+ y *= (0.1 / 25) * (25 - Math.abs((y % (2 * 25)) - 25)) + 1;
+ }
+
+ // Round-up for best browser compatibility
+ x = Math.round(x);
+ y = Math.round(y);
+
+ // Return this directly as a percentage to be used within CSS;
+ // hard pixel values won't ever work, given that fluid layout
+ return {
+ x: `${x}%`,
+ y: `${y}%`
+ };
+};
+
+export default focalPointCalc;