@comicrelief/component-library 8.52.0 → 8.52.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.
@@ -14,7 +14,7 @@ exports[`handles data structure correctly 1`] = `
14
14
  className="CTAMultiCardstyle__CardsContainer-sc-gsdqzv-3 gAuYUa"
15
15
  >
16
16
  <div
17
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 jZEwGJ"
17
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hKmRek"
18
18
  >
19
19
  <a
20
20
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -95,7 +95,7 @@ exports[`handles data structure correctly 1`] = `
95
95
  </a>
96
96
  </div>
97
97
  <div
98
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 jZEwGJ"
98
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hKmRek"
99
99
  >
100
100
  <div
101
101
  className="CTACardstyle__CardLink-sc-si8xx1-4 lbrljd"
@@ -141,7 +141,7 @@ exports[`handles data structure correctly 1`] = `
141
141
  </div>
142
142
  </div>
143
143
  <div
144
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 jZEwGJ"
144
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hKmRek"
145
145
  >
146
146
  <a
147
147
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -222,7 +222,7 @@ exports[`handles data structure correctly 1`] = `
222
222
  </a>
223
223
  </div>
224
224
  <div
225
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 jZEwGJ"
225
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hKmRek"
226
226
  >
227
227
  <a
228
228
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -580,7 +580,7 @@ exports[`renders carousel mode correctly 1`] = `
580
580
  className="CTAMultiCardstyle__CardsContainer-sc-gsdqzv-3 fqrDP"
581
581
  >
582
582
  <div
583
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
583
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
584
584
  >
585
585
  <a
586
586
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -661,7 +661,7 @@ exports[`renders carousel mode correctly 1`] = `
661
661
  </a>
662
662
  </div>
663
663
  <div
664
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
664
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
665
665
  >
666
666
  <div
667
667
  className="CTACardstyle__CardLink-sc-si8xx1-4 lbrljd"
@@ -707,7 +707,7 @@ exports[`renders carousel mode correctly 1`] = `
707
707
  </div>
708
708
  </div>
709
709
  <div
710
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
710
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
711
711
  >
712
712
  <a
713
713
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -788,7 +788,7 @@ exports[`renders carousel mode correctly 1`] = `
788
788
  </a>
789
789
  </div>
790
790
  <div
791
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
791
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
792
792
  >
793
793
  <a
794
794
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -863,7 +863,7 @@ exports[`renders correctly with data prop 1`] = `
863
863
  className="CTAMultiCardstyle__CardsContainer-sc-gsdqzv-3 fqrDP"
864
864
  >
865
865
  <div
866
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
866
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
867
867
  >
868
868
  <a
869
869
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -944,7 +944,7 @@ exports[`renders correctly with data prop 1`] = `
944
944
  </a>
945
945
  </div>
946
946
  <div
947
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
947
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
948
948
  >
949
949
  <div
950
950
  className="CTACardstyle__CardLink-sc-si8xx1-4 lbrljd"
@@ -990,7 +990,7 @@ exports[`renders correctly with data prop 1`] = `
990
990
  </div>
991
991
  </div>
992
992
  <div
993
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
993
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
994
994
  >
995
995
  <a
996
996
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -1071,7 +1071,7 @@ exports[`renders correctly with data prop 1`] = `
1071
1071
  </a>
1072
1072
  </div>
1073
1073
  <div
1074
- className="CTACardstyle__CardWrapper-sc-si8xx1-5 eieQSs"
1074
+ className="CTACardstyle__CardWrapper-sc-si8xx1-5 hQbghF"
1075
1075
  >
1076
1076
  <a
1077
1077
  className="CTACardstyle__CardLink-sc-si8xx1-4 eIrLL"
@@ -175,7 +175,7 @@ const CardWrapper = exports.CardWrapper = _styledComponents.default.div.withConf
175
175
  let {
176
176
  columns
177
177
  } = _ref28;
178
- return columns === 3 ? (0, _styledComponents.css)(["flex:0 1 auto;width:clamp(286px,calc((100% - 4rem) / 3),363px);"]) : (0, _styledComponents.css)(["flex:0 1 auto;width:100%;"]);
178
+ return columns === 3 ? (0, _styledComponents.css)(["flex:0 1 auto;width:clamp(261px,calc((100% - 4rem) / 3),363px);"]) : (0, _styledComponents.css)(["flex:0 1 auto;width:100%;"]);
179
179
  });
