@comicrelief/component-library 8.52.1 → 8.52.3
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.
- package/dist/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.md +1 -0
- package/dist/components/Molecules/CTA/CTAMultiCard/__snapshots__/CTAMultiCard.test.js.snap +280 -232
- package/dist/components/Molecules/CTA/CTASingleCard/__snapshots__/CTASingleCard.test.js.snap +68 -28
- package/dist/components/Molecules/CTA/shared/CTACard.js +1 -1
- package/dist/components/Molecules/CTA/shared/CTACard.style.js +11 -7
- package/dist/components/Organisms/DynamicGallery/DynamicGallery.js +9 -3
- package/dist/components/Organisms/DynamicGallery/DynamicGallery.style.js +13 -16
- package/dist/components/Organisms/DynamicGallery/_DynamicGalleryColumn.js +37 -28
- package/dist/components/Organisms/DynamicGallery/_Lightbox.js +14 -18
- package/dist/components/Organisms/DynamicGallery/__snapshots__/DynamicGallery.test.js.snap +64 -111
- package/dist/components/Organisms/DynamicGallery/_types.js +4 -3
- package/dist/components/Organisms/DynamicGallery/_utils.js +29 -3
- package/package.json +1 -1
- package/src/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.md +1 -0
- package/src/components/Molecules/CTA/CTAMultiCard/__snapshots__/CTAMultiCard.test.js.snap +280 -232
- package/src/components/Molecules/CTA/CTASingleCard/__snapshots__/CTASingleCard.test.js.snap +68 -28
- package/src/components/Molecules/CTA/shared/CTACard.js +6 -3
- package/src/components/Molecules/CTA/shared/CTACard.style.js +8 -0
- package/src/components/Organisms/DynamicGallery/DynamicGallery.js +8 -2
- package/src/components/Organisms/DynamicGallery/DynamicGallery.style.js +7 -15
- package/src/components/Organisms/DynamicGallery/_DynamicGalleryColumn.js +49 -41
- package/src/components/Organisms/DynamicGallery/_Lightbox.js +21 -26
- package/src/components/Organisms/DynamicGallery/__snapshots__/DynamicGallery.test.js.snap +64 -111
- package/src/components/Organisms/DynamicGallery/_types.js +4 -3
- package/src/components/Organisms/DynamicGallery/_utils.js +40 -3
|
@@ -32,7 +32,7 @@ exports[`renders correctly with data prop 1`] = `
|
|
|
32
32
|
object-fit: cover;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
.
|
|
35
|
+
.c19 {
|
|
36
36
|
display: inline-block;
|
|
37
37
|
color: #FFFFFF;
|
|
38
38
|
fill: currentColor;
|
|
@@ -85,7 +85,7 @@ exports[`renders correctly with data prop 1`] = `
|
|
|
85
85
|
pointer-events: none;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
.
|
|
88
|
+
.c18 {
|
|
89
89
|
width: 32px;
|
|
90
90
|
height: 32px;
|
|
91
91
|
border-radius: 50%;
|
|
@@ -107,6 +107,22 @@ exports[`renders correctly with data prop 1`] = `
|
|
|
107
107
|
flex-shrink: 0;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
.c17 {
|
|
111
|
+
padding-left: 1rem;
|
|
112
|
+
display: -webkit-box;
|
|
113
|
+
display: -webkit-flex;
|
|
114
|
+
display: -ms-flexbox;
|
|
115
|
+
display: flex;
|
|
116
|
+
-webkit-align-items: center;
|
|
117
|
+
-webkit-box-align: center;
|
|
118
|
+
-ms-flex-align: center;
|
|
119
|
+
align-items: center;
|
|
120
|
+
-webkit-box-pack: end;
|
|
121
|
+
-webkit-justify-content: flex-end;
|
|
122
|
+
-ms-flex-pack: end;
|
|
123
|
+
justify-content: flex-end;
|
|
124
|
+
}
|
|
125
|
+
|
|
110
126
|
.c3 {
|
|
111
127
|
display: -webkit-box;
|
|
112
128
|
display: -webkit-flex;
|
|
@@ -305,7 +321,7 @@ exports[`renders correctly with data prop 1`] = `
|
|
|
305
321
|
}
|
|
306
322
|
|
|
307
323
|
@media (min-width:1024px) {
|
|
308
|
-
.
|
|
324
|
+
.c18 {
|
|
309
325
|
background: #222222;
|
|
310
326
|
}
|
|
311
327
|
}
|
|
@@ -500,19 +516,23 @@ exports[`renders correctly with data prop 1`] = `
|
|
|
500
516
|
<div
|
|
501
517
|
className="c17"
|
|
502
518
|
>
|
|
503
|
-
<
|
|
519
|
+
<div
|
|
504
520
|
className="c18"
|
|
505
|
-
fill="none"
|
|
506
|
-
height="13"
|
|
507
|
-
viewBox="0 0 15 13"
|
|
508
|
-
width="15"
|
|
509
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
510
521
|
>
|
|
511
|
-
<
|
|
512
|
-
|
|
513
|
-
fill="
|
|
514
|
-
|
|
515
|
-
|
|
522
|
+
<svg
|
|
523
|
+
className="c19"
|
|
524
|
+
fill="none"
|
|
525
|
+
height="13"
|
|
526
|
+
viewBox="0 0 15 13"
|
|
527
|
+
width="15"
|
|
528
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
529
|
+
>
|
|
530
|
+
<path
|
|
531
|
+
d="M9.58496 0.349976C9.1395 -0.116662 8.40641 -0.116634 7.96094 0.349976C7.52803 0.803486 7.5281 1.53021 7.96094 1.98376L11.1582 5.33337H1.13672C0.48748 5.33337 0 5.87822 0 6.50037C2.15408e-05 7.1225 0.487494 7.66736 1.13672 7.66736H11.1582L7.96094 11.017C7.52806 11.4705 7.52899 12.1972 7.96191 12.6508C8.18163 12.8803 8.47556 13.0004 8.77344 13.0004C9.07114 13.0002 9.36533 12.8808 9.58496 12.6508L14.6758 7.31677L14.6748 7.3158L14.6875 7.3031L14.6865 7.30212C14.6954 7.29215 14.7044 7.28482 14.71 7.27771C14.7117 7.27545 14.7133 7.27285 14.7148 7.27087C14.7485 7.23203 14.7824 7.18925 14.8135 7.14099L14.8154 7.13806C14.8354 7.10658 14.8493 7.07842 14.8564 7.06384L14.8652 7.04626L14.8662 7.04431L14.8672 7.04333C14.8672 7.04333 14.868 7.04057 14.8691 7.03845C14.8709 7.03512 14.8758 7.02671 14.8799 7.01892L14.8802 7.01839C14.8888 7.002 14.9034 6.97423 14.917 6.93982V6.93787C14.9303 6.90375 14.9391 6.87285 14.9443 6.85388C14.9469 6.84458 14.9498 6.83567 14.9512 6.83044C14.9527 6.82454 14.9535 6.8228 14.9541 6.82068C14.9541 6.82068 14.9542 6.81753 14.9551 6.81482L14.958 6.80603L14.9586 6.80422C14.9631 6.78961 14.9718 6.76119 14.9785 6.72693V6.72498C15.0066 6.57705 15.0066 6.4246 14.9785 6.27673V6.27478L14.958 6.19568L14.9551 6.18591L14.9531 6.18005L14.9512 6.17224C14.9497 6.1664 14.9481 6.15677 14.9453 6.14685C14.9398 6.12695 14.9307 6.09654 14.917 6.06189C14.9032 6.02688 14.8885 5.99813 14.8799 5.98181C14.8758 5.97402 14.8709 5.96562 14.8691 5.96228L14.8564 5.93689C14.849 5.92177 14.8351 5.89372 14.8154 5.86267L14.8145 5.86072L14.7529 5.7738C14.7316 5.74659 14.7094 5.72129 14.6875 5.69763C14.6837 5.69341 14.6802 5.68854 14.6758 5.68396L9.58496 0.349976Z"
|
|
532
|
+
fill="currentColor"
|
|
533
|
+
/>
|
|
534
|
+
</svg>
|
|
535
|
+
</div>
|
|
516
536
|
</div>
|
|
517
537
|
</div>
|
|
518
538
|
</div>
|
|
@@ -540,7 +560,7 @@ exports[`renders correctly without image 1`] = `
|
|
|
540
560
|
line-height: inherit;
|
|
541
561
|
}
|
|
542
562
|
|
|
543
|
-
.
|
|
563
|
+
.c15 {
|
|
544
564
|
display: inline-block;
|
|
545
565
|
color: #FFFFFF;
|
|
546
566
|
fill: currentColor;
|
|
@@ -576,7 +596,7 @@ exports[`renders correctly without image 1`] = `
|
|
|
576
596
|
pointer-events: none;
|
|
577
597
|
}
|
|
578
598
|
|
|
579
|
-
.
|
|
599
|
+
.c14 {
|
|
580
600
|
width: 32px;
|
|
581
601
|
height: 32px;
|
|
582
602
|
border-radius: 50%;
|
|
@@ -598,6 +618,22 @@ exports[`renders correctly without image 1`] = `
|
|
|
598
618
|
flex-shrink: 0;
|
|
599
619
|
}
|
|
600
620
|
|
|
621
|
+
.c13 {
|
|
622
|
+
padding-left: 1rem;
|
|
623
|
+
display: -webkit-box;
|
|
624
|
+
display: -webkit-flex;
|
|
625
|
+
display: -ms-flexbox;
|
|
626
|
+
display: flex;
|
|
627
|
+
-webkit-align-items: center;
|
|
628
|
+
-webkit-box-align: center;
|
|
629
|
+
-ms-flex-align: center;
|
|
630
|
+
align-items: center;
|
|
631
|
+
-webkit-box-pack: end;
|
|
632
|
+
-webkit-justify-content: flex-end;
|
|
633
|
+
-ms-flex-pack: end;
|
|
634
|
+
justify-content: flex-end;
|
|
635
|
+
}
|
|
636
|
+
|
|
601
637
|
.c3 {
|
|
602
638
|
display: -webkit-box;
|
|
603
639
|
display: -webkit-flex;
|
|
@@ -758,7 +794,7 @@ exports[`renders correctly without image 1`] = `
|
|
|
758
794
|
}
|
|
759
795
|
|
|
760
796
|
@media (min-width:1024px) {
|
|
761
|
-
.
|
|
797
|
+
.c14 {
|
|
762
798
|
background: #222222;
|
|
763
799
|
}
|
|
764
800
|
}
|
|
@@ -922,19 +958,23 @@ exports[`renders correctly without image 1`] = `
|
|
|
922
958
|
<div
|
|
923
959
|
className="c13"
|
|
924
960
|
>
|
|
925
|
-
<
|
|
961
|
+
<div
|
|
926
962
|
className="c14"
|
|
927
|
-
fill="none"
|
|
928
|
-
height="13"
|
|
929
|
-
viewBox="0 0 15 13"
|
|
930
|
-
width="15"
|
|
931
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
932
963
|
>
|
|
933
|
-
<
|
|
934
|
-
|
|
935
|
-
fill="
|
|
936
|
-
|
|
937
|
-
|
|
964
|
+
<svg
|
|
965
|
+
className="c15"
|
|
966
|
+
fill="none"
|
|
967
|
+
height="13"
|
|
968
|
+
viewBox="0 0 15 13"
|
|
969
|
+
width="15"
|
|
970
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
971
|
+
>
|
|
972
|
+
<path
|
|
973
|
+
d="M9.58496 0.349976C9.1395 -0.116662 8.40641 -0.116634 7.96094 0.349976C7.52803 0.803486 7.5281 1.53021 7.96094 1.98376L11.1582 5.33337H1.13672C0.48748 5.33337 0 5.87822 0 6.50037C2.15408e-05 7.1225 0.487494 7.66736 1.13672 7.66736H11.1582L7.96094 11.017C7.52806 11.4705 7.52899 12.1972 7.96191 12.6508C8.18163 12.8803 8.47556 13.0004 8.77344 13.0004C9.07114 13.0002 9.36533 12.8808 9.58496 12.6508L14.6758 7.31677L14.6748 7.3158L14.6875 7.3031L14.6865 7.30212C14.6954 7.29215 14.7044 7.28482 14.71 7.27771C14.7117 7.27545 14.7133 7.27285 14.7148 7.27087C14.7485 7.23203 14.7824 7.18925 14.8135 7.14099L14.8154 7.13806C14.8354 7.10658 14.8493 7.07842 14.8564 7.06384L14.8652 7.04626L14.8662 7.04431L14.8672 7.04333C14.8672 7.04333 14.868 7.04057 14.8691 7.03845C14.8709 7.03512 14.8758 7.02671 14.8799 7.01892L14.8802 7.01839C14.8888 7.002 14.9034 6.97423 14.917 6.93982V6.93787C14.9303 6.90375 14.9391 6.87285 14.9443 6.85388C14.9469 6.84458 14.9498 6.83567 14.9512 6.83044C14.9527 6.82454 14.9535 6.8228 14.9541 6.82068C14.9541 6.82068 14.9542 6.81753 14.9551 6.81482L14.958 6.80603L14.9586 6.80422C14.9631 6.78961 14.9718 6.76119 14.9785 6.72693V6.72498C15.0066 6.57705 15.0066 6.4246 14.9785 6.27673V6.27478L14.958 6.19568L14.9551 6.18591L14.9531 6.18005L14.9512 6.17224C14.9497 6.1664 14.9481 6.15677 14.9453 6.14685C14.9398 6.12695 14.9307 6.09654 14.917 6.06189C14.9032 6.02688 14.8885 5.99813 14.8799 5.98181C14.8758 5.97402 14.8709 5.96562 14.8691 5.96228L14.8564 5.93689C14.849 5.92177 14.8351 5.89372 14.8154 5.86267L14.8145 5.86072L14.7529 5.7738C14.7316 5.74659 14.7094 5.72129 14.6875 5.69763C14.6837 5.69341 14.6802 5.68854 14.6758 5.68396L9.58496 0.349976Z"
|
|
974
|
+
fill="currentColor"
|
|
975
|
+
/>
|
|
976
|
+
</svg>
|
|
977
|
+
</div>
|
|
938
978
|
</div>
|
|
939
979
|
</div>
|
|
940
980
|
</div>
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
CTA,
|
|
13
13
|
CTAText,
|
|
14
14
|
CTATextUnderline,
|
|
15
|
+
ArrowIconOuter,
|
|
15
16
|
ArrowIconWrapper,
|
|
16
17
|
CardWrapper
|
|
17
18
|
} from './CTACard.style';
|
|
@@ -88,9 +89,11 @@ const CTACard = ({
|
|
|
88
89
|
aria-hidden="true"
|
|
89
90
|
/>
|
|
90
91
|
</CTAText>
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
|
|
92
|
+
<ArrowIconOuter>
|
|
93
|
+
<ArrowIconWrapper>
|
|
94
|
+
<ArrowIcon />
|
|
95
|
+
</ArrowIconWrapper>
|
|
96
|
+
</ArrowIconOuter>
|
|
94
97
|
</CTA>
|
|
95
98
|
)}
|
|
96
99
|
</CopyAndLinkSection>
|
|
@@ -88,6 +88,13 @@ const ArrowIconWrapper = styled.div`
|
|
|
88
88
|
flex-shrink: 0;
|
|
89
89
|
`;
|
|
90
90
|
|
|
91
|
+
const ArrowIconOuter = styled.div`
|
|
92
|
+
padding-left: 1rem;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: flex-end;
|
|
96
|
+
`;
|
|
97
|
+
|
|
91
98
|
// Card wrapper link - makes entire card clickable
|
|
92
99
|
const CardLink = styled.a`
|
|
93
100
|
display: flex;
|
|
@@ -316,6 +323,7 @@ export {
|
|
|
316
323
|
CTA,
|
|
317
324
|
CTAText,
|
|
318
325
|
CTATextUnderline,
|
|
326
|
+
ArrowIconOuter,
|
|
319
327
|
ArrowIconWrapper,
|
|
320
328
|
CardWrapper
|
|
321
329
|
};
|
|
@@ -98,6 +98,7 @@ const DynamicGallery = ({
|
|
|
98
98
|
|
|
99
99
|
// handle selected gallery node
|
|
100
100
|
const [selectedNode, setSelectedNode] = useState(null);
|
|
101
|
+
const [focusedNode, setFocusedNode] = useState(null);
|
|
101
102
|
|
|
102
103
|
// handle next/previous node events from the lightbox
|
|
103
104
|
function handleNextNode(node) {
|
|
@@ -122,6 +123,8 @@ const DynamicGallery = ({
|
|
|
122
123
|
const nodeIndex = +event.target.dataset.nodeIndex;
|
|
123
124
|
if (Number.isNaN(nodeIndex)) return;
|
|
124
125
|
setSelectedNode(nodes[nodeIndex]);
|
|
126
|
+
// also store the focused node for focus restoration when the lightbox closes
|
|
127
|
+
setFocusedNode(event.target.closest('.gallery-node'));
|
|
125
128
|
}
|
|
126
129
|
break;
|
|
127
130
|
}
|
|
@@ -188,7 +191,9 @@ const DynamicGallery = ({
|
|
|
188
191
|
selectedNode,
|
|
189
192
|
setSelectedNode,
|
|
190
193
|
nextNode: handleNextNode,
|
|
191
|
-
previousNode: handlePreviousNode
|
|
194
|
+
previousNode: handlePreviousNode,
|
|
195
|
+
focusedNode,
|
|
196
|
+
setFocusedNode
|
|
192
197
|
}}
|
|
193
198
|
>
|
|
194
199
|
<ImageGrid className="gallery-grid" onKeyDown={event => handleKeyDown(event)}>
|
|
@@ -206,6 +211,7 @@ const DynamicGallery = ({
|
|
|
206
211
|
nodes={nodes.slice(0, imageCount)}
|
|
207
212
|
imageRatio={imageRatio}
|
|
208
213
|
updateTabOrder={throttledUpdateTabOrder.current}
|
|
214
|
+
focusOutlineColour={textColour}
|
|
209
215
|
/>
|
|
210
216
|
))}
|
|
211
217
|
|
|
@@ -215,7 +221,7 @@ const DynamicGallery = ({
|
|
|
215
221
|
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */}
|
|
216
222
|
<div className="gallery-focus-trap" tabIndex={0} />
|
|
217
223
|
</LightboxContext.Provider>
|
|
218
|
-
{imageCount < nodes.length && <Button onClick={() => handleLoadMore()}>
|
|
224
|
+
{imageCount < nodes.length && <Button onClick={() => handleLoadMore()}>Show more</Button>}
|
|
219
225
|
</Container>
|
|
220
226
|
);
|
|
221
227
|
};
|
|
@@ -39,12 +39,18 @@ export const EmptyMessage = styled.div`
|
|
|
39
39
|
const GalleryNodeBase = css`
|
|
40
40
|
display: flex;
|
|
41
41
|
flex-direction: column;
|
|
42
|
-
gap: 0.
|
|
42
|
+
gap: 0.9rem;
|
|
43
43
|
padding: 0;
|
|
44
44
|
margin: 0;
|
|
45
45
|
background: none;
|
|
46
46
|
border: none;
|
|
47
47
|
text-align: left;
|
|
48
|
+
|
|
49
|
+
&:focus-visible {
|
|
50
|
+
outline: 2px solid ${({ focusOutlineColour }) => focusOutlineColour};
|
|
51
|
+
outline-offset: 0.5rem;
|
|
52
|
+
border-radius: 1rem;
|
|
53
|
+
}
|
|
48
54
|
`;
|
|
49
55
|
|
|
50
56
|
export const GalleryNode = styled.div`
|
|
@@ -60,10 +66,6 @@ export const InteractiveGalleryNode = styled.button`
|
|
|
60
66
|
transition: all 0.1s ease-out;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
|
-
&:focus-visible {
|
|
64
|
-
outline: 2px solid #000000;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
69
|
& > div:first-child {
|
|
68
70
|
&:hover {
|
|
69
71
|
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.4);
|
|
@@ -95,13 +97,3 @@ export const Details = styled.div`
|
|
|
95
97
|
gap: 0.5rem;
|
|
96
98
|
padding: 0 1rem;
|
|
97
99
|
`;
|
|
98
|
-
|
|
99
|
-
export const Title = styled.div`
|
|
100
|
-
&:first-child {
|
|
101
|
-
margin-bottom: 0;
|
|
102
|
-
}
|
|
103
|
-
`;
|
|
104
|
-
|
|
105
|
-
export const Caption = styled.div`
|
|
106
|
-
line-height: 1;
|
|
107
|
-
`;
|
|
@@ -10,21 +10,21 @@ import React, {
|
|
|
10
10
|
import Picture from '../../Atoms/Picture/Picture';
|
|
11
11
|
import { LightboxContext } from './_Lightbox';
|
|
12
12
|
import {
|
|
13
|
-
Caption,
|
|
14
13
|
Column,
|
|
15
14
|
Details,
|
|
16
15
|
GalleryNode,
|
|
17
16
|
ImageContainer,
|
|
18
|
-
InteractiveGalleryNode
|
|
19
|
-
Title
|
|
17
|
+
InteractiveGalleryNode
|
|
20
18
|
} from './DynamicGallery.style';
|
|
21
19
|
import { GalleryNodeType } from './_types';
|
|
20
|
+
import { extractNodeText } from './_utils';
|
|
22
21
|
|
|
23
22
|
/**
|
|
24
23
|
* a separate component to handle columns of images;
|
|
25
24
|
* this component handles aspect ratio calculations to enfore a min/max ratio for its images
|
|
26
25
|
*/
|
|
27
26
|
export default function DynamicGalleryColumn({
|
|
27
|
+
focusOutlineColour,
|
|
28
28
|
updateTabOrder,
|
|
29
29
|
nodes,
|
|
30
30
|
imageRatio,
|
|
@@ -92,45 +92,52 @@ export default function DynamicGalleryColumn({
|
|
|
92
92
|
<Column ref={elRef} className="gallery-column">
|
|
93
93
|
{nodes
|
|
94
94
|
?.filter((_, nodeIndex) => nodeIndex % columnCount === columnIndex)
|
|
95
|
-
.map((node, nodeIndex) =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// eslint-disable-next-line prefer-template
|
|
110
|
-
maxHeight={String(maxHeight) + 'px'}
|
|
95
|
+
.map((node, nodeIndex) => {
|
|
96
|
+
const bodyText = extractNodeText(node.gridBody);
|
|
97
|
+
const key = String(nodeIndex) + bodyText;
|
|
98
|
+
return (
|
|
99
|
+
<NodeComponent
|
|
100
|
+
key={key}
|
|
101
|
+
className="gallery-node"
|
|
102
|
+
caption={bodyText}
|
|
103
|
+
aria-label={bodyText}
|
|
104
|
+
title={bodyText}
|
|
105
|
+
data-node-index={nodeIndex}
|
|
106
|
+
focusOutlineColour={focusOutlineColour}
|
|
107
|
+
onPointerUp={useLightbox ? () => handlePointerUp(node) : undefined}
|
|
108
|
+
tabIndex={0}
|
|
111
109
|
>
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
110
|
+
<ImageContainer
|
|
111
|
+
className="gallery-node-image"
|
|
112
|
+
// eslint prefers template literals for strings, but they break the compiler
|
|
113
|
+
// eslint-disable-next-line prefer-template
|
|
114
|
+
minHeight={String(minHeight) + 'px'}
|
|
115
|
+
// eslint-disable-next-line prefer-template
|
|
116
|
+
maxHeight={String(maxHeight) + 'px'}
|
|
117
|
+
>
|
|
118
|
+
<Picture
|
|
119
|
+
image={node.image}
|
|
120
|
+
objectFit="cover"
|
|
121
|
+
alt={bodyText}
|
|
122
|
+
// animate image in on load
|
|
123
|
+
onLoad={event => {
|
|
124
|
+
event.target
|
|
125
|
+
.closest('.gallery-node-image')
|
|
126
|
+
.querySelector('img')
|
|
127
|
+
.style.setProperty('opacity', '1');
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
// update tab order once the image has loaded
|
|
130
|
+
updateTabOrder();
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
133
|
+
</ImageContainer>
|
|
134
|
+
<Details>
|
|
135
|
+
{node.gridBody && <div>{node.gridBody}</div>}
|
|
136
|
+
{node.gridCaption && <div>{node.gridCaption}</div>}
|
|
137
|
+
</Details>
|
|
138
|
+
</NodeComponent>
|
|
139
|
+
);
|
|
140
|
+
})}
|
|
134
141
|
</Column>
|
|
135
142
|
);
|
|
136
143
|
}
|
|
@@ -140,5 +147,6 @@ DynamicGalleryColumn.propTypes = {
|
|
|
140
147
|
imageRatio: PropTypes.oneOf(['dynamic', '4:3']),
|
|
141
148
|
columnIndex: PropTypes.number,
|
|
142
149
|
columnCount: PropTypes.number,
|
|
143
|
-
updateTabOrder: PropTypes.func
|
|
150
|
+
updateTabOrder: PropTypes.func,
|
|
151
|
+
focusOutlineColour: PropTypes.string
|
|
144
152
|
};
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
ScreenReaderOnly
|
|
20
20
|
} from './_Lightbox.style';
|
|
21
21
|
import ScrollFix from './_ScrollFix';
|
|
22
|
+
import { extractNodeText } from './_utils';
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* lightbox context:
|
|
@@ -59,12 +60,13 @@ const Lightbox = () => {
|
|
|
59
60
|
selectedNode,
|
|
60
61
|
setSelectedNode,
|
|
61
62
|
nextNode,
|
|
62
|
-
previousNode
|
|
63
|
+
previousNode,
|
|
64
|
+
focusedNode,
|
|
65
|
+
setFocusedNode
|
|
63
66
|
} = useContext(LightboxContext);
|
|
64
67
|
|
|
65
68
|
const hasNode = Boolean(selectedNode);
|
|
66
69
|
const dialogRef = useRef(null);
|
|
67
|
-
const previousFocusRef = useRef(null);
|
|
68
70
|
|
|
69
71
|
/**
|
|
70
72
|
* handle keyboard events within the lightbox;
|
|
@@ -125,30 +127,20 @@ const Lightbox = () => {
|
|
|
125
127
|
|
|
126
128
|
// handle focus management when dialog opens/closes
|
|
127
129
|
useEffect(() => {
|
|
128
|
-
// when the lightbox is opened, store the previously focused element
|
|
129
|
-
// and move focus to the first focusable element in the dialog
|
|
130
130
|
if (hasNode) {
|
|
131
|
-
//
|
|
132
|
-
previousFocusRef.current = document.activeElement;
|
|
133
|
-
// move focus to the first focusable element in the dialog
|
|
131
|
+
// move focus to the first focusable element in the dialog when it opens
|
|
134
132
|
setTimeout(() => {
|
|
135
133
|
const focusableElements = getFocusableElements(dialogRef.current);
|
|
136
134
|
if (focusableElements.length > 0) {
|
|
137
135
|
focusableElements[0].focus();
|
|
138
136
|
}
|
|
139
137
|
}, 0);
|
|
140
|
-
|
|
138
|
+
} else {
|
|
139
|
+
// restore focus to the previously focused element when lightbox closes
|
|
140
|
+
focusedNode?.focus();
|
|
141
|
+
setFocusedNode(null);
|
|
141
142
|
}
|
|
142
|
-
|
|
143
|
-
// when the lightbox is closed, restore focus to the previously focused element
|
|
144
|
-
if (
|
|
145
|
-
previousFocusRef.current
|
|
146
|
-
&& typeof previousFocusRef.current.focus === 'function'
|
|
147
|
-
) {
|
|
148
|
-
previousFocusRef.current.focus();
|
|
149
|
-
previousFocusRef.current = null;
|
|
150
|
-
}
|
|
151
|
-
}, [hasNode]);
|
|
143
|
+
}, [hasNode, focusedNode, setFocusedNode]);
|
|
152
144
|
|
|
153
145
|
/**
|
|
154
146
|
* close the lightbox when the backdrop is clicked
|
|
@@ -182,9 +174,13 @@ const Lightbox = () => {
|
|
|
182
174
|
target.style.opacity = '1';
|
|
183
175
|
}
|
|
184
176
|
|
|
177
|
+
const bodyText = extractNodeText(selectedNode?.lightboxBody);
|
|
178
|
+
|
|
185
179
|
return (
|
|
186
180
|
<Container isOpen={hasNode}>
|
|
187
|
-
<Backdrop
|
|
181
|
+
<Backdrop
|
|
182
|
+
onPointerUp={() => handleBackdropClick()}
|
|
183
|
+
/>
|
|
188
184
|
<Dialog
|
|
189
185
|
ref={dialogRef}
|
|
190
186
|
aria-labelledby="lightboxTitle"
|
|
@@ -199,7 +195,7 @@ const Lightbox = () => {
|
|
|
199
195
|
{hasNode && (
|
|
200
196
|
<Picture
|
|
201
197
|
key={selectedNode?.image}
|
|
202
|
-
alt={
|
|
198
|
+
alt={bodyText}
|
|
203
199
|
image={selectedNode?.image}
|
|
204
200
|
width={imageDimensions.width}
|
|
205
201
|
height={imageDimensions.height}
|
|
@@ -209,15 +205,14 @@ const Lightbox = () => {
|
|
|
209
205
|
)}
|
|
210
206
|
</LightboxImage>
|
|
211
207
|
<LightboxDetails id="lightboxDescription" aria-live="polite" aria-atomic="true">
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
{selectedNode?.caption}
|
|
208
|
+
{selectedNode?.lightboxBody && (
|
|
209
|
+
<div id="lightboxTitle">
|
|
210
|
+
{selectedNode.lightboxBody}
|
|
216
211
|
</div>
|
|
217
212
|
)}
|
|
218
|
-
{selectedNode?.
|
|
213
|
+
{selectedNode?.lightboxCaption && (
|
|
219
214
|
<div>
|
|
220
|
-
{selectedNode
|
|
215
|
+
{selectedNode?.lightboxCaption}
|
|
221
216
|
</div>
|
|
222
217
|
)}
|
|
223
218
|
</LightboxDetails>
|