@comicrelief/component-library 8.44.4 → 8.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/components/Atoms/SocialIcons/Icon/Icon.js +39 -14
  2. package/dist/components/Atoms/SocialIcons/SocialIcons.js +91 -22
  3. package/dist/components/Atoms/SocialIcons/Utils/Icons.js +26 -7
  4. package/dist/components/Atoms/SocialIcons/Utils/Links.js +10 -0
  5. package/dist/components/Atoms/SocialIcons/__snapshots__/SocialIcons.test.js.snap +63 -48
  6. package/{src/components/Atoms/SocialIcons/assets → dist/components/Atoms/SocialIcons/assets/circled}/facebook.svg +1 -1
  7. package/{src/components/Atoms/SocialIcons/assets → dist/components/Atoms/SocialIcons/assets/circled}/twitter.svg +1 -1
  8. package/dist/components/Atoms/SocialIcons/assets/{youtube.svg → circled/youtube.svg} +1 -1
  9. package/dist/components/Atoms/SocialIcons/assets/standard/facebook.svg +3 -0
  10. package/dist/components/Atoms/SocialIcons/assets/standard/instagram.svg +3 -0
  11. package/dist/components/Atoms/SocialIcons/assets/standard/tiktok.svg +3 -0
  12. package/dist/components/Atoms/SocialIcons/assets/standard/x.svg +3 -0
  13. package/dist/components/Atoms/SocialIcons/assets/standard/youtube.svg +3 -0
  14. package/dist/components/Molecules/EmailSignUp/EmailSignUp.js +38 -0
  15. package/dist/components/Molecules/EmailSignUp/EmailSignUp.style.js +113 -0
  16. package/dist/components/Molecules/LogoLinked/LogoLinked.js +6 -6
  17. package/dist/components/Organisms/Footer/Footer.md +12 -11
  18. package/dist/components/Organisms/Footer/FundraisingRegulatorLogo/FundraisingRegulatorLogo.js +36 -16
  19. package/dist/components/Organisms/Footer/Nav/Nav.style.js +8 -8
  20. package/dist/components/Organisms/Footer/__snapshots__/Footer.test.js.snap +188 -183
  21. package/dist/components/Organisms/FooterNew/FooterNew.js +136 -0
  22. package/dist/components/Organisms/FooterNew/FooterNew.md +47 -0
  23. package/dist/components/Organisms/FooterNew/FooterNew.style.js +312 -0
  24. package/dist/components/Organisms/FooterNew/FooterNew.test.js +20 -0
  25. package/dist/components/Organisms/FooterNew/Nav/PrimaryNav.js +32 -0
  26. package/dist/components/Organisms/FooterNew/Nav/SecondaryNav.js +32 -0
  27. package/dist/components/Organisms/FooterNew/__snapshots__/FooterNew.test.js.snap +1490 -0
  28. package/dist/components/Organisms/FooterNew/dev-data/data.js +106 -0
  29. package/dist/index.js +20 -0
  30. package/dist/theme/crTheme/colors.js +12 -7
  31. package/dist/theme/shared/animations.js +46 -0
  32. package/package.json +1 -1
  33. package/src/components/Atoms/SocialIcons/Icon/Icon.js +47 -11
  34. package/src/components/Atoms/SocialIcons/SocialIcons.js +99 -25
  35. package/src/components/Atoms/SocialIcons/Utils/Icons.js +29 -10
  36. package/src/components/Atoms/SocialIcons/Utils/Links.js +10 -0
  37. package/src/components/Atoms/SocialIcons/__snapshots__/SocialIcons.test.js.snap +63 -48
  38. package/{dist/components/Atoms/SocialIcons/assets → src/components/Atoms/SocialIcons/assets/circled}/facebook.svg +1 -1
  39. package/{dist/components/Atoms/SocialIcons/assets → src/components/Atoms/SocialIcons/assets/circled}/twitter.svg +1 -1
  40. package/src/components/Atoms/SocialIcons/assets/{youtube.svg → circled/youtube.svg} +1 -1
  41. package/src/components/Atoms/SocialIcons/assets/standard/facebook.svg +3 -0
  42. package/src/components/Atoms/SocialIcons/assets/standard/instagram.svg +3 -0
  43. package/src/components/Atoms/SocialIcons/assets/standard/tiktok.svg +3 -0
  44. package/src/components/Atoms/SocialIcons/assets/standard/x.svg +3 -0
  45. package/src/components/Atoms/SocialIcons/assets/standard/youtube.svg +3 -0
  46. package/src/components/Molecules/EmailSignUp/EmailSignUp.js +55 -0
  47. package/src/components/Molecules/EmailSignUp/EmailSignUp.style.js +107 -0
  48. package/src/components/Molecules/LogoLinked/LogoLinked.js +5 -14
  49. package/src/components/Organisms/Footer/Footer.md +12 -11
  50. package/src/components/Organisms/Footer/FundraisingRegulatorLogo/FundraisingRegulatorLogo.js +14 -3
  51. package/src/components/Organisms/Footer/Nav/Nav.style.js +8 -8
  52. package/src/components/Organisms/Footer/__snapshots__/Footer.test.js.snap +188 -183
  53. package/src/components/Organisms/FooterNew/FooterNew.js +211 -0
  54. package/src/components/Organisms/FooterNew/FooterNew.md +47 -0
  55. package/src/components/Organisms/FooterNew/FooterNew.style.js +294 -0
  56. package/src/components/Organisms/FooterNew/FooterNew.test.js +24 -0
  57. package/src/components/Organisms/FooterNew/Nav/PrimaryNav.js +54 -0
  58. package/src/components/Organisms/FooterNew/Nav/SecondaryNav.js +54 -0
  59. package/src/components/Organisms/FooterNew/__snapshots__/FooterNew.test.js.snap +1490 -0
  60. package/src/components/Organisms/FooterNew/dev-data/data.js +123 -0
  61. package/src/index.js +2 -0
  62. package/src/theme/crTheme/colors.js +13 -7
  63. package/src/theme/shared/animations.js +60 -0
  64. /package/dist/components/Atoms/SocialIcons/assets/{X-white-Subtract.svg → circled/X-white-Subtract.svg} +0 -0
  65. /package/dist/components/Atoms/SocialIcons/assets/{instagram.svg → circled/instagram.svg} +0 -0
  66. /package/src/components/Atoms/SocialIcons/assets/{X-white-Subtract.svg → circled/X-white-Subtract.svg} +0 -0
  67. /package/src/components/Atoms/SocialIcons/assets/{instagram.svg → circled/instagram.svg} +0 -0
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.testSecondaryLinksList = exports.testPrimaryLinksList = exports.secondaryLinksList = exports.primaryLinksList = void 0;
7
+ const primaryLinksList = exports.primaryLinksList = [{
8
+ title: 'Contact us',
9
+ path: 'contact-us',
10
+ internal: {
11
+ type: 'ContentfulPageLandingPage'
12
+ }
13
+ }, {
14
+ title: 'Update your preferences',
15
+ path: 'https://www.comicrelief.com/update-your-preferences',
16
+ internal: {
17
+ type: 'ContentfulPageLandingPage'
18
+ }
19
+ }, {
20
+ title: 'Your Gift Aid',
21
+ path: 'https://giftaid.comicrelief.com/update',
22
+ internal: {
23
+ type: 'ContentfulPageLandingPage'
24
+ }
25
+ }, {
26
+ title: 'Reporting complaints and concerns',
27
+ path: 'https://www.comicrelief.com/reporting-complaints',
28
+ internal: {
29
+ type: 'ContentfulPageLandingPage'
30
+ }
31
+ }, {
32
+ title: 'FAQs',
33
+ path: 'https://www.comicrelief.com/frequently-asked-questions',
34
+ internal: {
35
+ type: 'ContentfulPageLandingPage'
36
+ }
37
+ }];
38
+ const secondaryLinksList = exports.secondaryLinksList = [{
39
+ title: 'Terms of use',
40
+ path: 'https://www.comicrelief.com/terms-of-use',
41
+ internal: {
42
+ type: 'ContentfulPageLandingPage'
43
+ }
44
+ }, {
45
+ title: 'Privacy notice',
46
+ path: 'https://www.comicrelief.com/privacy-notice',
47
+ internal: {
48
+ type: 'ContentfulPageLandingPage'
49
+ }
50
+ }, {
51
+ title: 'Cookies',
52
+ path: 'https://www.comicrelief.com/cookies',
53
+ internal: {
54
+ type: 'ContentfulPageLandingPage'
55
+ }
56
+ }, {
57
+ title: 'Text to donate terms',
58
+ path: 'https://www.comicrelief.com/text-to-donate-terms',
59
+ internal: {
60
+ type: 'ContentfulPageLandingPage'
61
+ }
62
+ }, {
63
+ title: 'Prize draw terms',
64
+ path: 'https://www.comicrelief.com/prize-draw-terms',
65
+ internal: {
66
+ type: 'ContentfulPageLandingPage'
67
+ }
68
+ }, {
69
+ title: 'Modern Slavery and Human Trafficking Statement',
70
+ path: 'https://www.comicrelief.com/modern-slavery-statement',
71
+ internal: {
72
+ type: 'ContentfulPageLandingPage'
73
+ }
74
+ }, {
75
+ title: 'Positive Practices',
76
+ path: 'https://www.comicrelief.com/positive-practices',
77
+ internal: {
78
+ type: 'ContentfulPageLandingPage'
79
+ }
80
+ }];
81
+ const testPrimaryLinksList = exports.testPrimaryLinksList = [{
82
+ title: 'Contact us',
83
+ path: 'contact-us',
84
+ internal: {
85
+ type: 'ContentfulPageLandingPage'
86
+ }
87
+ }, {
88
+ title: 'FAQs',
89
+ path: 'https://www.comicrelief.com/frequently-asked-questions',
90
+ internal: {
91
+ type: 'ContentfulPageLandingPage'
92
+ }
93
+ }];
94
+ const testSecondaryLinksList = exports.testSecondaryLinksList = [{
95
+ title: 'Terms of use',
96
+ path: 'https://www.comicrelief.com/terms-of-use',
97
+ internal: {
98
+ type: 'ContentfulPageLandingPage'
99
+ }
100
+ }, {
101
+ title: 'Privacy notice',
102
+ path: 'https://www.comicrelief.com/privacy-notice',
103
+ internal: {
104
+ type: 'ContentfulPageLandingPage'
105
+ }
106
+ }];
package/dist/index.js CHANGED
@@ -130,6 +130,12 @@ Object.defineProperty(exports, "Footer", {
130
130
  return _Footer.default;
131
131
  }
132
132
  });
