@comicrelief/component-library 8.55.3 → 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.
@@ -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(_Picture.default, {
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-4"
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-5"
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-6"
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-7"
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-8"
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-9"
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-10"
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
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.55.3",
4
+ "version": "8.55.4",
5
5
  "main": "dist/index.js",
6
6
  "license": "ISC",
7
7
  "jest": {
@@ -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
- <Picture
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;