@comicrelief/component-library 8.25.0 → 8.25.2

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.
@@ -28,23 +28,28 @@ const InputWrapper = _styledComponents.default.div.withConfig({
28
28
  const InputFieldContainer = _styledComponents.default.div.withConfig({
29
29
  displayName: "Input__InputFieldContainer",
30
30
  componentId: "sc-bcqy1o-1"
31
- })(["position:relative;width:100%;display:flex;justify-content:flex-end;align-items:center;", ""], _ref2 => {
31
+ })(["position:relative;width:100%;display:flex;", ";justify-content:flex-end;align-items:center;", ""], _ref2 => {
32
+ let {
33
+ error
34
+ } = _ref2;
35
+ return error && 'flex-direction: row;';
36
+ }, _ref3 => {
32
37
  let {
33
38
  maxPxWidthMediumBreakpoint,
34
39
  maxPxWidthLargeBreakpoint,
35
40
  theme
36
- } = _ref2;
41
+ } = _ref3;
37
42
  return (0, _styledComponents.css)(["@media ", "{", "}@media ", "{", "}"], theme.allBreakpoints('M'), maxPxWidthMediumBreakpoint && "max-width: ".concat(maxPxWidthMediumBreakpoint, "px;"), theme.allBreakpoints('L'), maxPxWidthLargeBreakpoint && "max-width: ".concat(maxPxWidthLargeBreakpoint, "px;"));
38
43
  });
39
44
  const InputField = _styledComponents.default.input.withConfig({
40
45
  displayName: "Input__InputField",
41
46
  componentId: "sc-bcqy1o-2"
42
- })(["", ""], _ref3 => {
47
+ })(["", ""], _ref4 => {
43
48
  let {
44
49
  theme,
45
50
  error,
46
51
  prefixLength
47
- } = _ref3;
52
+ } = _ref4;
48
53
  return (0, _styledComponents.css)(["position:relative;box-sizing:border-box;width:100%;height:48px;padding:1rem 2.4rem 1rem 1.5rem;", " background-color:", ";border:1px solid;border-color:", ";box-shadow:none;appearance:none;color:", ";border-radius:0.5rem;font-size:inherit;z-index:2;font-family:", ";:focus{border:1px solid ", ";}"], prefixLength > 0 ? "padding-left: ".concat(getPrefixWidth(prefixLength), ";") : '', theme.color('grey_light'), error ? theme.color('red') : theme.color('grey_medium'), theme.color('black'), theme.fontFamilies(theme.font.regular), theme.color('grey_for_forms'));
49
54
  });
