@comicrelief/component-library 8.55.2 → 8.55.4
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/Organisms/DynamicGallery/_Lightbox.js +22 -20
- package/dist/components/Organisms/DynamicGallery/_Lightbox.style.js +13 -8
- package/dist/theme/shared/global.css +2 -2
- package/package.json +1 -1
- package/playwright/components/organisms/dynamicGallery.spec.js +33 -0
- package/src/components/Organisms/DynamicGallery/_Lightbox.js +24 -17
- package/src/components/Organisms/DynamicGallery/_Lightbox.style.js +6 -0
- package/src/theme/shared/global.css +2 -2
|
@@ -10,7 +10,6 @@ var _react = _interopRequireWildcard(require("react"));
|
|
|
10
10
|
var _PulseLoader = _interopRequireDefault(require("react-spinners/PulseLoader"));
|
|
11
11
|
var _Arrow = _interopRequireDefault(require("../../Atoms/Icons/Arrow"));
|
|
12
12
|
var _Cross = _interopRequireDefault(require("../../Atoms/Icons/Cross"));
|
|
13
|
-
var _Picture = _interopRequireDefault(require("../../Atoms/Picture/Picture"));
|
|
14
13
|
var _Lightbox = require("./_Lightbox.style");
|
|
15
14
|
var _DynamicGallery = require("./DynamicGallery.style");
|
|
16
15
|
var _ScrollFix = _interopRequireDefault(require("./_ScrollFix"));
|
|
@@ -53,19 +52,6 @@ const Lightbox = () => {
|
|
|
53
52
|
const hasNode = Boolean(selectedNode);
|
|
54
53
|
const dialogRef = (0, _react.useRef)(null);
|
|
55
54
|
|
|
56
|
-
// handle interaction type
|
|
57
|
-
const interactionTypeRef = (0, _react.useRef)('keyboard');
|
|
58
|
-
(0, _react.useEffect)(() => {
|
|
59
|
-
function handlePointerDown() {
|
|
60
|
-
interactionTypeRef.current = 'pointer';
|
|
61
|
-
document.removeEventListener('pointerdown', handlePointerDown);
|
|
62
|
-
}
|
|
63
|
-
document.addEventListener('pointerdown', handlePointerDown);
|
|
64
|
-
return () => {
|
|
65
|
-
document.removeEventListener('pointerdown', handlePointerDown);
|
|
66
|
-
};
|
|
67
|
-
}, []);
|
|
68
|
-
|
|
69
55
|
/**
|
|
70
56
|
* handle keyboard events within the lightbox;
|
|
71
57
|
* - trapped focus between UI elements
|
|
@@ -118,6 +104,26 @@ const Lightbox = () => {
|
|
|
118
104
|
};
|
|
119
105
|
}, [hasNode, selectedNode, setSelectedNode, previousNode, nextNode]);
|
|
120
106
|
|
|
107
|
+
// when the user interacts with the page, check the interaction type.
|
|
108
|
+
// this is used to determine whether to focus the close button when the lightbox opens;
|
|
109
|
+
// for keyboard interaction, we focus the close button automatically.
|
|
110
|
+
// ideally we could just use focus-visible, but Safari on iOS always shows the focus ring.
|
|
111
|
+
const interactionTypeRef = (0, _react.useRef)('keyboard');
|
|
112
|
+
(0, _react.useEffect)(() => {
|
|
113
|
+
function handlePointerDown() {
|
|
114
|
+
interactionTypeRef.current = 'pointer';
|
|
115
|
+
}
|
|
116
|
+
function handleKeyDown() {
|
|
117
|
+
interactionTypeRef.current = 'keyboard';
|
|
118
|
+
}
|
|
119
|
+
document.addEventListener('pointerdown', handlePointerDown);
|
|
120
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
121
|
+
return () => {
|
|
122
|
+
document.removeEventListener('pointerdown', handlePointerDown);
|
|
123
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
124
|
+
};
|
|
125
|
+
}, []);
|
|
126
|
+
|
|
121
127
|
// handle focus management when dialog opens/closes
|
|
122
128
|
(0, _react.useEffect)(() => {
|
|
123
129
|
if (hasNode) {
|
|
@@ -191,18 +197,14 @@ const Lightbox = () => {
|
|
|
191
197
|
height: 16,
|
|
192
198
|
width: 2,
|
|
193
199
|
color: "#E1E2E3"
|
|
194
|
-
})), hasNode && /*#__PURE__*/_react.default.createElement(
|
|
200
|
+
})), hasNode && /*#__PURE__*/_react.default.createElement(_Lightbox.LightboxPicture, {
|
|
195
201
|
key: selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.image,
|
|
196
202
|
alt: bodyText,
|
|
197
203
|
image: selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.image,
|
|
198
204
|
width: imageDimensions.width,
|
|
199
205
|
height: imageDimensions.height,
|
|
200
206
|
objectFit: "contain",
|
|
201
|
-
onLoad: event => onLoad(event)
|
|
202
|
-
style: {
|
|
203
|
-
borderRadius: '0.6rem',
|
|
204
|
-
overflow: 'hidden'
|
|
205
|
-
}
|
|
207
|
+
onLoad: event => onLoad(event)
|
|
206
208
|
}), /*#__PURE__*/_react.default.createElement(_Lightbox.PreviousButton, {
|
|
207
209
|
type: "button",
|
|
208
210
|
onClick: () => previousNode(selectedNode)
|
|
@@ -4,8 +4,9 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.PreviousButton = exports.NextButton = exports.NavButton = exports.LightboxSpinner = exports.LightboxImage = exports.LightboxDetails = exports.LightboxContent = exports.Dialog = exports.Container = exports.CloseButton = exports.Backdrop = void 0;
|
|
7
|
+
exports.PreviousButton = exports.NextButton = exports.NavButton = exports.LightboxSpinner = exports.LightboxPicture = exports.LightboxImage = exports.LightboxDetails = exports.LightboxContent = exports.Dialog = exports.Container = exports.CloseButton = exports.Backdrop = void 0;
|
|
8
8
|
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
9
|
+
var _Picture = _interopRequireDefault(require("../../Atoms/Picture/Picture"));
|
|
9
10
|
const Container = exports.Container = _styledComponents.default.div.withConfig({
|
|
10
11
|
displayName: "_Lightboxstyle__Container",
|
|
11
12
|
componentId: "sc-twdy7x-0"
|
|
@@ -32,21 +33,25 @@ const LightboxContent = exports.LightboxContent = _styledComponents.default.div.
|
|
|
32
33
|
displayName: "_Lightboxstyle__LightboxContent",
|
|
33
34
|
componentId: "sc-twdy7x-3"
|
|
34
35
|
})(["display:flex;flex-direction:column;align-items:center;gap:1rem;position:relative;padding:1rem;background:#ffffff;border-radius:1rem;"]);
|
|
36
|
+
const LightboxPicture = exports.LightboxPicture = (0, _styledComponents.default)(_Picture.default).withConfig({
|
|
37
|
+
displayName: "_Lightboxstyle__LightboxPicture",
|
|
38
|
+
componentId: "sc-twdy7x-4"
|
|
39
|
+
})(["overflow:hidden;border-radius:0.6rem;"]);
|
|
35
40
|
const LightboxImage = exports.LightboxImage = _styledComponents.default.div.withConfig({
|
|
36
41
|
displayName: "_Lightboxstyle__LightboxImage",
|
|
37
|
-
componentId: "sc-twdy7x-
|
|
42
|
+
componentId: "sc-twdy7x-5"
|
|
38
43
|
})(["position:relative;display:flex;align-items:center;justify-content:center;min-width:128px;min-height:32px;width:100%;& > div{display:flex;align-items:center;justify-content:center;transition:width 0.3s ease-in-out,height 0.3s ease-in-out;}& img{opacity:0;transition:opacity 0.1s ease-out 0.3s;}"]);
|
|
39
44
|
const LightboxSpinner = exports.LightboxSpinner = _styledComponents.default.div.withConfig({
|
|
40
45
|
displayName: "_Lightboxstyle__LightboxSpinner",
|
|
41
|
-
componentId: "sc-twdy7x-
|
|
46
|
+
componentId: "sc-twdy7x-6"
|
|
42
47
|
})(["position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);"]);
|
|
43
48
|
const LightboxDetails = exports.LightboxDetails = _styledComponents.default.div.withConfig({
|
|
44
49
|
displayName: "_Lightboxstyle__LightboxDetails",
|
|
45
|
-
componentId: "sc-twdy7x-
|
|
50
|
+
componentId: "sc-twdy7x-7"
|
|
46
51
|
})(["display:flex;flex-direction:column;align-items:stretch;gap:0.5rem;width:100%;max-width:1024px;padding:0 1rem;"]);
|
|
47
52
|
const NavButton = exports.NavButton = _styledComponents.default.button.withConfig({
|
|
48
53
|
displayName: "_Lightboxstyle__NavButton",
|
|
49
|
-
componentId: "sc-twdy7x-
|
|
54
|
+
componentId: "sc-twdy7x-8"
|
|
50
55
|
})(["position:absolute;display:flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;border-radius:0.5rem;border:none;background-color:white;cursor:pointer;z-index:10;svg{transition:fill 0.1s ease-out;}@media (hover:hover){&:hover{svg{fill:", ";}}}:focus-visible{outline:2px solid ", ";}"], _ref3 => {
|
|
51
56
|
let {
|
|
52
57
|
theme
|
|
@@ -60,11 +65,11 @@ const NavButton = exports.NavButton = _styledComponents.default.button.withConfi
|
|
|
60
65
|
});
|
|
61
66
|
const CloseButton = exports.CloseButton = (0, _styledComponents.default)(NavButton).withConfig({
|
|
62
67
|
displayName: "_Lightboxstyle__CloseButton",
|
|
63
|
-
componentId: "sc-twdy7x-
|
|
68
|
+
componentId: "sc-twdy7x-9"
|
|
64
69
|
})(["top:0;right:0;"]);
|
|
65
70
|
const PreviousButton = exports.PreviousButton = (0, _styledComponents.default)(NavButton).withConfig({
|
|
66
71
|
displayName: "_Lightboxstyle__PreviousButton",
|
|
67
|
-
componentId: "sc-twdy7x-
|
|
72
|
+
componentId: "sc-twdy7x-10"
|
|
68
73
|
})(["top:50%;left:0;transform:translate(-1rem,-50%);@media ", "{position:fixed;transform:translate(1rem,-50%);top:50%;}"], _ref5 => {
|
|
69
74
|
let {
|
|
70
75
|
theme
|
|
@@ -73,7 +78,7 @@ const PreviousButton = exports.PreviousButton = (0, _styledComponents.default)(N
|
|
|
73
78
|
});
|
|
74
79
|
const NextButton = exports.NextButton = (0, _styledComponents.default)(NavButton).withConfig({
|
|
75
80
|
displayName: "_Lightboxstyle__NextButton",
|
|
76
|
-
componentId: "sc-twdy7x-
|
|
81
|
+
componentId: "sc-twdy7x-11"
|
|
77
82
|
})(["top:50%;right:0;transform:translate(1rem,-50%);@media ", "{position:fixed;transform:translate(-1rem,-50%);top:50%;}"], _ref6 => {
|
|
78
83
|
let {
|
|
79
84
|
theme
|
|
@@ -47,7 +47,7 @@ body {
|
|
|
47
47
|
h1 {
|
|
48
48
|
text-transform: uppercase;
|
|
49
49
|
font-family: 'Anton', Impact, sans-serif;
|
|
50
|
-
margin:
|
|
50
|
+
margin-bottom: 1rem;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
h1:only-child,
|
|
@@ -68,7 +68,7 @@ button {
|
|
|
68
68
|
h2 {
|
|
69
69
|
text-transform: uppercase;
|
|
70
70
|
font-family: 'Anton', Impact, sans-serif;
|
|
71
|
-
margin-bottom:
|
|
71
|
+
margin-bottom: 1rem;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
h3, h4, h5 {
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ function hexToRgb(hex) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
test.describe('dynamic gallery component', () => {
|
|
16
|
+
// MARK: smoke test
|
|
16
17
|
test('smoke test', async ({ page }) => {
|
|
17
18
|
await page.goto('/#dynamicgallery');
|
|
18
19
|
|
|
@@ -28,6 +29,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
28
29
|
await page.close();
|
|
29
30
|
});
|
|
30
31
|
|
|
32
|
+
// MARK: responsive columns
|
|
31
33
|
test('responsive gallery columns', async ({ page }) => {
|
|
32
34
|
await page.goto('/#!/DynamicGallery/3');
|
|
33
35
|
|
|
@@ -49,6 +51,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
49
51
|
await page.close();
|
|
50
52
|
});
|
|
51
53
|
|
|
54
|
+
// MARK: chunk mode
|
|
52
55
|
test('chunk mode test', async ({ page }) => {
|
|
53
56
|
await page.goto('/#!/DynamicGallery/3');
|
|
54
57
|
|
|
@@ -67,6 +70,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
67
70
|
await page.close();
|
|
68
71
|
});
|
|
69
72
|
|
|
73
|
+
// MARK: non-chunk mode
|
|
70
74
|
test('non-chunk mode test', async ({ page }) => {
|
|
71
75
|
await page.goto('/#!/DynamicGallery/5');
|
|
72
76
|
|
|
@@ -79,6 +83,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
79
83
|
await page.close();
|
|
80
84
|
});
|
|
81
85
|
|
|
86
|
+
// MARK: tabbing
|
|
82
87
|
test('gallery tabbing', async ({ page }) => {
|
|
83
88
|
await page.goto('/#!/DynamicGallery/3');
|
|
84
89
|
|
|
@@ -104,6 +109,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
104
109
|
await page.close();
|
|
105
110
|
});
|
|
106
111
|
|
|
112
|
+
// MARK: tabbing out
|
|
107
113
|
test('gallery tabbing should allow tabbing out of the gallery', async ({ page }) => {
|
|
108
114
|
await page.goto('/#!/DynamicGallery/5');
|
|
109
115
|
|
|
@@ -126,6 +132,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
126
132
|
await page.close();
|
|
127
133
|
});
|
|
128
134
|
|
|
135
|
+
// MARK: colours
|
|
129
136
|
test('custom page background and text colour', async ({ page }) => {
|
|
130
137
|
await page.goto('/#!/DynamicGallery/5');
|
|
131
138
|
|
|
@@ -140,6 +147,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
140
147
|
await page.close();
|
|
141
148
|
});
|
|
142
149
|
|
|
150
|
+
// MARK: lightbox mode
|
|
143
151
|
test('check lightbox mode', async ({ page }) => {
|
|
144
152
|
await page.goto('/#!/DynamicGallery/3');
|
|
145
153
|
|
|
@@ -166,6 +174,29 @@ test.describe('dynamic gallery component', () => {
|
|
|
166
174
|
await page.close();
|
|
167
175
|
});
|
|
168
176
|
|
|
177
|
+
// MARK: lightbox focus
|
|
178
|
+
test('check lightbox auto-focus', async ({ page }) => {
|
|
179
|
+
await page.goto('/#!/DynamicGallery/3');
|
|
180
|
+
|
|
181
|
+
// find the first gallery node
|
|
182
|
+
const galleryNode = page.locator('.gallery-node').first();
|
|
183
|
+
|
|
184
|
+
// click it
|
|
185
|
+
await galleryNode.click();
|
|
186
|
+
|
|
187
|
+
// the close button should not be focused after opening the lightbox with the mouse
|
|
188
|
+
await expect(page.locator('.close-button')).not.toBeFocused();
|
|
189
|
+
await page.keyboard.press('Escape');
|
|
190
|
+
|
|
191
|
+
// the close button should be focused after opening the lightbox with the keyboard
|
|
192
|
+
await galleryNode.focus();
|
|
193
|
+
await page.keyboard.press('Enter');
|
|
194
|
+
await expect(page.locator('.close-button')).toBeFocused();
|
|
195
|
+
|
|
196
|
+
await page.close();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// MARK: lightbox navigation
|
|
169
200
|
test('lightbox navigation', async ({ page }) => {
|
|
170
201
|
await page.goto('/#!/DynamicGallery/3');
|
|
171
202
|
|
|
@@ -188,6 +219,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
188
219
|
await page.close();
|
|
189
220
|
});
|
|
190
221
|
|
|
222
|
+
// MARK: lightbox pointer close
|
|
191
223
|
test('lightbox pointer close', async ({ page }) => {
|
|
192
224
|
await page.goto('/#!/DynamicGallery/3');
|
|
193
225
|
|
|
@@ -206,6 +238,7 @@ test.describe('dynamic gallery component', () => {
|
|
|
206
238
|
await page.close();
|
|
207
239
|
});
|
|
208
240
|
|
|
241
|
+
// MARK: non-lightbox mode
|
|
209
242
|
test('check non-lightbox mode', async ({ page }) => {
|
|
210
243
|
await page.goto('/#!/DynamicGallery/5');
|
|
211
244
|
|
|
@@ -4,13 +4,13 @@ import React, {
|
|
|
4
4
|
import PulseLoader from 'react-spinners/PulseLoader';
|
|
5
5
|
import Arrow from '../../Atoms/Icons/Arrow';
|
|
6
6
|
import Cross from '../../Atoms/Icons/Cross';
|
|
7
|
-
import Picture from '../../Atoms/Picture/Picture';
|
|
8
7
|
import {
|
|
9
8
|
Backdrop,
|
|
10
9
|
CloseButton,
|
|
11
10
|
Container,
|
|
12
11
|
Dialog,
|
|
13
12
|
LightboxContent,
|
|
13
|
+
LightboxPicture,
|
|
14
14
|
LightboxDetails,
|
|
15
15
|
LightboxImage,
|
|
16
16
|
LightboxSpinner,
|
|
@@ -68,20 +68,6 @@ const Lightbox = () => {
|
|
|
68
68
|
const hasNode = Boolean(selectedNode);
|
|
69
69
|
const dialogRef = useRef(null);
|
|
70
70
|
|
|
71
|
-
// handle interaction type
|
|
72
|
-
const interactionTypeRef = useRef('keyboard');
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
function handlePointerDown() {
|
|
76
|
-
interactionTypeRef.current = 'pointer';
|
|
77
|
-
document.removeEventListener('pointerdown', handlePointerDown);
|
|
78
|
-
}
|
|
79
|
-
document.addEventListener('pointerdown', handlePointerDown);
|
|
80
|
-
return () => {
|
|
81
|
-
document.removeEventListener('pointerdown', handlePointerDown);
|
|
82
|
-
};
|
|
83
|
-
}, []);
|
|
84
|
-
|
|
85
71
|
/**
|
|
86
72
|
* handle keyboard events within the lightbox;
|
|
87
73
|
* - trapped focus between UI elements
|
|
@@ -139,6 +125,28 @@ const Lightbox = () => {
|
|
|
139
125
|
};
|
|
140
126
|
}, [hasNode, selectedNode, setSelectedNode, previousNode, nextNode]);
|
|
141
127
|
|
|
128
|
+
// when the user interacts with the page, check the interaction type.
|
|
129
|
+
// this is used to determine whether to focus the close button when the lightbox opens;
|
|
130
|
+
// for keyboard interaction, we focus the close button automatically.
|
|
131
|
+
// ideally we could just use focus-visible, but Safari on iOS always shows the focus ring.
|
|
132
|
+
const interactionTypeRef = useRef('keyboard');
|
|
133
|
+
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
function handlePointerDown() {
|
|
136
|
+
interactionTypeRef.current = 'pointer';
|
|
137
|
+
}
|
|
138
|
+
function handleKeyDown() {
|
|
139
|
+
interactionTypeRef.current = 'keyboard';
|
|
140
|
+
}
|
|
141
|
+
document.addEventListener('pointerdown', handlePointerDown);
|
|
142
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
143
|
+
|
|
144
|
+
return () => {
|
|
145
|
+
document.removeEventListener('pointerdown', handlePointerDown);
|
|
146
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
147
|
+
};
|
|
148
|
+
}, []);
|
|
149
|
+
|
|
142
150
|
// handle focus management when dialog opens/closes
|
|
143
151
|
useEffect(() => {
|
|
144
152
|
if (hasNode) {
|
|
@@ -209,7 +217,7 @@ const Lightbox = () => {
|
|
|
209
217
|
<PulseLoader height={16} width={2} color="#E1E2E3" />
|
|
210
218
|
</LightboxSpinner>
|
|
211
219
|
{hasNode && (
|
|
212
|
-
<
|
|
220
|
+
<LightboxPicture
|
|
213
221
|
key={selectedNode?.image}
|
|
214
222
|
alt={bodyText}
|
|
215
223
|
image={selectedNode?.image}
|
|
@@ -217,7 +225,6 @@ const Lightbox = () => {
|
|
|
217
225
|
height={imageDimensions.height}
|
|
218
226
|
objectFit="contain"
|
|
219
227
|
onLoad={event => onLoad(event)}
|
|
220
|
-
style={{ borderRadius: '0.6rem', overflow: 'hidden' }}
|
|
221
228
|
/>
|
|
222
229
|
)}
|
|
223
230
|
<PreviousButton type="button" onClick={() => previousNode(selectedNode)}>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
|
+
import Picture from '../../Atoms/Picture/Picture';
|
|
2
3
|
|
|
3
4
|
export const Container = styled.div`
|
|
4
5
|
position: fixed;
|
|
@@ -47,6 +48,11 @@ export const LightboxContent = styled.div`
|
|
|
47
48
|
border-radius: 1rem;
|
|
48
49
|
`;
|
|
49
50
|
|
|
51
|
+
export const LightboxPicture = styled(Picture)`
|
|
52
|
+
overflow: hidden;
|
|
53
|
+
border-radius: 0.6rem;
|
|
54
|
+
`;
|
|
55
|
+
|
|
50
56
|
export const LightboxImage = styled.div`
|
|
51
57
|
position: relative;
|
|
52
58
|
display: flex;
|
|
@@ -47,7 +47,7 @@ body {
|
|
|
47
47
|
h1 {
|
|
48
48
|
text-transform: uppercase;
|
|
49
49
|
font-family: 'Anton', Impact, sans-serif;
|
|
50
|
-
margin:
|
|
50
|
+
margin-bottom: 1rem;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
h1:only-child,
|
|
@@ -68,7 +68,7 @@ button {
|
|
|
68
68
|
h2 {
|
|
69
69
|
text-transform: uppercase;
|
|
70
70
|
font-family: 'Anton', Impact, sans-serif;
|
|
71
|
-
margin-bottom:
|
|
71
|
+
margin-bottom: 1rem;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
h3, h4, h5 {
|