180
180
  });
181
181
  const CopyAndLinkSection = exports.CopyAndLinkSection = _styledComponents.default.div.withConfig({
@@ -103,6 +103,7 @@ const DynamicGallery = _ref => {
103
103
 
104
104
  // handle selected gallery node
105
105
  const [selectedNode, setSelectedNode] = (0, _react.useState)(null);
106
+ const [focusedNode, setFocusedNode] = (0, _react.useState)(null);
106
107
 
107
108
  // handle next/previous node events from the lightbox
108
109
  function handleNextNode(node) {
@@ -128,6 +129,8 @@ const DynamicGallery = _ref => {
128
129
  const nodeIndex = +event.target.dataset.nodeIndex;
129
130
  if (Number.isNaN(nodeIndex)) return;
130
131
  setSelectedNode(nodes[nodeIndex]);
132
+ // also store the focused node for focus restoration when the lightbox closes
133
+ setFocusedNode(event.target.closest('.gallery-node'));
131
134
  }
132
135
  break;
133
136
  }
@@ -190,7 +193,9 @@ const DynamicGallery = _ref => {
190
193
  selectedNode,
191
194
  setSelectedNode,
192
195
  nextNode: handleNextNode,
193
- previousNode: handlePreviousNode
196
+ previousNode: handlePreviousNode,
197
+ focusedNode,
198
+ setFocusedNode
194
199
  }
195
200
  }, /*#__PURE__*/_react.default.createElement(_DynamicGallery.ImageGrid, {
196
201
  className: "gallery-grid",
@@ -205,7 +210,8 @@ const DynamicGallery = _ref => {
205
210
  columnCount: columnCount,
206
211
  nodes: nodes.slice(0, imageCount),
207
212
  imageRatio: imageRatio,
208
- updateTabOrder: throttledUpdateTabOrder.current
213
+ updateTabOrder: throttledUpdateTabOrder.current,
214
+ focusOutlineColour: textColour
209
215
  })), /*#__PURE__*/_react.default.createElement(_DynamicGallery.EmptyMessage, {
210
216
  isEmpty: !hasNodes
211
217
  }, "No images to display")), /*#__PURE__*/_react.default.createElement(_Lightbox.default, null), /*#__PURE__*/_react.default.createElement("div", {
@@ -213,6 +219,6 @@ const DynamicGallery = _ref => {
213
219
  tabIndex: 0
214
220
  })), imageCount < nodes.length && /*#__PURE__*/_react.default.createElement(_Button.default, {
215
221
  onClick: () => handleLoadMore()
216
- }, "Load more"));
222
+ }, "Show more"));
217
223
  };
218
224
  var _default = exports.default = DynamicGallery;
@@ -4,7 +4,7 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.Title = exports.InteractiveGalleryNode = exports.ImageGrid = exports.ImageContainer = exports.GalleryNode = exports.EmptyMessage = exports.Details = exports.Container = exports.Column = exports.Caption = void 0;
7
+ exports.InteractiveGalleryNode = exports.ImageGrid = exports.ImageContainer = exports.GalleryNode = exports.EmptyMessage = exports.Details = exports.Container = exports.Column = void 0;
8
8
  var _styledComponents = _interopRequireWildcard(require("styled-components"));
9
9
  const Container = exports.Container = _styledComponents.default.div.withConfig({
10
10
  displayName: "DynamicGallerystyle__Container",
@@ -60,7 +60,12 @@ const EmptyMessage = exports.EmptyMessage = _styledComponents.default.div.withCo
60
60
  } = _ref7;
61
61
  return isEmpty ? 'block' : 'none';
62
62
  });
