@financial-times/x-teaser 21.0.0-beta.1 → 21.1.0
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/Props.d.ts +1 -0
- package/__tests__/image-service.test.js +12 -12
- package/dist/Teaser.cjs.js +22 -14
- package/dist/Teaser.es5.js +19 -14
- package/dist/Teaser.esm.js +22 -14
- package/package.json +2 -3
- package/readme.md +1 -2
- package/src/Byline.jsx +2 -2
- package/src/Headshot.jsx +1 -1
- package/src/Image.jsx +9 -3
- package/src/concerns/image-service.js +3 -8
package/Props.d.ts
CHANGED
|
@@ -2,63 +2,63 @@ import imageService from '../src/concerns/image-service'
|
|
|
2
2
|
|
|
3
3
|
describe('image-service', () => {
|
|
4
4
|
it('wraps an image in a v3 URL', () => {
|
|
5
|
-
expect(imageService('https://example.com/image.jpg', 100)).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&fit=scale-down&dpr=2&width=100');
|
|
5
|
+
expect(imageService('https://example.com/image.jpg', { width: 100 })).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&fit=scale-down&dpr=2&width=100');
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
it('allows setting the source param', () => {
|
|
9
|
-
expect(imageService('https://example.com/image.jpg', 100,
|
|
9
|
+
expect(imageService('https://example.com/image.jpg', { width: 100, source: 'system-code' })).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=system-code&fit=scale-down&dpr=2&width=100');
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
describe('double wrapping v2 URLs', () => {
|
|
13
13
|
it('does not double wrap an image service v2 URL', () => {
|
|
14
|
-
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=test&width=100', 100);
|
|
14
|
+
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=test&width=100', { width: 100 });
|
|
15
15
|
expect(result).toEqual('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&width=100&fit=scale-down&dpr=2');
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
it('preserves example-query-param=1234 from the original URL', () => {
|
|
19
|
-
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?example-query-param=1234', 100);
|
|
19
|
+
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?example-query-param=1234', { width: 100 });
|
|
20
20
|
expect(result).toEqual('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?example-query-param=1234&source=next&fit=scale-down&dpr=2&width=100');
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('overrides the "source" query param using default OPTIONS', () => {
|
|
24
|
-
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source', 100);
|
|
24
|
+
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source', { width: 100 });
|
|
25
25
|
expect(result).toEqual('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&fit=scale-down&dpr=2&width=100');
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it('overrides the "width" query param when passed in', () => {
|
|
29
|
-
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', 200);
|
|
29
|
+
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', { width: 200 });
|
|
30
30
|
expect(result).toEqual('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&width=200&fit=scale-down&dpr=2');
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('overrides the "source" query param when passed in', () => {
|
|
34
|
-
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', 200,
|
|
34
|
+
const result = imageService('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', { width: 200, source: 'latest-source' });
|
|
35
35
|
expect(result).toEqual('https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=latest-source&width=200&fit=scale-down&dpr=2');
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
describe('double wrapping v3 URLs', () => {
|
|
40
40
|
it('does not double wrap an image service v3 URL', () => {
|
|
41
|
-
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=test&width=100', 100);
|
|
41
|
+
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=test&width=100', { width: 100 });
|
|
42
42
|
expect(result).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&width=100&fit=scale-down&dpr=2');
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
it('preserves example-query-param=1234 from the original URL', () => {
|
|
46
|
-
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?example-query-param=1234', 100);
|
|
46
|
+
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?example-query-param=1234', { width: 100 });
|
|
47
47
|
expect(result).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?example-query-param=1234&source=next&fit=scale-down&dpr=2&width=100');
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
it('overrides the "source" query param using default OPTIONS', () => {
|
|
51
|
-
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source', 100);
|
|
51
|
+
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source', { width: 100 });
|
|
52
52
|
expect(result).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&fit=scale-down&dpr=2&width=100');
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
it('overrides the "width" query param when passed in', () => {
|
|
56
|
-
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', 200);
|
|
56
|
+
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', { width: 200 });
|
|
57
57
|
expect(result).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=next&width=200&fit=scale-down&dpr=2');
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
it('overrides the "source" query param when passed in', () => {
|
|
61
|
-
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', 200,
|
|
61
|
+
const result = imageService('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=original-source&width=100', { width: 200, source: 'latest-source' });
|
|
62
62
|
expect(result).toEqual('https://images.ft.com/v3/image/raw/https%3A%2F%2Fexample.com%2Fimage.jpg?source=latest-source&width=200&fit=scale-down&dpr=2');
|
|
63
63
|
});
|
|
64
64
|
});
|
package/dist/Teaser.cjs.js
CHANGED
|
@@ -173,10 +173,10 @@ const OPTIONS = {
|
|
|
173
173
|
/**
|
|
174
174
|
* Image Service
|
|
175
175
|
* @param {String} url
|
|
176
|
-
* @param {
|
|
177
|
-
|
|
176
|
+
* @param {Object} options
|
|
177
|
+
|
|
178
178
|
*/
|
|
179
|
-
function imageService(url,
|
|
179
|
+
function imageService(url, options) {
|
|
180
180
|
if (url.startsWith(BASE_URL_V2) || url.startsWith(BASE_URL_V3)) {
|
|
181
181
|
const parsedUrl = new URL(url);
|
|
182
182
|
parsedUrl.search = new URLSearchParams({
|
|
@@ -184,9 +184,6 @@ function imageService(url, width, options) {
|
|
|
184
184
|
...OPTIONS,
|
|
185
185
|
...options
|
|
186
186
|
});
|
|
187
|
-
if (width) {
|
|
188
|
-
parsedUrl.searchParams.set('width', width);
|
|
189
|
-
}
|
|
190
187
|
return parsedUrl.toString();
|
|
191
188
|
}
|
|
192
189
|
const imageSrc = new URL(`${BASE_URL_V3}/${encodeURIComponent(url)}`);
|
|
@@ -194,7 +191,6 @@ function imageService(url, width, options) {
|
|
|
194
191
|
...OPTIONS,
|
|
195
192
|
...options
|
|
196
193
|
});
|
|
197
|
-
imageSrc.searchParams.set('width', width);
|
|
198
194
|
return imageSrc.href;
|
|
199
195
|
}
|
|
200
196
|
|
|
@@ -239,9 +235,13 @@ const BylineLink = ({
|
|
|
239
235
|
onError: ({
|
|
240
236
|
currentTarget
|
|
241
237
|
}) => currentTarget === null || currentTarget === void 0 ? void 0 : currentTarget.remove(),
|
|
242
|
-
src: imageService(headshot,
|
|
238
|
+
src: imageService(headshot, {
|
|
239
|
+
width: ImageSizes.BylineHeadshot
|
|
240
|
+
}),
|
|
243
241
|
srcSet: `
|
|
244
|
-
${imageService(headshot,
|
|
242
|
+
${imageService(headshot, {
|
|
243
|
+
width: ImageSizes.BylineHeadshot * 2
|
|
244
|
+
})} 2x
|
|
245
245
|
`
|
|
246
246
|
}) : null, xEngine.h("span", {
|
|
247
247
|
className: "o-teaser__byline-link-label"
|
|
@@ -282,7 +282,10 @@ var Headshot = ({
|
|
|
282
282
|
height: ImageSizes.Headshot,
|
|
283
283
|
alt: "",
|
|
284
284
|
"aria-hidden": "true",
|
|
285
|
-
src: imageService(headshot,
|
|
285
|
+
src: imageService(headshot, {
|
|
286
|
+
...options,
|
|
287
|
+
width: ImageSizes.Headshot
|
|
288
|
+
})
|
|
286
289
|
}) : null;
|
|
287
290
|
};
|
|
288
291
|
|
|
@@ -329,6 +332,7 @@ var Image = ({
|
|
|
329
332
|
imageSize,
|
|
330
333
|
imageLazyLoad,
|
|
331
334
|
imageHighestQuality,
|
|
335
|
+
imageOptions,
|
|
332
336
|
...props
|
|
333
337
|
}) => {
|
|
334
338
|
if (!image || image && !image.url) {
|
|
@@ -336,10 +340,14 @@ var Image = ({
|
|
|
336
340
|
}
|
|
337
341
|
const displayUrl = relativeUrl || url;
|
|
338
342
|
const useImageService = !(image.url.startsWith('data:') || image.url.startsWith('blob:'));
|
|
339
|
-
const options =
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
+
const options = {
|
|
344
|
+
width: ImageSizes[imageSize],
|
|
345
|
+
...(imageSize === 'XXL' && imageHighestQuality && {
|
|
346
|
+
quality: 'highest'
|
|
347
|
+
}),
|
|
348
|
+
...(imageOptions ?? {})
|
|
349
|
+
};
|
|
350
|
+
const imageSrc = useImageService ? imageService(image.url, options) : image.url;
|
|
343
351
|
const alt = (image.altText || '').trim();
|
|
344
352
|
const ImageComponent = imageLazyLoad ? LazyImage : NormalImage;
|
|
345
353
|
return xEngine.h("div", {
|
package/dist/Teaser.es5.js
CHANGED
|
@@ -304,21 +304,17 @@ var OPTIONS = {
|
|
|
304
304
|
/**
|
|
305
305
|
* Image Service
|
|
306
306
|
* @param {String} url
|
|
307
|
-
* @param {
|
|
308
|
-
|
|
307
|
+
* @param {Object} options
|
|
308
|
+
|
|
309
309
|
*/
|
|
310
|
-
function imageService(url,
|
|
310
|
+
function imageService(url, options) {
|
|
311
311
|
if (url.startsWith(BASE_URL_V2) || url.startsWith(BASE_URL_V3)) {
|
|
312
312
|
var parsedUrl = new URL(url);
|
|
313
313
|
parsedUrl.search = new URLSearchParams(_objectSpread2(_objectSpread2(_objectSpread2({}, Object.fromEntries(parsedUrl.searchParams)), OPTIONS), options));
|
|
314
|
-
if (width) {
|
|
315
|
-
parsedUrl.searchParams.set('width', width);
|
|
316
|
-
}
|
|
317
314
|
return parsedUrl.toString();
|
|
318
315
|
}
|
|
319
316
|
var imageSrc = new URL("".concat(BASE_URL_V3, "/").concat(encodeURIComponent(url)));
|
|
320
317
|
imageSrc.search = new URLSearchParams(_objectSpread2(_objectSpread2({}, OPTIONS), options));
|
|
321
|
-
imageSrc.searchParams.set('width', width);
|
|
322
318
|
return imageSrc.href;
|
|
323
319
|
}
|
|
324
320
|
|
|
@@ -365,8 +361,12 @@ var BylineLink = function BylineLink(_ref) {
|
|
|
365
361
|
var currentTarget = _ref2.currentTarget;
|
|
366
362
|
return currentTarget === null || currentTarget === void 0 ? void 0 : currentTarget.remove();
|
|
367
363
|
},
|
|
368
|
-
src: imageService(headshot,
|
|
369
|
-
|
|
364
|
+
src: imageService(headshot, {
|
|
365
|
+
width: ImageSizes.BylineHeadshot
|
|
366
|
+
}),
|
|
367
|
+
srcSet: "\n\t\t\t\t\t".concat(imageService(headshot, {
|
|
368
|
+
width: ImageSizes.BylineHeadshot * 2
|
|
369
|
+
}), " 2x\n\t\t\t\t")
|
|
370
370
|
}) : null, xEngine.h("span", {
|
|
371
371
|
className: "o-teaser__byline-link-label"
|
|
372
372
|
}, text));
|
|
@@ -414,11 +414,13 @@ var Headshot = (function (_ref) {
|
|
|
414
414
|
height: ImageSizes.Headshot,
|
|
415
415
|
alt: "",
|
|
416
416
|
"aria-hidden": "true",
|
|
417
|
-
src: imageService(headshot,
|
|
417
|
+
src: imageService(headshot, _objectSpread2(_objectSpread2({}, options), {}, {
|
|
418
|
+
width: ImageSizes.Headshot
|
|
419
|
+
}))
|
|
418
420
|
}) : null;
|
|
419
421
|
});
|
|
420
422
|
|
|
421
|
-
var _excluded$1 = ["relativeUrl", "url", "image", "imageSize", "imageLazyLoad", "imageHighestQuality"];
|
|
423
|
+
var _excluded$1 = ["relativeUrl", "url", "image", "imageSize", "imageLazyLoad", "imageHighestQuality", "imageOptions"];
|
|
422
424
|
|
|
423
425
|
/**
|
|
424
426
|
* Aspect Ratio
|
|
@@ -462,16 +464,19 @@ var Image = (function (_ref4) {
|
|
|
462
464
|
imageSize = _ref4.imageSize,
|
|
463
465
|
imageLazyLoad = _ref4.imageLazyLoad,
|
|
464
466
|
imageHighestQuality = _ref4.imageHighestQuality,
|
|
467
|
+
imageOptions = _ref4.imageOptions,
|
|
465
468
|
props = _objectWithoutProperties(_ref4, _excluded$1);
|
|
466
469
|
if (!image || image && !image.url) {
|
|
467
470
|
return null;
|
|
468
471
|
}
|
|
469
472
|
var displayUrl = relativeUrl || url;
|
|
470
473
|
var useImageService = !(image.url.startsWith('data:') || image.url.startsWith('blob:'));
|
|
471
|
-
var options =
|
|
474
|
+
var options = _objectSpread2(_objectSpread2({
|
|
475
|
+
width: ImageSizes[imageSize]
|
|
476
|
+
}, imageSize === 'XXL' && imageHighestQuality && {
|
|
472
477
|
quality: 'highest'
|
|
473
|
-
} : {};
|
|
474
|
-
var imageSrc = useImageService ? imageService(image.url,
|
|
478
|
+
}), imageOptions !== null && imageOptions !== void 0 ? imageOptions : {});
|
|
479
|
+
var imageSrc = useImageService ? imageService(image.url, options) : image.url;
|
|
475
480
|
var alt = (image.altText || '').trim();
|
|
476
481
|
var ImageComponent = imageLazyLoad ? LazyImage : NormalImage;
|
|
477
482
|
return xEngine.h("div", {
|
package/dist/Teaser.esm.js
CHANGED
|
@@ -167,10 +167,10 @@ const OPTIONS = {
|
|
|
167
167
|
/**
|
|
168
168
|
* Image Service
|
|
169
169
|
* @param {String} url
|
|
170
|
-
* @param {
|
|
171
|
-
|
|
170
|
+
* @param {Object} options
|
|
171
|
+
|
|
172
172
|
*/
|
|
173
|
-
function imageService(url,
|
|
173
|
+
function imageService(url, options) {
|
|
174
174
|
if (url.startsWith(BASE_URL_V2) || url.startsWith(BASE_URL_V3)) {
|
|
175
175
|
const parsedUrl = new URL(url);
|
|
176
176
|
parsedUrl.search = new URLSearchParams({
|
|
@@ -178,9 +178,6 @@ function imageService(url, width, options) {
|
|
|
178
178
|
...OPTIONS,
|
|
179
179
|
...options
|
|
180
180
|
});
|
|
181
|
-
if (width) {
|
|
182
|
-
parsedUrl.searchParams.set('width', width);
|
|
183
|
-
}
|
|
184
181
|
return parsedUrl.toString();
|
|
185
182
|
}
|
|
186
183
|
const imageSrc = new URL(`${BASE_URL_V3}/${encodeURIComponent(url)}`);
|
|
@@ -188,7 +185,6 @@ function imageService(url, width, options) {
|
|
|
188
185
|
...OPTIONS,
|
|
189
186
|
...options
|
|
190
187
|
});
|
|
191
|
-
imageSrc.searchParams.set('width', width);
|
|
192
188
|
return imageSrc.href;
|
|
193
189
|
}
|
|
194
190
|
|
|
@@ -233,9 +229,13 @@ const BylineLink = ({
|
|
|
233
229
|
onError: ({
|
|
234
230
|
currentTarget
|
|
235
231
|
}) => currentTarget === null || currentTarget === void 0 ? void 0 : currentTarget.remove(),
|
|
236
|
-
src: imageService(headshot,
|
|
232
|
+
src: imageService(headshot, {
|
|
233
|
+
width: ImageSizes.BylineHeadshot
|
|
234
|
+
}),
|
|
237
235
|
srcSet: `
|
|
238
|
-
${imageService(headshot,
|
|
236
|
+
${imageService(headshot, {
|
|
237
|
+
width: ImageSizes.BylineHeadshot * 2
|
|
238
|
+
})} 2x
|
|
239
239
|
`
|
|
240
240
|
}) : null, h("span", {
|
|
241
241
|
className: "o-teaser__byline-link-label"
|
|
@@ -276,7 +276,10 @@ var Headshot = ({
|
|
|
276
276
|
height: ImageSizes.Headshot,
|
|
277
277
|
alt: "",
|
|
278
278
|
"aria-hidden": "true",
|
|
279
|
-
src: imageService(headshot,
|
|
279
|
+
src: imageService(headshot, {
|
|
280
|
+
...options,
|
|
281
|
+
width: ImageSizes.Headshot
|
|
282
|
+
})
|
|
280
283
|
}) : null;
|
|
281
284
|
};
|
|
282
285
|
|
|
@@ -323,6 +326,7 @@ var Image = ({
|
|
|
323
326
|
imageSize,
|
|
324
327
|
imageLazyLoad,
|
|
325
328
|
imageHighestQuality,
|
|
329
|
+
imageOptions,
|
|
326
330
|
...props
|
|
327
331
|
}) => {
|
|
328
332
|
if (!image || image && !image.url) {
|
|
@@ -330,10 +334,14 @@ var Image = ({
|
|
|
330
334
|
}
|
|
331
335
|
const displayUrl = relativeUrl || url;
|
|
332
336
|
const useImageService = !(image.url.startsWith('data:') || image.url.startsWith('blob:'));
|
|
333
|
-
const options =
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
+
const options = {
|
|
338
|
+
width: ImageSizes[imageSize],
|
|
339
|
+
...(imageSize === 'XXL' && imageHighestQuality && {
|
|
340
|
+
quality: 'highest'
|
|
341
|
+
}),
|
|
342
|
+
...(imageOptions ?? {})
|
|
343
|
+
};
|
|
344
|
+
const imageSrc = useImageService ? imageService(image.url, options) : image.url;
|
|
337
345
|
const alt = (image.altText || '').trim();
|
|
338
346
|
const ImageComponent = imageLazyLoad ? LazyImage : NormalImage;
|
|
339
347
|
return h("div", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/x-teaser",
|
|
3
|
-
"version": "21.
|
|
3
|
+
"version": "21.1.0",
|
|
4
4
|
"description": "This module provides templates for use with o-teaser. Teasers are used to present content.",
|
|
5
5
|
"source": "src/Teaser.jsx",
|
|
6
6
|
"main": "dist/Teaser.cjs.js",
|
|
@@ -27,8 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/Financial-Times/x-teaser/tree/HEAD/components/x-teaser",
|
|
29
29
|
"engines": {
|
|
30
|
-
"node": "
|
|
31
|
-
"npm": "7.x || 8.x || 9.x || 10.x"
|
|
30
|
+
"node": "22.x || 24.x"
|
|
32
31
|
},
|
|
33
32
|
"publishConfig": {
|
|
34
33
|
"access": "public"
|
package/readme.md
CHANGED
|
@@ -4,8 +4,6 @@ This module provides templates for use with [o-teaser](https://github.com/Financ
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
This module is supported on Node 12 and is distributed on npm.
|
|
8
|
-
|
|
9
7
|
```bash
|
|
10
8
|
npm install --save @financial-times/x-teaser @financial-times/o-teaser
|
|
11
9
|
```
|
|
@@ -182,6 +180,7 @@ As covered in the [features](#features) documentation the teaser properties, or
|
|
|
182
180
|
| `imageSize` | String | XS, Small, Medium, Large, XL or XXL |
|
|
183
181
|
| `imageLazyLoad` | Boolean, String | Output image with `data-src` attribute. If this is a string it will be appended to the image as a class name. |
|
|
184
182
|
| `imageHighestQuality` | Boolean | Calls image service with "quality=highest" option, works only with XXL images |
|
|
183
|
+
| `imageOptions` | Object | Calls Image Service with specified props, takes precedence over other image options such as `imageSize` and `imageHighestQuality` |
|
|
185
184
|
|
|
186
185
|
#### Byline Props
|
|
187
186
|
|
package/src/Byline.jsx
CHANGED
|
@@ -19,9 +19,9 @@ const BylineLink = ({ text, url, headshot, showBylineHeadshot }) => (
|
|
|
19
19
|
loading="lazy"
|
|
20
20
|
aria-hidden="true"
|
|
21
21
|
onError={({ currentTarget }) => currentTarget?.remove()}
|
|
22
|
-
src={imageService(headshot, ImageSizes.BylineHeadshot
|
|
22
|
+
src={imageService(headshot, { width: ImageSizes.BylineHeadshot })}
|
|
23
23
|
srcSet={`
|
|
24
|
-
${imageService(headshot, ImageSizes.BylineHeadshot * 2
|
|
24
|
+
${imageService(headshot, { width: ImageSizes.BylineHeadshot * 2 })} 2x
|
|
25
25
|
`}
|
|
26
26
|
/>
|
|
27
27
|
) : null}
|
package/src/Headshot.jsx
CHANGED
|
@@ -15,7 +15,7 @@ export default ({ headshot, headshotTint }) => {
|
|
|
15
15
|
height={ImageSizes.Headshot}
|
|
16
16
|
alt=""
|
|
17
17
|
aria-hidden="true"
|
|
18
|
-
src={imageService(headshot, ImageSizes.Headshot
|
|
18
|
+
src={imageService(headshot, { ...options, width: ImageSizes.Headshot })}
|
|
19
19
|
/>
|
|
20
20
|
) : null
|
|
21
21
|
}
|
package/src/Image.jsx
CHANGED
|
@@ -22,14 +22,20 @@ const LazyImage = ({ src, lazyLoad, alt }) => {
|
|
|
22
22
|
return <img className={`o-teaser__image ${lazyClassName}`} data-src={src} alt={alt} />
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export default ({ relativeUrl, url, image, imageSize, imageLazyLoad, imageHighestQuality, ...props }) => {
|
|
25
|
+
export default ({ relativeUrl, url, image, imageSize, imageLazyLoad, imageHighestQuality, imageOptions, ...props }) => {
|
|
26
26
|
if (!image || (image && !image.url)) {
|
|
27
27
|
return null
|
|
28
28
|
}
|
|
29
29
|
const displayUrl = relativeUrl || url
|
|
30
30
|
const useImageService = !(image.url.startsWith('data:') || image.url.startsWith('blob:'))
|
|
31
|
-
|
|
32
|
-
const
|
|
31
|
+
|
|
32
|
+
const options = {
|
|
33
|
+
width: ImageSizes[imageSize],
|
|
34
|
+
...(imageSize === 'XXL' && imageHighestQuality && { quality: 'highest' }),
|
|
35
|
+
...(imageOptions ?? {})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const imageSrc = useImageService ? imageService(image.url, options) : image.url
|
|
33
39
|
const alt = (image.altText || '').trim()
|
|
34
40
|
const ImageComponent = imageLazyLoad ? LazyImage : NormalImage
|
|
35
41
|
|
|
@@ -5,10 +5,10 @@ const OPTIONS = { source: 'next', fit: 'scale-down', dpr: 2 }
|
|
|
5
5
|
/**
|
|
6
6
|
* Image Service
|
|
7
7
|
* @param {String} url
|
|
8
|
-
* @param {
|
|
9
|
-
|
|
8
|
+
* @param {Object} options
|
|
9
|
+
|
|
10
10
|
*/
|
|
11
|
-
export default function imageService(url,
|
|
11
|
+
export default function imageService(url, options) {
|
|
12
12
|
if (url.startsWith(BASE_URL_V2) || url.startsWith(BASE_URL_V3)) {
|
|
13
13
|
const parsedUrl = new URL(url);
|
|
14
14
|
|
|
@@ -18,15 +18,10 @@ export default function imageService(url, width, options) {
|
|
|
18
18
|
...options,
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
-
if (width) {
|
|
22
|
-
parsedUrl.searchParams.set('width', width);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
21
|
return parsedUrl.toString();
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
const imageSrc = new URL(`${BASE_URL_V3}/${encodeURIComponent(url)}`)
|
|
29
25
|
imageSrc.search = new URLSearchParams({ ...OPTIONS, ...options })
|
|
30
|
-
imageSrc.searchParams.set('width', width)
|
|
31
26
|
return imageSrc.href
|
|
32
27
|
}
|