50
55
  const ErrorIconWrapper = _styledComponents.default.div.withConfig({
@@ -54,18 +59,18 @@ const ErrorIconWrapper = _styledComponents.default.div.withConfig({
54
59
  const Prefix = _styledComponents.default.div.withConfig({
55
60
  displayName: "Input__Prefix",
56
61
  componentId: "sc-bcqy1o-4"
57
- })(["position:absolute;left:0;top:0;", " display:flex;height:100%;width:", ";justify-content:center;align-items:center;color:", ";font-weight:700;font-size:inherit;margin-left:2px;"], (0, _zIndex.default)('high'), _ref4 => {
62
+ })(["position:absolute;left:0;top:0;", " display:flex;height:100%;width:", ";justify-content:center;align-items:center;color:", ";font-weight:700;font-size:inherit;margin-left:2px;"], (0, _zIndex.default)('high'), _ref5 => {
58
63
  let {
59
64
  length
60
- } = _ref4;
65
+ } = _ref5;
61
66
  return getPrefixWidth(length);
62
- }, _ref5 => {
67
+ }, _ref6 => {
63
68
  let {
64
69
  theme
65
- } = _ref5;
70
+ } = _ref6;
66
71
  return theme.color('grey_dark');
67
72
  });
68
- const Input = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
73
+ const Input = /*#__PURE__*/_react.default.forwardRef((_ref7, ref) => {
69
74
  let {
70
75
  errorMsg = '',
71
76
  id,
@@ -81,7 +86,7 @@ const Input = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
81
86
  maxPxWidthMediumBreakpoint,
82
87
  maxPxWidthLargeBreakpoint,
83
88
  ...rest
84
- } = _ref6;
89
+ } = _ref7;
85
90
  return /*#__PURE__*/_react.default.createElement(_Label.default, Object.assign({
86
91
  className: className,
87
92
  htmlFor: id,
@@ -95,7 +100,8 @@ const Input = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
95
100
  length: prefix.length
96
101
  }, prefix), /*#__PURE__*/_react.default.createElement(InputFieldContainer, {
97
102
  maxPxWidthMediumBreakpoint: maxPxWidthMediumBreakpoint,
98
- maxPxWidthLargeBreakpoint: maxPxWidthLargeBreakpoint
103
+ maxPxWidthLargeBreakpoint: maxPxWidthLargeBreakpoint,
104
+ error: Boolean(errorMsg)
99
105
  }, /*#__PURE__*/_react.default.createElement(InputField, Object.assign({
100
106
  id: id,
101
107
  type: type,
@@ -98,7 +98,7 @@ const SubNavMenu = exports.SubNavMenu = _styledComponents.default.ul.withConfig(
98
98
  const SubNavItem = exports.SubNavItem = _styledComponents.default.li.withConfig({
99
99
  displayName: "HeaderNavstyle__SubNavItem",
100
100
  componentId: "sc-1eihosl-3"
101
- })(["padding:0;height:100%;width:100%;border-top:1px solid ", ";;position:relative;transition:background-color ", "s ease;&:first-of-type{border-top:none;}span{font-weight:100;}:hover,:focus,:focus-within{background-color:", ";+ span{border-bottom:0;padding-bottom:2px;color:", ";}}"], _ref13 => {
101
+ })(["padding:0;height:100%;width:100%;border-top:1px solid ", ";position:relative;transition:background-color ", "s ease;&:first-of-type{border-top:none;}span{font-weight:100;}:hover,:focus,:focus-within{background-color:", ";+ span{border-bottom:0;padding-bottom:2px;color:", ";}}"], _ref13 => {
102
102
  let {
103
103
  theme
104
104
  } = _ref13;
@@ -10,5 +10,5 @@
10
10
 
11
11
  .rsg--header-11,
12
12
  .rsg--tabs-12 {
13
- display: none !important;;
13
+ display: none !important;
14
14
  }
@@ -125,7 +125,7 @@ const SubNavMenu = exports.SubNavMenu = _styledComponents.default.ul.withConfig(
125
125
  const SubNavItem = exports.SubNavItem = _styledComponents.default.li.withConfig({
126
126
  displayName: "HeaderNav2025style__SubNavItem",
127
127
  componentId: "sc-xflhtq-3"
128
- })(["padding:0;height:100%;width:100%;border-top:1px solid ", ";;position:relative;transition:background-color ", "s ease;&:first-of-type{border-top:none;}span{font-weight:100;}"], _ref18 => {
128
+ })(["padding:0;height:100%;width:100%;border-top:1px solid ", ";position:relative;transition:background-color ", "s ease;&:first-of-type{border-top:none;}span{font-weight:100;}"], _ref18 => {
129
129
  let {
130
130
  theme
131
131
  } = _ref18;
@@ -10,5 +10,5 @@
10
10
 
11
11
  .rsg--header-11,
12
12
  .rsg--tabs-12 {
13
- display: none !important;;
13
+ display: none !important;
14
14
  }
@@ -48,9 +48,10 @@ const FormField = exports.FormField = _styledComponents.default.div.withConfig({
48
48
  componentId: "sc-68n85q-5"
49
49
  })(["", ""], _ref2 => {
50
50
  let {
51
- theme
51
+ theme,
52
+ isError
52
53
  } = _ref2;
53
- return (0, _styledComponents.css)(["position:relative;margin-bottom:", ";width:100%;display:flex;flex-direction:column;padding:", ";border:1px solid ", ";;border-radius:10px;background-color:", ";transition:background-color 0.3s,color 0.3s;&:hover{background-color:", ";}&.selected{background-color:", ";span.icon-mp_permissionEmail{background-image:url(", ");}span.icon-mp_permissionPhone{background-image:url(", ");}span.icon-mp_permissionPost{background-image:url(", ");}span.icon-mp_permissionSMS{background-image:url(", ");}> div{label,> span{color:", ";}}&:hover{background-color:#161a85;}}label{position:relative;margin-bottom:0;width:100%;color:", ";font-weight:600;display:flex;justify-content:space-between;}h3{position:relative;margin-bottom:", ";&:before{position:absolute;top:0;left:0;width:24px;height:24px;content:'';}}"], (0, _spacing.default)('md'), (0, _spacing.default)('m'), theme.color('grey'), theme.color('grey_light'), theme.color('grey_medium'), theme.color('blue_donate'), _EmailWhite.default, _PhoneWhite.default, _PostWhite.default, _TextWhite.default, theme.color('white'), theme.color('black'), (0, _spacing.default)('md'));
54
+ return (0, _styledComponents.css)(["position:relative;margin-bottom:", ";width:100%;display:flex;flex-direction:column;padding:", ";background-color:", ";transition:background-color 0.3s,color 0.3s;border-radius:10px;border:1px solid ", ";&.selected{background-color:", ";&:hover{background-color:", ";border-color:", ";}span.icon-mp_permissionEmail{background-image:url(", ");}span.icon-mp_permissionPhone{background-image:url(", ");}span.icon-mp_permissionPost{background-image:url(", ");}span.icon-mp_permissionSMS{background-image:url(", ");}> div{label,> span{color:", ";}}}label{position:relative;margin-bottom:0;width:100%;color:", ";font-weight:600;display:flex;justify-content:space-between;}h3{position:relative;margin-bottom:", ";&:before{position:absolute;top:0;left:0;width:24px;height:24px;content:'';}}"], (0, _spacing.default)('md'), (0, _spacing.default)('m'), theme.color('grey_light'), theme.color('grey'), isError ? theme.color('red') : theme.color('blue_donate'), isError ? theme.color('red_dark') : theme.color('blue_donate'), theme.color('grey_4'), _EmailWhite.default, _PhoneWhite.default, _PostWhite.default, _TextWhite.default, theme.color('white'), theme.color('black'), (0, _spacing.default)('md'));
54
55
  });
55
56
  const CheckContainer = exports.CheckContainer = _styledComponents.default.div.withConfig({
56
57
  displayName: "MarketingPreferencesDSstyle__CheckContainer",
@@ -73,7 +74,7 @@ const CheckLabel = exports.CheckLabel = _styledComponents.default.label.withConf
73
74
  const CheckInput = exports.CheckInput = _styledComponents.default.input.withConfig({
74
75
  displayName: "MarketingPreferencesDSstyle__CheckInput",
75
76
  componentId: "sc-68n85q-8"
76
- })(["font-size:", ";display:block;box-sizing:border-box;opacity:0;position:absolute;width:100%;height:100%;left:0;top:0;margin:0;border:1px solid ", ";+ span{width:30px;height:30px;background-color:", ";border:1px solid ", ";float:left;border-radius:8px;}:checked + span{background:url(", ") no-repeat center ", ";;background-size:contain;}"], _ref5 => {
77
+ })(["font-size:", ";display:block;box-sizing:border-box;opacity:0;position:absolute;width:100%;height:100%;left:0;top:0;margin:0;border:1px solid ", ";+ span{width:30px;height:30px;background-color:", ";border:1px solid ", ";float:left;border-radius:8px;}:checked + span{background:url(", ") no-repeat center ", ";background-size:contain;}"], _ref5 => {
77
78
  let {
78
79
  theme
79
80
  } = _ref5;
@@ -120,7 +121,7 @@ const ExtraInfo = exports.ExtraInfo = _styledComponents.default.span.withConfig(
120
121
  const MPTextInput = exports.MPTextInput = (0, _styledComponents.default)(_TextInput.default).withConfig({
121
122
  displayName: "MarketingPreferencesDSstyle__MPTextInput",
122
123
  componentId: "sc-68n85q-11"
123
- })(["> div + span span{margin-top:-20px;}> span{margin-bottom:.5rem;}input{border:1px solid ", ";background-color:", ";margin-bottom:10px;@media ", "{max-width:none;}}"], _ref12 => {
124
+ })(["input{border:1px solid ", ";background-color:", ";@media ", "{max-width:none;}}span{color:white;}"], _ref12 => {
124
125
  let {
125
126
  theme
126
127
  } = _ref12;
@@ -90,10 +90,17 @@ const MarketingPreferencesDS = _ref => {
90
90
  const showPhoneField = !mp_permissionPhone.hideInput && (phoneChoice || errors.mp_phone);
91
91
  const showPostFields = !mp_permissionPost.hideInput && (postChoice || isAddressErroring());
92
92
  const customId = id ? "marketing-preferences--".concat(id) : 'marketing-preferences';
93
+
94
+ // Check for field-specific errors
95
+ const hasEmailError = Boolean(errors.mp_permissionEmail || errors.mp_email);
96
+ const hasPostError = Boolean(errors.mp_permissionPost || errors.mp_address1 || errors.mp_address2 || errors.mp_address3 || errors.mp_town || errors.mp_country || errors.mp_postcode);
97
+ const hasSMSError = Boolean(errors.mp_permissionSMS || errors.mp_mobile);
98
+ const hasPhoneError = Boolean(errors.mp_permissionPhone || errors.mp_phone);
93
99
  return /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.OuterWrapper, Object.assign({
94
100
  id: customId
95
101
  }, rest), copyTop && /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.TopCopyWrapper, null, copyTop), !mp_permissionEmail.disableOption && /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.FormField, {
96
- className: "field-email ".concat(emailChoice && 'selected')
102
+ className: "field-email ".concat(emailChoice && 'selected'),
103
+ isError: hasEmailError
97
104
  }, /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.CheckboxWrapper, null, /*#__PURE__*/_react.default.createElement(_OptInCheckbox.default, {
98
105
  mpValidationOptions: mpValidationOptions,
99
106
  name: "mp_permissionEmail",
@@ -115,7 +122,8 @@ const MarketingPreferencesDS = _ref => {
115
122
  id: "mp_email",
116
123
  formContext: formContext
117
124
  })))), !mp_permissionPost.disableOption && /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.FormField, {
118
- className: "field-post ".concat(postChoice && 'selected')
125
+ className: "field-post ".concat(postChoice && 'selected'),
126
+ isError: hasPostError
119
127
  }, /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.CheckboxWrapper, null, /*#__PURE__*/_react.default.createElement(_OptInCheckbox.default, {
120
128
  name: "mp_permissionPost",
121
129
  mpValidationOptions: mpValidationOptions,
@@ -169,7 +177,8 @@ const MarketingPreferencesDS = _ref => {
169
177
  id: "mp_country",
170
178
  formContext: formContext
171
179
  })))), !mp_permissionSMS.disableOption && /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.FormField, {
172
- className: "field-sms ".concat(smsChoice && 'selected')
180
+ className: "field-sms ".concat(smsChoice && 'selected'),
181
+ isError: hasSMSError
173
182
  }, /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.CheckboxWrapper, null, /*#__PURE__*/_react.default.createElement(_OptInCheckbox.default, {
174
183
  name: "mp_permissionSMS",
175
184
  id: "mp_permissionSMS",
@@ -188,7 +197,8 @@ const MarketingPreferencesDS = _ref => {
188
197
  id: "mp_mobile",
189
198
  formContext: formContext
190
199
  })))), !mp_permissionPhone.disableOption && /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.FormField, {
191
- className: "field-phone ".concat(phoneChoice && 'selected')
200
+ className: "field-phone ".concat(phoneChoice && 'selected'),
201
+ isError: hasPhoneError
192
202
  }, /*#__PURE__*/_react.default.createElement(_MarketingPreferencesDS.CheckboxWrapper, null, /*#__PURE__*/_react.default.createElement(_OptInCheckbox.default, {
193
203
  name: "mp_permissionPhone",
194
204
  mpValidationOptions: mpValidationOptions,
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.25.0",
4
+ "version": "8.25.2",
5
5
  "main": "dist/index.js",
6
6
  "license": "ISC",
7
7
  "jest": {
@@ -20,6 +20,7 @@ const InputFieldContainer = styled.div`
20
20
  position: relative;
21
21
  width: 100%;
22
22
  display: flex;
23
+ ${({ error }) => error && 'flex-direction: row;'};
23
24
  justify-content: flex-end;
24
25
  align-items: center;
25
26
  ${({ maxPxWidthMediumBreakpoint, maxPxWidthLargeBreakpoint, theme }) => css`
@@ -115,6 +116,7 @@ const Input = React.forwardRef(
115
116
  <InputFieldContainer
116
117
  maxPxWidthMediumBreakpoint={maxPxWidthMediumBreakpoint}
117
118
  maxPxWidthLargeBreakpoint={maxPxWidthLargeBreakpoint}
119
+ error={Boolean(errorMsg)}
118
120
  >
119
121
  <InputField
120
122
  id={id}
@@ -80,7 +80,7 @@ const SubNavMenu = styled.ul`
80
80
  overflow: hidden;
81
81
  border: 1px solid ${({ theme }) => theme.color('grey_medium')};
82
82
 
83
- // DESKTOP:
83
+ // DESKTOP:
84
84
  @media ${({ theme }) => theme.allBreakpoints('Nav')} {
85
85
  display: flex;
86
86
  visibility: ${({ isFocussed }) => (isFocussed ? 'visible' : 'hidden')};
@@ -104,7 +104,7 @@ const SubNavItem = styled.li`
104
104
  padding: 0;
105
105
  height: 100%;
106
106
  width: 100%;
107
- border-top: 1px solid ${({ theme }) => theme.color('grey_medium')};;
107
+ border-top: 1px solid ${({ theme }) => theme.color('grey_medium')};
108
108
  position: relative;
109
109
  transition: background-color ${transitionDuration}s ease;
110
110
 
@@ -230,8 +230,8 @@ const NavItem = styled.li`
230
230
  }
231
231
  }
232
232
  }
233
-
234
-
233
+
234
+
235
235
  @media ${({ theme }) => theme.allBreakpoints('Nav')} {
236
236
  margin: 0 4px;
237
237
  padding: 25px 5px;
@@ -364,12 +364,12 @@ const DonateButtonWrapperBottom = styled.div`
364
364
  transition: width 0.35s cubic-bezier(0.5, 1.5, 0.5, 0.9);
365
365
 
366
366
  &:hover,
367
- &:focus {
367
+ &:focus {
368
368
  width: 100%;
369
369
  box-shadow: rgba(0, 0, 0, 0.1) 0 0 20px 0;
370
370
  }
371
371
  }
372
-
372
+
373
373
  // Hide the 'Nav'-embedded version of the button when the nav
374
374
  // goes FULL DESKTOP, leaving just the 'Header'-embedded example
375
375
  @media ${({ theme }) => theme.allBreakpoints('Nav')} {
@@ -10,5 +10,5 @@
10
10
 
11
11
  .rsg--header-11,
12
12
  .rsg--tabs-12 {
13
- display: none !important;;
13
+ display: none !important;
14
14
  }
@@ -24,7 +24,7 @@ const NavLinkClass = styled(Link)`
24
24
  :focus-within {
25
25
  border: 0;
26
26
  }
27
-
27
+
28
28
  // No hover state for mobile, so targetting Medium+:
29
29
  @media ${({ theme }) => theme.allBreakpoints('M')} {
30
30
  :hover,
@@ -44,7 +44,7 @@ const NavLinkClass = styled(Link)`
44
44
  }
45
45
  }
46
46
  }
47
-
47
+
48
48
  // Chevron icon:
49
49
  > div {
50
50
  height: auto;
@@ -113,7 +113,7 @@ const SubNavMenu = styled.ul`
113
113
  overflow: hidden;
114
114
  border-top: 1px solid ${({ theme }) => theme.color('grey_medium')};
115
115
 
116
- // DESKTOP:
116
+ // DESKTOP:
117
117
  @media ${({ theme }) => theme.allBreakpoints('Nav')} {
118
118
  display: flex;
119
119
  width: 330px;
@@ -136,7 +136,7 @@ const SubNavItem = styled.li`
136
136
  padding: 0;
137
137
  height: 100%;
138
138
  width: 100%;
139
- border-top: 1px solid ${({ theme }) => theme.color('grey_medium')};;
139
+ border-top: 1px solid ${({ theme }) => theme.color('grey_medium')};
140
140
  position: relative;
141
141
  transition: background-color ${transitionDuration}s ease;
142
142
 
@@ -208,7 +208,7 @@ const NavLink = styled(NavLinkClass)`
208
208
  ${({ hasSubMenu }) => (hasSubMenu && css`
209
209
  padding: 10px 14px 10px 0;
210
210
  `)}
211
-
211
+
212
212
  :hover,
213
213
  :focus-within,
214
214
  :focus {
@@ -217,7 +217,7 @@ const NavLink = styled(NavLinkClass)`
217
217
  opacity: 1;
218
218
  }}
219
219
  }
220
-
220
+
221
221
  @media ${({ theme }) => theme.allBreakpoints('NavWide')} {
222
222
  ${({ hasSubMenu }) => (hasSubMenu && css`
223
223
  padding: 10px 16px 10px 0;
@@ -286,8 +286,8 @@ const NavItem = styled.li`
286
286
  }
287
287
  }
288
288
  }
289
-
290
-
289
+
290
+
291
291
  @media ${({ theme }) => theme.allBreakpoints('Nav')} {
292
292
  margin: 0 22px 0 0;
293
293
  padding: 25px 0px;
@@ -399,7 +399,7 @@ const NavMetaIcons = styled.div`
399
399
  &:hover {
400
400
  span {
401
401
  color: ${({ theme }) => theme.color('red')};
402
- }
402
+ }
403
403
  }
404
404
  }
405
405
  }
@@ -438,12 +438,12 @@ const DonateButtonWrapperBottom = styled.div`
438
438
  transition: width 0.35s cubic-bezier(0.5, 1.5, 0.5, 0.9);
439
439
 
440
440
  &:hover,
441
- &:focus {
441
+ &:focus {
442
442
  width: 100%;
443
443
  box-shadow: rgba(0, 0, 0, 0.1) 0 0 20px 0;
444
444
  }
445
445
  }
446
-
446
+
447
447
  // Hide the 'Nav'-embedded version of the button when the nav
448
448
  // goes FULL DESKTOP, leaving just the 'Header'-embedded example
449
449
  @media ${({ theme }) => theme.allBreakpoints('Nav')} {
@@ -10,5 +10,5 @@
10
10
 
11
11
  .rsg--header-11,
12
12
  .rsg--tabs-12 {
13
- display: none !important;;
13
+ display: none !important;
14
14
  }
@@ -16,7 +16,7 @@ const OuterWrapper = styled.div`
16
16
  display: flex;
17
17
  flex-direction: column;
18
18
 
19
- // Preload 'selected' icons
19
+ /* Preload 'selected' icons */
20
20
  &:after {
21
21
  position:absolute;
22
22
  width: 0;
@@ -75,24 +75,24 @@ const AssociatedFieldsName = styled.span`
75
75
  }
76
76
  `;
77
77
 
78
- const FormField = styled.div`${({ theme }) => css`
78
+ const FormField = styled.div`${({ theme, isError }) => css`
79
79
  position: relative;
80
80
  margin-bottom: ${spacing('md')};
81
81
  width: 100%;
82
82
  display: flex;
83
83
  flex-direction: column;
84
84
  padding: ${spacing('m')};
85
- border: 1px solid ${theme.color('grey')};;
86
- border-radius: 10px;
87
85
  background-color: ${theme.color('grey_light')};
88
86
  transition: background-color 0.3s, color 0.3s;
89
-
90
- &:hover {
91
- background-color: ${theme.color('grey_medium')};
92
- }
87
+ border-radius: 10px;
88
+ border: 1px solid ${theme.color('grey')};
93
89
 
94
90
  &.selected {
95
- background-color: ${theme.color('blue_donate')};
91
+ background-color: ${isError ? theme.color('red') : theme.color('blue_donate')};
92
+ &:hover {
93
+ background-color: ${isError ? theme.color('red_dark') : theme.color('blue_donate')};
94
+ border-color: ${theme.color('grey_4')};
95
+ }
96
96
 
97
97
  span.icon-mp_permissionEmail {
98
98
  background-image: url(${EmailIconWhite});
@@ -115,14 +115,9 @@ const FormField = styled.div`${({ theme }) => css`
115
115
  color: ${theme.color('white')};
116
116
  }
117
117
  }
118
-
119
- &:hover {
120
- // No fancy functions yet to darken preexisting colours..
121
- background-color: #161a85;
122
- }
123
118
  }
124
119
 
125
- // All labels; input AND checkbox
120
+ /* All labels; input AND checkbox */
126
121
  label {
127
122
  position: relative;
128
123
  margin-bottom: 0;
@@ -187,7 +182,7 @@ const CheckInput = styled.input`
187
182
  border-radius: 8px;
188
183
  }
189
184
  :checked + span {
190
- background: url(${checkBoxIcon}) no-repeat center ${({ theme }) => theme.color('white')};;
185
+ background: url(${checkBoxIcon}) no-repeat center ${({ theme }) => theme.color('white')};
191
186
  background-size: contain;
192
187
  }
193
188
  `;
@@ -219,9 +214,9 @@ const ExtraInfo = styled.span`
219
214
  margin-top: ${spacing('md')};
220
215
  margin-bottom: 0;
221
216
 
222
- // Visually hide the actual field label for the
223
- // non-multifield options, as we have the
224
- // more chatty 'extra info' language
217
+ /* Visually hide the actual field label for the */
218
+ /* non-multifield options, as we have the */
219
+ /* more chatty 'extra info' language */
225
220
  &[for="mp_email"],
226
221
  &[for="mp_mobile"],
227
222
  &[for="mp_phone"] {
@@ -240,23 +235,17 @@ const ExtraInfo = styled.span`
240
235
  `;
241
236
 
242
237
  const MPTextInput = styled(TextInput)`
243
- // Correct the ErrorMsg offset for this context
244
- > div + span span {
245
- margin-top: -20px;
246
- }
247
-
248
- > span {
249
- margin-bottom: .5rem;
250
- }
251
-
252
238
  input {
253
239
  border: 1px solid ${({ theme }) => theme.color('black')};
254
240
  background-color: ${({ theme }) => theme.color('white')};
255
- margin-bottom: 10px;
256
241
  @media ${({ theme }) => theme.allBreakpoints('M')} {
257
242
  max-width: none;
258
243
  }
259
244
  }
245
+ /* error message text colour */
246
+ span {
247
+ color: white;
248
+ }
260
249
  `;
261
250
 
262
251
  export {
@@ -61,13 +61,23 @@ const MarketingPreferencesDS = ({
61
61
 
62
62
  const customId = id ? `marketing-preferences--${id}` : 'marketing-preferences';
63
63
 
64
+ // Check for field-specific errors
65
+ const hasEmailError = Boolean(errors.mp_permissionEmail || errors.mp_email);
66
+ const hasPostError = Boolean(errors.mp_permissionPost || errors.mp_address1 || errors.mp_address2
67
+ || errors.mp_address3 || errors.mp_town || errors.mp_country || errors.mp_postcode);
68
+ const hasSMSError = Boolean(errors.mp_permissionSMS || errors.mp_mobile);
69
+ const hasPhoneError = Boolean(errors.mp_permissionPhone || errors.mp_phone);
70
+
64
71
  return (
65
72
  <OuterWrapper id={customId} {...rest}>
66
73
  {copyTop && <TopCopyWrapper>{copyTop}</TopCopyWrapper>}
67
74
 
68
75
  {/* Render Email checkboxes and input if not removed in config */}
69
76
  {!mp_permissionEmail.disableOption && (
70
- <FormField className={`field-email ${emailChoice && 'selected'}`}>
77
+ <FormField
78
+ className={`field-email ${emailChoice && 'selected'}`}
79
+ isError={hasEmailError}
80
+ >
71
81
  <CheckboxWrapper>
72
82
  <OptInCheckbox
73
83
  mpValidationOptions={mpValidationOptions}
@@ -102,7 +112,10 @@ const MarketingPreferencesDS = ({
102
112
 
103
113
  {/* Render Post checkboxes and inputs if not removed in config */}
104
114
  {!mp_permissionPost.disableOption && (
105
- <FormField className={`field-post ${postChoice && 'selected'}`}>
115
+ <FormField
116
+ className={`field-post ${postChoice && 'selected'}`}
117
+ isError={hasPostError}
118
+ >
106
119
  <CheckboxWrapper>
107
120
  <OptInCheckbox
108
121
  name="mp_permissionPost"
@@ -174,7 +187,10 @@ const MarketingPreferencesDS = ({
174
187
 
175
188
  {/* Render SMS checkboxes and inputs if not removed in config */}
176
189
  {!mp_permissionSMS.disableOption && (
177
- <FormField className={`field-sms ${smsChoice && 'selected'}`}>
190
+ <FormField
191
+ className={`field-sms ${smsChoice && 'selected'}`}
192
+ isError={hasSMSError}
193
+ >
178
194
  <CheckboxWrapper>
179
195
  <OptInCheckbox
180
196
  name="mp_permissionSMS"
@@ -206,7 +222,10 @@ const MarketingPreferencesDS = ({
206
222
 
207
223
  {/* Render Phone checkboxes and input if not removed in config */}
208
224
  {!mp_permissionPhone.disableOption && (
209
- <FormField className={`field-phone ${phoneChoice && 'selected'}`}>
225
+ <FormField
226
+ className={`field-phone ${phoneChoice && 'selected'}`}
227
+ isError={hasPhoneError}
228
+ >
210
229
  <CheckboxWrapper>
211
230
  <OptInCheckbox
212
231
  name="mp_permissionPhone"