63
- const GalleryNodeBase = (0, _styledComponents.css)(["display:flex;flex-direction:column;gap:0.8rem;padding:0;margin:0;background:none;border:none;text-align:left;"]);
63
+ const GalleryNodeBase = (0, _styledComponents.css)(["display:flex;flex-direction:column;gap:0.9rem;padding:0;margin:0;background:none;border:none;text-align:left;&:focus-visible{outline:2px solid ", ";outline-offset:0.5rem;border-radius:1rem;}"], _ref8 => {
64
+ let {
65
+ focusOutlineColour
66
+ } = _ref8;
67
+ return focusOutlineColour;
68
+ });
64
69
  const GalleryNode = exports.GalleryNode = _styledComponents.default.div.withConfig({
65
70
  displayName: "DynamicGallerystyle__GalleryNode",
66
71
  componentId: "sc-1kgt7yr-4"
@@ -68,30 +73,22 @@ const GalleryNode = exports.GalleryNode = _styledComponents.default.div.withConf
68
73
  const InteractiveGalleryNode = exports.InteractiveGalleryNode = _styledComponents.default.button.withConfig({
69
74
  displayName: "DynamicGallerystyle__InteractiveGalleryNode",
70
75
  componentId: "sc-1kgt7yr-5"
71
- })(["", " cursor:pointer;color:inherit;& div:first-child{transition:all 0.1s ease-out;}&:focus-visible{outline:2px solid #000000;}& > div:first-child{&:hover{box-shadow:0px 3px 10px 0px rgba(0,0,0,0.4);}}"], GalleryNodeBase);
76
+ })(["", " cursor:pointer;color:inherit;& div:first-child{transition:all 0.1s ease-out;}& > div:first-child{&:hover{box-shadow:0px 3px 10px 0px rgba(0,0,0,0.4);}}"], GalleryNodeBase);
72
77
  const ImageContainer = exports.ImageContainer = _styledComponents.default.div.withConfig({
73
78
  displayName: "DynamicGallerystyle__ImageContainer",
74
79
  componentId: "sc-1kgt7yr-6"
75
- })(["display:flex;height:auto;width:100%;min-height:", ";max-height:", ";overflow:hidden;border-radius:1rem;background:rgba(0,0,0,0.05);box-shadow:0px 2px 8px 0px rgba(0,0,0,0.2);img{height:100%;opacity:0;transition:opacity 0.1s ease-out 0.3s;}"], _ref8 => {
80
+ })(["display:flex;height:auto;width:100%;min-height:", ";max-height:", ";overflow:hidden;border-radius:1rem;background:rgba(0,0,0,0.05);box-shadow:0px 2px 8px 0px rgba(0,0,0,0.2);img{height:100%;opacity:0;transition:opacity 0.1s ease-out 0.3s;}"], _ref9 => {
76
81
  let {
77
82
  minHeight
78
- } = _ref8;
83
+ } = _ref9;
79
84
  return minHeight;
80
- }, _ref9 => {
85
+ }, _ref10 => {
81
86
  let {
82
87
  maxHeight
83
- } = _ref9;
88
+ } = _ref10;
84
89
  return maxHeight;
85
90
  });
86
91
  const Details = exports.Details = _styledComponents.default.div.withConfig({
87
92
  displayName: "DynamicGallerystyle__Details",
88
93
  componentId: "sc-1kgt7yr-7"
89
- })(["display:flex;flex-direction:column;gap:0.5rem;padding:0 1rem;"]);
90
- const Title = exports.Title = _styledComponents.default.div.withConfig({
91
- displayName: "DynamicGallerystyle__Title",
92
- componentId: "sc-1kgt7yr-8"
93
- })(["&:first-child{margin-bottom:0;}"]);
94
- const Caption = exports.Caption = _styledComponents.default.div.withConfig({
95
- displayName: "DynamicGallerystyle__Caption",
96
- componentId: "sc-1kgt7yr-9"
97
- })(["line-height:1;"]);
94
+ })(["display:flex;flex-direction:column;gap:0.5rem;padding:0 1rem;"]);
@@ -12,12 +12,14 @@ var _Picture = _interopRequireDefault(require("../../Atoms/Picture/Picture"));
12
12
  var _Lightbox = require("./_Lightbox");
13
13
  var _DynamicGallery = require("./DynamicGallery.style");
14
14
  var _types = require("./_types");
15
+ var _utils = require("./_utils");
15
16
  /**
16
17
  * a separate component to handle columns of images;
17
18
  * this component handles aspect ratio calculations to enfore a min/max ratio for its images
18
19
  */