133
+ Object.defineProperty(exports, "FooterNew", {
134
+ enumerable: true,
135
+ get: function () {
136
+ return _FooterNew.default;
137
+ }
138
+ });
133
139
  Object.defineProperty(exports, "Header", {
134
140
  enumerable: true,
135
141
  get: function () {
@@ -400,6 +406,12 @@ Object.defineProperty(exports, "hideVisually", {
400
406
  return _hideVisually.default;
401
407
  }
402
408
  });
409
+ Object.defineProperty(exports, "logoRotateAnimation", {
410
+ enumerable: true,
411
+ get: function () {
412
+ return _animations.logoRotateAnimation;
413
+ }
414
+ });
403
415
  Object.defineProperty(exports, "setInitialValues", {
404
416
  enumerable: true,
405
417
  get: function () {
@@ -412,6 +424,12 @@ Object.defineProperty(exports, "spacing", {
412
424
  return _spacing.default;
413
425
  }
414
426
  });
427
+ Object.defineProperty(exports, "springScaleAnimation", {
428
+ enumerable: true,
429
+ get: function () {
430
+ return _animations.springScaleAnimation;
431
+ }
432
+ });
415
433
  Object.defineProperty(exports, "zIndex", {
416
434
  enumerable: true,
417
435
  get: function () {
@@ -426,6 +444,7 @@ var _allowListed = _interopRequireDefault(require("./utils/allowListed"));
426
444
  var _spacing = _interopRequireDefault(require("./theme/shared/spacing"));
427
445
  var _allBreakpoints = _interopRequireDefault(require("./theme/shared/allBreakpoints"));
428
446
  var _containers = _interopRequireDefault(require("./theme/shared/containers"));
447
+ var _animations = require("./theme/shared/animations");
429
448
  var _Text = _interopRequireDefault(require("./components/Atoms/Text/Text"));
430
449
  var _Logo = _interopRequireDefault(require("./components/Atoms/Logo/Logo"));
431
450
  var _Picture = _interopRequireDefault(require("./components/Atoms/Picture/Picture"));
@@ -459,6 +478,7 @@ var _Donate = _interopRequireDefault(require("./components/Organisms/Donate/Dona
459
478
  var _DoubleCopy = _interopRequireDefault(require("./components/Molecules/DoubleCopy/DoubleCopy"));
460
479
  var _PartnerLink = _interopRequireDefault(require("./components/Molecules/PartnerLink/PartnerLink"));
461
480
  var _Footer = _interopRequireDefault(require("./components/Organisms/Footer/Footer"));
481
+ var _FooterNew = _interopRequireDefault(require("./components/Organisms/FooterNew/FooterNew"));
462
482
  var _SearchResult = _interopRequireDefault(require("./components/Molecules/SearchResult/SearchResult"));
463
483
  var _SearchInput = _interopRequireDefault(require("./components/Molecules/SearchInput/SearchInput"));
464
484
  var _ShareButton = _interopRequireDefault(require("./components/Molecules/ShareButton/ShareButton"));
@@ -33,17 +33,22 @@ const colors = {
33
33
  grey_extra_light: '#f0f0f0',
34
34
  grey_for_forms: '#666',
35
35
  grey_label: '#5C5C5E',
36
- // this is the Curtis approved list of 5 greys that will be later numbered grey_1 thru grey_5
37
- // grey_1
36
+ grey_1: '#FFFFFF',
38
37
  grey_light: '#F4F3F5',
39
- // grey_2
40
38
  grey_medium: '#E1E2E3',
41
- // grey_3
39
+ grey_2: '#E1E2E3',
40
+ // TODO: 'grey' is actually 'grey_3'. It is referenced in many places.
41
+ // We need to rename it to 'grey_3' across all references.
42
+ // Until then, we need to keep both names for backwards compatibility.
43
+ // Same story with 'grey_medium' - it should be grey_2, and
44
+ // grey_dark, should be grey_4.
45
+ // For the time being we need both of each. I will provision a separate PR.
42
46
  grey: '#969598',
43
- // grey_4
44
- grey_4: '#6E6E6E',
45
- // grey_5
47
+ grey_3: '#969598',
46
48
  grey_dark: '#222222',
49
+ grey_4: '#222222',
50
+ grey_4_hover: '#3A3A3A',
51
+ grey_5: '#18181A',
47
52
  /* GENERAL COLOURS */
48
53
  blue: '#0565D1',
49
54
  blue_dark: '#274084',
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.springScaleAnimation = exports.logoRotateAnimation = void 0;
7
+ var _styledComponents = require("styled-components");
8
+ /**
9
+ * Logo rotation animation on hover
10
+ * Applies a rotation transition that rotates the logo (or whatever else)
11
+ * -14deg on hover/focus
12
+ * @param {boolean} animateRotate - Whether to enable the rotation animation
13
+ * @returns {css} template literal for the animation
14
+ */
15
+ const logoRotateAnimation = animateRotate => {
16
+ if (!animateRotate) {
17
+ return (0, _styledComponents.css)([""]);
18
+ }
19
+ return (0, _styledComponents.css)(["img{transition:transform 0.6s cubic-bezier(0.41,1.64,0.41,0.8);}&:hover,&:focus{img{transform:rotate(-14deg);}}"]);
20
+ };
21
+
22
+ /**
23
+ * Spring scale animation on hover
24
+ * Applies a smooth spring-like scale transition that expands the element on hover/focus
25
+ * @param {boolean} animateScale - Whether to enable the scale animation
26
+ * @param {number} scaleFactor - Scale factor to apply on hover (default 8%)
27
+ * @param {number} bounceIntensity - Intensity of the springy bounce effect (0-3, default: 1)
28
+ * @returns {css} template literal for the animation
29
+ */
30
+ exports.logoRotateAnimation = logoRotateAnimation;
31
+ const springScaleAnimation = function (animateScale) {
32
+ let scaleFactor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1.08;
33
+ let bounceIntensity = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
34
+ if (!animateScale) {
35
+ return (0, _styledComponents.css)([""]);
36
+ }
37
+
38
+ // More negative pull-back and higher overshoot = more bounce
39
+ // Default intensity (1) gives: cubic-bezier(0.68, -0.85, 0.265, 1.95)
40
+ // Higher intensity = more pronounced bounce effect
41
+ const pullBack = -0.55 - bounceIntensity * 0.3;
42
+ const overshoot = 1.55 + bounceIntensity * 0.4;
43
+ const duration = 0.2 + bounceIntensity * 0.1;
44
+ return (0, _styledComponents.css)(["transition:transform ", "s cubic-bezier(0.68,", ",0.265,", ");transform-origin:center;&:hover,&:focus{transform:scale(", ");}"], duration, pullBack, overshoot, scaleFactor);
45
+ };
46
+ exports.springScaleAnimation = springScaleAnimation;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comicrelief/component-library",
3
3
  "author": "Comic Relief Engineering Team",
4
- "version": "8.44.4",
4
+ "version": "8.45.0",
5
5
  "main": "dist/index.js",
6
6
  "license": "ISC",
7
7
  "jest": {
@@ -4,6 +4,7 @@ import styled, { css } from 'styled-components';
4
4
  import { kebabCase } from 'lodash';
5
5
  import hideVisually from '../../../../theme/shared/hideVisually';
6
6
  import Text from '../../Text/Text';
7
+ import { springScaleAnimation } from '../../../../theme/shared/animations';
7
8
 
8
9
  const RevealTextWidth = 55;
9
10
  const RevealTextSpeed = 0.35;
@@ -30,11 +31,11 @@ const StyledLink = styled.a`
30
31
  &:focus {
31
32
  opacity: 1;
32
33
  }
33
-
34
+
34
35
  // No hover state for mobile, so targetting Medium+:
35
- @media ${({ theme }) => theme.allBreakpoints('M')} {
36
+ @media ${({ theme }) => theme.breakpoints2026('M')} {
36
37
  &:hover,
37
- &:focus {
38
+ &:focus {
38
39
  img {
39
40
  filter: invert(0.5) sepia(1) saturate(100) hue-rotate(20deg);
40
41
  }
@@ -46,24 +47,46 @@ const StyledLink = styled.a`
46
47
  &:focus {
47
48
  // Default
48
49
  padding-right: ${RevealTextWidth}px;
49
-
50
+
50
51
  // Tweak for ESU's longer text:
51
52
  &[data-test="header-esu"] {
52
53
  padding-right: 92px;
53
54
  }
54
-
55
+
55
56
  // Tweak for Shop's shorter text:
56
57
  &[data-test="header-shop"] {
57
58
  padding-right: 48px;
58
59
  }
59
-
60
- // Show the Reveal text
60
+
61
+ // Show the Reveal text
61
62
  img + span {
62
63
  display: block;
63
64
  }
64
65
  }
65
66
  `}
66
67
  };
68
+
69
+ // New style is rounded square buttons with dark grey background, and animation.
70
+ // When we've moved fully to the new design,
71
+ // this prop and the old styles can be removed.
72
+ ${({ newStyle }) => newStyle && css`
73
+ background-color: ${({ theme }) => theme.color('grey_4')};
74
+ border-radius: 0.5rem;
75
+ padding: 0.5rem;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ width: 100%;
80
+ height: 100%;
81
+
82
+ ${springScaleAnimation(true, 1.15, 2)}
83
+
84
+ &:hover,
85
+ &:focus {
86
+ background-color: ${({ theme }) => theme.color('grey_4_hover')};
87
+ opacity: 1;
88
+ }
89
+ `}
67
90
  `;
68
91
 
69
92
  const RevealText = styled(Text)`
@@ -88,6 +111,9 @@ const RevealText = styled(Text)`
88
111
 
89
112
  const StyledImage = styled.img`
90
113
  width: 100%;
114
+ ${({ invertColor }) => invertColor && css`
115
+ filter: brightness(0) invert(1);
116
+ `}
91
117
  `;
92
118
 
93
119
  const HelperText = styled.span`
@@ -95,7 +121,8 @@ const HelperText = styled.span`
95
121
  `;
96
122
 
97
123
  const Icon = ({
98
- href, target, icon, brand, title, isHeader = false, id, ...restProps
124
+ href, target, icon, brand, title, id,
125
+ isHeader = false, newStyle = false, invertColor = false, ...restProps
99
126
  }) => (
100
127
  <StyledLink
101
128
  href={href}
@@ -105,9 +132,9 @@ const Icon = ({
105
132
  rel="noopener noreferrer"
106
133
  data-test={`${isHeader ? 'header' : 'icon'}-${kebabCase(id)}`}
107
134
  isHeader={isHeader}
135
+ newStyle={newStyle}
108
136
  >
109
- <StyledImage src={icon} alt={brand} />
110
-
137
+ <StyledImage src={icon} alt={brand} invertColor={invertColor} />
111
138
  { isHeader && (
112
139
  <RevealText>{title}</RevealText>
113
140
  )}
@@ -125,7 +152,16 @@ Icon.propTypes = {
125
152
  icon: PropTypes.string.isRequired,
126
153
  title: PropTypes.string.isRequired,
127
154
  isHeader: PropTypes.bool,
128
- id: PropTypes.string.isRequired
155
+ id: PropTypes.string.isRequired,
156
+ /** This applies the newer style, fitting with the new footer design for our pre-RND 2026
157
+ * website redesign.
158
+ * Currently only in use in the new footer. Once we have moved fully to the new design,
159
+ * this prop and the old styles can be removed. */
160
+ newStyle: PropTypes.bool,
161
+ /** Invert the color of the svg icon, e.g. for if you're using a dark background
162
+ * (currently only in use in the new footer)
163
+ */
164
+ invertColor: PropTypes.bool
129
165
  };
130
166
 
131
167
  export default Icon;
@@ -2,50 +2,107 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import styled from 'styled-components';
4
4
  import getLinks from './Utils/Links';
5
- import icons from './Utils/Icons';
5
+ import { circledIcons, standardIcons } from './Utils/Icons';
6
6
  import Icon from './Icon/Icon';
7
7
  import spacing from '../../../theme/shared/spacing';
8
8
 
9
9
  const StyledList = styled.ul`
10
10
  display: flex;
11
11
  list-style-type: none;
12
- margin: 0 auto;
13
- justify-content: center;
12
+ justify-content: ${newStyle => (newStyle ? 'space-around' : 'center')};
13
+ margin: ${({ newStyle }) => (newStyle ? `${spacing('lg')} 0` : '0 auto 0 0')};
14
14
  padding: 0;
15
15
  align-items: center;
16
16
 
17
- @media ${({ theme }) => theme.allBreakpoints('M')} {
17
+ @media ${({ theme }) => theme.breakpoints2026('M')} {
18
18
  justify-content: start;
19
+ margin: ${({ newStyle }) => (newStyle ? `${spacing('sm')} 0` : '0 auto 0 0')};
19
20
  }
20
21
  `;
21
22
 
22
23
  const StyledItem = styled.li`
23
- width: 32px;
24
- margin-right: ${spacing('m')};
25
- @media ${({ theme }) => theme.allBreakpoints('M')} {
26
- width: 48px;
24
+ width: 48px;
25
+ margin-right: ${({ newStyle }) => (newStyle ? '0' : spacing('m'))};
26
+
27
+ @media ${({ theme }) => theme.breakpoints2026('M')} {
28
+ margin-right: ${({ newStyle }) => (newStyle ? spacing('md') : spacing('m'))};
27
29
  }
28
30
  `;
29
31
 
30
- /** Social media icons with customizable style linked to campaign social media accounts */
31
- const SocialIcons = ({ target = 'blank', campaign, ...restProps }) => {
32
+ const StyledIcon = styled(Icon)`
33
+ width: auto;
34
+ `;
35
+
36
+ const SocialIcons = ({
37
+ campaign,
38
+ showFacebookSocialIcon,
39
+ showInstagramSocialIcon,
40
+ showXSocialIcon,
41
+ showTikTokSocialIcon,
42
+ showYouTubeSocialIcon,
43
+ target = 'blank',
44
+ newStyle = false,
45
+ invertColor = false,
46
+ ...restProps
47
+ }) => {
32
48
  const links = getLinks(campaign);
33
49
 
50
+ // We've got two sets now - one better suited to the new footer design,
51
+ // and one for the legacy footer.
52
+ const iconSet = newStyle ? standardIcons : circledIcons;
53
+
54
+ // Map brand names to their show props
55
+ const brandVisibilityMap = {
56
+ facebook: showFacebookSocialIcon,
57
+ instagram: showInstagramSocialIcon,
58
+ twitter: showXSocialIcon,
59
+ x: showXSocialIcon,
60
+ tiktok: showTikTokSocialIcon,
61
+ youtube: showYouTubeSocialIcon
62
+ };
63
+
64
+ // If prop is explicitly false, hide; otherwise show
65
+ // (for backward compatibility with the 'old' footer)
66
+ const shouldShowIcon = brand => {
67
+ const visibilityProp = brandVisibilityMap[brand];
68
+ return visibilityProp !== false;
69
+ };
70
+
71
+ // Get the list of brands to display
72
+ // For newStyle, include tiktok and use 'x' instead of twitter
73
+ const brandsToShow = newStyle
74
+ ? ['facebook', 'instagram', 'x', 'tiktok', 'youtube']
75
+ : ['facebook', 'instagram', 'twitter', 'youtube'];
76
+
34
77
  return (
35
- <StyledList>
36
- {Object.keys(icons).map(brand => (
37
- <StyledItem key={brand}>
38
- <Icon
39
- target={target}
40
- icon={icons[brand]}
41
- href={links[brand].url}
42
- title={links[brand].title}
43
- brand={brand}
44
- id={links[brand].id}
45
- {...restProps}
46
- />
47
- </StyledItem>
48
- ))}
78
+ <StyledList newStyle={newStyle}>
79
+ {brandsToShow
80
+ .filter(brand => shouldShowIcon(brand))
81
+ .map(brand => {
82
+ const linkData = links[brand];
83
+ if (!linkData) {
84
+ return null;
85
+ }
86
+ const icon = iconSet[brand];
87
+ if (!icon) {
88
+ return null;
89
+ }
90
+ return (
91
+ <StyledItem key={brand} newStyle={newStyle}>
92
+ <StyledIcon
93
+ target={target}
94
+ icon={icon}
95
+ href={linkData.url}
96
+ title={linkData.title}
97
+ brand={brand}
98
+ id={linkData.id}
99
+ newStyle={newStyle}
100
+ invertColor={invertColor}
101
+ {...restProps}
102
+ />
103
+ </StyledItem>
104
+ );
105
+ })}
49
106
  </StyledList>
50
107
  );
51
108
  };
@@ -54,7 +111,24 @@ SocialIcons.propTypes = {
54
111
  /** Campaign, used to get social media accounts' links */
55
112
  campaign: PropTypes.string.isRequired,
56
113
  /** Social media account link target */
57
- target: PropTypes.string
114
+ target: PropTypes.string,
115
+ /** This applies the newer style, fitting with the new footer design for
116
+ * our pre-RND 2026 website redesign.
117
+ Currently only in use in the new footer. Once we have moved fully to
118
+ the new design, this prop and the old styles can be removed. */
119
+ newStyle: PropTypes.bool,
120
+ /** Show/hide Facebook social icon */
121
+ showFacebookSocialIcon: PropTypes.bool,
122
+ /** Show/hide Instagram social icon */
123
+ showInstagramSocialIcon: PropTypes.bool,
124
+ /** Show/hide X (Twitter) social icon */
125
+ showXSocialIcon: PropTypes.bool,
126
+ /** Show/hide TikTok social icon */
127
+ showTikTokSocialIcon: PropTypes.bool,
128
+ /** Show/hide YouTube social icon */
129
+ showYouTubeSocialIcon: PropTypes.bool,
130
+ /** Invert the color of the svg icon, e.g. for if you're using a dark background */
131
+ invertColor: PropTypes.bool
58
132
  };
59
133
 
60
134
  export default SocialIcons;
@@ -1,11 +1,30 @@
1
- import facebook from '../assets/facebook.svg';
2
- import twitter from '../assets/X-white-Subtract.svg';
3
- import youtube from '../assets/youtube.svg';
4
- import instagram from '../assets/instagram.svg';
5
-
6
- export default {
7
- facebook,
8
- instagram,
9
- twitter,
10
- youtube
1
+ // Icons with drawn circular border (old style)
2
+ import facebookCircled from '../assets/circled/facebook.svg';
3
+ import twitterCircled from '../assets/circled/X-white-Subtract.svg';
4
+ import youtubeCircled from '../assets/circled/youtube.svg';
5
+ import instagramCircled from '../assets/circled/instagram.svg';
6
+
7
+ // Standard icons without drawn border (new style)
8
+ import facebookStandard from '../assets/standard/facebook.svg';
9
+ import xStandard from '../assets/standard/x.svg';
10
+ import youtubeStandard from '../assets/standard/youtube.svg';
11
+ import instagramStandard from '../assets/standard/instagram.svg';
12
+ import tiktokStandard from '../assets/standard/tiktok.svg';
13
+
14
+ export const circledIcons = {
15
+ facebook: facebookCircled,
16
+ instagram: instagramCircled,
17
+ twitter: twitterCircled,
18
+ youtube: youtubeCircled
11
19
  };
20
+
21
+ export const standardIcons = {
22
+ facebook: facebookStandard,
23
+ instagram: instagramStandard,
24
+ x: xStandard,
25
+ youtube: youtubeStandard,
26
+ tiktok: tiktokStandard
27
+ };
28
+
29
+ // Default export for backward compatibility (circled icons)
30
+ export default circledIcons;
@@ -14,6 +14,11 @@ export default campaign => ({
14
14
  title: 'Check out our Twitter account',
15
15
  id: 'twitter'
16
16
  },
17
+ x: {
18
+ url: `https://x.com/${campaign}`,
19
+ title: 'Check out our X account',
20
+ id: 'x'
21
+ },
17
22
  youtube: {
18
23
  url: 'https://www.youtube.com/channel/UCdF5u0ggeSETozc8fsprjcw',
19
24
  title: 'Check out our YouTube channel',
@@ -23,5 +28,10 @@ export default campaign => ({
23
28
  url: `https://www.instagram.com/${campaign}`,
24
29
  title: 'Check out our Instagram account',
25
30
  id: 'instagram'
31
+ },
32
+ tiktok: {
33
+ url: `https://www.tiktok.com/@${campaign}`,
34
+ title: 'Check out our TikTok account',
35
+ id: 'tiktok'
26
36
  }
27
37
  });