19
20
  function DynamicGalleryColumn(_ref) {
20
21
  let {
22
+ focusOutlineColour,
21
23
  updateTabOrder,
22
24
  nodes,
23
25
  imageRatio,
@@ -79,33 +81,40 @@ function DynamicGalleryColumn(_ref) {
79
81
  return /*#__PURE__*/_react.default.createElement(_DynamicGallery.Column, {
80
82
  ref: elRef,
81
83
  className: "gallery-column"
82
- }, nodes === null || nodes === void 0 ? void 0 : nodes.filter((_, nodeIndex) => nodeIndex % columnCount === columnIndex).map((node, nodeIndex) => /*#__PURE__*/_react.default.createElement(NodeComponent, {
83
- key: String(nodeIndex) + node.title,
84
- className: "gallery-node",
85
- title: node.title,
86
- "aria-label": node.title,
87
- "data-node-index": nodeIndex,
88
- onPointerUp: useLightbox ? () => handlePointerUp(node) : undefined,
89
- tabIndex: 0
90
- }, /*#__PURE__*/_react.default.createElement(_DynamicGallery.ImageContainer, {
91
- className: "gallery-node-image"
92
- // eslint-disable-next-line prefer-template
93
- ,
94
- minHeight: String(minHeight) + 'px'
95
- // eslint-disable-next-line prefer-template
96
- ,
97
- maxHeight: String(maxHeight) + 'px'
98
- }, /*#__PURE__*/_react.default.createElement(_Picture.default, {
99
- image: node.image,
100
- objectFit: "cover",
101
- alt: node.title
102
- // animate image in on load
103
- ,
104
- onLoad: event => {
105
- event.target.closest('.gallery-node-image').querySelector('img').style.setProperty('opacity', '1');
84
+ }, nodes === null || nodes === void 0 ? void 0 : nodes.filter((_, nodeIndex) => nodeIndex % columnCount === columnIndex).map((node, nodeIndex) => {
85
+ const bodyText = (0, _utils.extractNodeText)(node.gridBody);
86
+ const key = String(nodeIndex) + bodyText;
87
+ return /*#__PURE__*/_react.default.createElement(NodeComponent, {
88
+ key: key,
89
+ className: "gallery-node",
90
+ caption: bodyText,
91
+ "aria-label": bodyText,
92
+ title: bodyText,
93
+ "data-node-index": nodeIndex,
94
+ focusOutlineColour: focusOutlineColour,
95
+ onPointerUp: useLightbox ? () => handlePointerUp(node) : undefined,
96
+ tabIndex: 0
97
+ }, /*#__PURE__*/_react.default.createElement(_DynamicGallery.ImageContainer, {
98
+ className: "gallery-node-image"
99
+ // eslint prefers template literals for strings, but they break the compiler
100
+ // eslint-disable-next-line prefer-template
101
+ ,
102
+ minHeight: String(minHeight) + 'px'
103
+ // eslint-disable-next-line prefer-template
104
+ ,
105
+ maxHeight: String(maxHeight) + 'px'
106
+ }, /*#__PURE__*/_react.default.createElement(_Picture.default, {
107
+ image: node.image,
108
+ objectFit: "cover",
109
+ alt: bodyText
110
+ // animate image in on load
111
+ ,
112
+ onLoad: event => {
113
+ event.target.closest('.gallery-node-image').querySelector('img').style.setProperty('opacity', '1');
106
114
 
107
- // update tab order once the image has loaded
108
- updateTabOrder();
109
- }
110
- })), /*#__PURE__*/_react.default.createElement(_DynamicGallery.Details, null, /*#__PURE__*/_react.default.createElement(_DynamicGallery.Title, null, node.title), node.caption && /*#__PURE__*/_react.default.createElement(_DynamicGallery.Caption, null, node.caption)))));
115
+ // update tab order once the image has loaded
116
+ updateTabOrder();
117
+ }
118
+ })), /*#__PURE__*/_react.default.createElement(_DynamicGallery.Details, null, node.gridBody && /*#__PURE__*/_react.default.createElement("div", null, node.gridBody), node.gridCaption && /*#__PURE__*/_react.default.createElement("div", null, node.gridCaption)));
119
+ }));
111
120
  }
@@ -13,6 +13,7 @@ var _Cross = _interopRequireDefault(require("../../Atoms/Icons/Cross"));
13
13
  var _Picture = _interopRequireDefault(require("../../Atoms/Picture/Picture"));
14
14
  var _Lightbox = require("./_Lightbox.style");
15
15
  var _ScrollFix = _interopRequireDefault(require("./_ScrollFix"));
16
+ var _utils = require("./_utils");
16
17
  /**
17
18
  * lightbox context:
18
19
  * - selectedNode: the node that is currently selected
@@ -44,11 +45,12 @@ const Lightbox = () => {
44
45
  selectedNode,
45
46
  setSelectedNode,
46
47
  nextNode,
47
- previousNode
48
+ previousNode,
49
+ focusedNode,
50
+ setFocusedNode
48
51
  } = (0, _react.useContext)(LightboxContext);
49
52
  const hasNode = Boolean(selectedNode);
50
53
  const dialogRef = (0, _react.useRef)(null);
51
- const previousFocusRef = (0, _react.useRef)(null);
52
54
 
53
55
  /**
54
56
  * handle keyboard events within the lightbox;
@@ -104,27 +106,20 @@ const Lightbox = () => {
104
106
 
105
107
  // handle focus management when dialog opens/closes
106
108
  (0, _react.useEffect)(() => {
107
- // when the lightbox is opened, store the previously focused element
108
- // and move focus to the first focusable element in the dialog
109
109
  if (hasNode) {
110
- // store the previously focused element
111
- previousFocusRef.current = document.activeElement;
112
- // move focus to the first focusable element in the dialog
110
+ // move focus to the first focusable element in the dialog when it opens
113
111
  setTimeout(() => {
114
112
  const focusableElements = getFocusableElements(dialogRef.current);
115
113
  if (focusableElements.length > 0) {
116
114
  focusableElements[0].focus();
117
115
  }
118
116
  }, 0);
119
- return;
117
+ } else {
118
+ // restore focus to the previously focused element when lightbox closes
119
+ focusedNode === null || focusedNode === void 0 ? void 0 : focusedNode.focus();
120
+ setFocusedNode(null);
120
121
  }
121
-
122
- // when the lightbox is closed, restore focus to the previously focused element
123
- if (previousFocusRef.current && typeof previousFocusRef.current.focus === 'function') {
124
- previousFocusRef.current.focus();
125
- previousFocusRef.current = null;
126
- }
127
- }, [hasNode]);
122
+ }, [hasNode, focusedNode, setFocusedNode]);
128
123
 
129
124
  /**
130
125
  * close the lightbox when the backdrop is clicked
@@ -165,6 +160,7 @@ const Lightbox = () => {
165
160
  });
166
161
  target.style.opacity = '1';
167
162
  }
163
+ const bodyText = (0, _utils.extractNodeText)(selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.lightboxBody);
168
164
  return /*#__PURE__*/_react.default.createElement(_Lightbox.Container, {
169
165
  isOpen: hasNode
170
166
  }, /*#__PURE__*/_react.default.createElement(_Lightbox.Backdrop, {
@@ -181,7 +177,7 @@ const Lightbox = () => {
181
177
  color: "#E1E2E3"
182
178
  })), hasNode && /*#__PURE__*/_react.default.createElement(_Picture.default, {
183
179
  key: selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.image,
184
- alt: selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.title,
180
+ alt: bodyText,
185
181
  image: selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.image,
186
182
  width: imageDimensions.width,
187
183
  height: imageDimensions.height,
@@ -191,9 +187,9 @@ const Lightbox = () => {
191
187
  id: "lightboxDescription",
192
188
  "aria-live": "polite",
193
189
  "aria-atomic": "true"
194
- }, /*#__PURE__*/_react.default.createElement("div", {
190
+ }, (selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.lightboxBody) && /*#__PURE__*/_react.default.createElement("div", {
195
191
  id: "lightboxTitle"
196
- }, selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.title), (selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.caption) && /*#__PURE__*/_react.default.createElement("div", null, selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.caption), (selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.body) && /*#__PURE__*/_react.default.createElement("div", null, selectedNode.body)), /*#__PURE__*/_react.default.createElement(_Lightbox.CloseButton, {
192
+ }, selectedNode.lightboxBody), (selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.lightboxCaption) && /*#__PURE__*/_react.default.createElement("div", null, selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.lightboxCaption)), /*#__PURE__*/_react.default.createElement(_Lightbox.CloseButton, {
197
193
  type: "button",
198
194
  onClick: () => setSelectedNode(null)
199
195
  }, /*#__PURE__*/_react.default.createElement(_Lightbox.ScreenReaderOnly, null, "Close"), /*#__PURE__*/_react.default.createElement(_Cross.default, {