@financial-times/cp-content-pipeline-ui 9.10.0 → 9.12.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/CHANGELOG.md CHANGED
@@ -574,6 +574,41 @@
574
574
  * @financial-times/cp-content-pipeline-client bumped from ^3.7.2 to ^3.7.3
575
575
  * @financial-times/cp-content-pipeline-schema bumped from ^2.10.1 to ^2.10.2
576
576
 
577
+ ## [9.12.0](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v9.11.0...cp-content-pipeline-ui-v9.12.0) (2025-11-21)
578
+
579
+
580
+ ### Features
581
+
582
+ * anchor links in clips ([f753082](https://github.com/Financial-Times/cp-content-pipeline/commit/f753082b61b1e5aa989cd1db901546eeee71fe83))
583
+
584
+
585
+ ### Bug Fixes
586
+
587
+ * avoid fetching teaser data from RecommendedList resolver ([54bc53f](https://github.com/Financial-Times/cp-content-pipeline/commit/54bc53f9a40446667a9f93b85d710cd6a943157d))
588
+
589
+
590
+ ### Dependencies
591
+
592
+ * The following workspace dependencies were updated
593
+ * devDependencies
594
+ * @financial-times/cp-content-pipeline-client bumped from ^4.20.0 to ^4.20.1
595
+ * @financial-times/cp-content-pipeline-schema bumped from ^3.19.0 to ^3.20.0
596
+
597
+ ## [9.11.0](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v9.10.0...cp-content-pipeline-ui-v9.11.0) (2025-11-11)
598
+
599
+
600
+ ### Features
601
+
602
+ * ci-3111 media queries on clips sources ([856bd45](https://github.com/Financial-Times/cp-content-pipeline/commit/856bd457ba6dc56f292c6a31e0edfe3f29b4a904))
603
+
604
+
605
+ ### Dependencies
606
+
607
+ * The following workspace dependencies were updated
608
+ * devDependencies
609
+ * @financial-times/cp-content-pipeline-client bumped from ^4.19.0 to ^4.20.0
610
+ * @financial-times/cp-content-pipeline-schema bumped from ^3.18.0 to ^3.19.0
611
+
577
612
  ## [9.10.0](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v9.9.0...cp-content-pipeline-ui-v9.10.0) (2025-11-06)
578
613
 
579
614
 
@@ -13,6 +13,7 @@ interface ClipTagProps {
13
13
  noDescription?: boolean;
14
14
  noInfoBox?: boolean;
15
15
  noCaption?: boolean;
16
+ maxClipWidth?: number;
16
17
  noClosedCaption?: boolean;
17
18
  accessibility?: ComponentWorkarounds.ClipAccessibility;
18
19
  muted?: boolean;
@@ -20,6 +21,7 @@ interface ClipTagProps {
20
21
  caption?: string;
21
22
  preload?: string;
22
23
  systemTitle?: string;
24
+ fragmentIdentifier?: string;
23
25
  }
24
26
  export declare const ClipTag: React.FC<ClipTagProps>;
25
27
  export {};
@@ -7,16 +7,45 @@ exports.ClipTag = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const index_1 = require("./index");
9
9
  const FixedAspectRatio_1 = require("../../../FixedAspectRatio/FixedAspectRatio");
10
- const ClipTag = ({ id, dataLayout, description, poster, autoplay, noAudio, loop, muted, clip, credits, caption, accessibility, preload, noDescription = false, noInfoBox = false, noCaption = false, dataTrackable, systemTitle, }) => {
10
+ const ClipTag = ({ id, dataLayout, description, poster, autoplay, noAudio, loop, muted, clip, credits, caption, accessibility, preload, noDescription = false, noInfoBox = false, noCaption = false, maxClipWidth = 0, dataTrackable, systemTitle, fragmentIdentifier, }) => {
11
11
  const { pixelWidth, pixelHeight } = clip?.dataSource?.[0]
12
12
  ? clip.dataSource[0]
13
13
  : { pixelWidth: 0, pixelHeight: 0 };
14
- return (react_1.default.createElement("div", { "data-cp-clip-layout": dataLayout, "data-cp-clip-poster": poster, "data-cp-clip-autoplay": autoplay, "data-cp-clip-no-audio": noAudio, "data-cp-clip-no-description": noDescription, "data-cp-clip-caption": caption, "data-cp-clip-no-info-box": noInfoBox, "data-cp-clip-no-caption": noCaption, "data-cp-clip-closed-caption": Boolean(accessibility?.captions?.[0]?.url), "data-cp-clip-loop": loop, className: "cp-clip", "data-trackable": dataTrackable, "data-o-component": "cp-clip", "data-cp-clip-id": id, "data-cp-clip-system-title": systemTitle },
14
+ const mediaQuery = ({ dppx, previousSourceWidth, }) => {
15
+ const mqOptions = [];
16
+ if (dppx && dppx > 1) {
17
+ mqOptions.push(`(min-resolution: ${dppx}dppx)`);
18
+ }
19
+ if (previousSourceWidth) {
20
+ mqOptions.push(`(min-width: ${previousSourceWidth}px)`);
21
+ }
22
+ if (mqOptions.length > 0) {
23
+ return mqOptions.join(' and ');
24
+ }
25
+ };
26
+ // get the index of the last source that is a video
27
+ const getLastVideoIndex = () => {
28
+ for (let i = clip?.dataSource.length - 1; i >= 0; i--) {
29
+ if (clip?.dataSource[i]?.mediaType.startsWith('video/')) {
30
+ return i;
31
+ }
32
+ }
33
+ return 0;
34
+ };
35
+ const lastVideoIndex = getLastVideoIndex();
36
+ return (react_1.default.createElement("div", { "data-cp-clip-layout": dataLayout, "data-cp-clip-poster": poster, "data-cp-clip-autoplay": autoplay, "data-cp-clip-no-audio": noAudio, "data-cp-clip-no-description": noDescription, "data-cp-clip-caption": caption, "data-cp-clip-no-info-box": noInfoBox, "data-cp-clip-no-caption": noCaption, "data-cp-clip-closed-caption": Boolean(accessibility?.captions?.[0]?.url), "data-cp-clip-loop": loop, className: "cp-clip", "data-trackable": dataTrackable, "data-o-component": "cp-clip", "data-cp-clip-id": id, "data-cp-clip-system-title": systemTitle, id: fragmentIdentifier },
15
37
  !noInfoBox && react_1.default.createElement(index_1.VideoInfoBox, null),
16
38
  react_1.default.createElement("div", { className: "cp-clip__video-container" },
17
39
  react_1.default.createElement(FixedAspectRatio_1.FixedAspectRatio, { width: pixelWidth, height: pixelHeight, element: "video", className: "cp-clip__video", controls: true, controlsList: "nodownload noremoteplayback noplaybackrate", disablePictureInPicture: true, disableRemotePlayback: true, playsInline: true, muted: muted, loop: loop, poster: poster, preload: preload, id: `clip-${id}`, crossOrigin: "anonymous" },
18
- clip?.dataSource?.map(({ binaryUrl, mediaType }, index) => {
19
- return (react_1.default.createElement("source", { id: `video-source-${index}-${id}`, "data-cp-component": "cp-clip__video-source", src: binaryUrl, type: mediaType !== '' ? mediaType : undefined, key: binaryUrl }));
40
+ clip?.dataSource?.map(({ binaryUrl, mediaType, dppx, previousSourceWidth }, index) => {
41
+ // allow user to set a max width for clip sources to avoid loading very large videos on places like the homepage
42
+ if (maxClipWidth &&
43
+ previousSourceWidth &&
44
+ previousSourceWidth > maxClipWidth &&
45
+ index < lastVideoIndex) {
46
+ return null;
47
+ }
48
+ return (react_1.default.createElement("source", { id: `video-source-${index}-${id}`, "data-cp-component": "cp-clip__video-source", src: binaryUrl, type: mediaType !== '' ? mediaType : undefined, key: binaryUrl, media: mediaQuery({ dppx, previousSourceWidth }) }));
20
49
  }),
21
50
  react_1.default.createElement(index_1.ClosedCaptions, { accessibility: accessibility }))),
22
51
  (!noDescription || !noCaption) && (react_1.default.createElement("div", { className: "cp-clip__video-meta-info", "data-cp-clip-video-meta-info": true },
@@ -1 +1 @@
1
- {"version":3,"file":"ClipTag.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/Clip/components/ClipTag.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,mCAKgB;AAChB,iFAA6E;AAyBtE,MAAM,OAAO,GAA2B,CAAC,EAC9C,EAAE,EACF,UAAU,EACV,WAAW,EACX,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,aAAa,EACb,OAAO,EACP,aAAa,GAAG,KAAK,EACrB,SAAS,GAAG,KAAK,EACjB,SAAS,GAAG,KAAK,EACjB,aAAa,EACb,WAAW,GACZ,EAAE,EAAE;IACH,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAA;IAErC,OAAO,CACL,8DACuB,UAAU,yBACV,MAAM,2BACJ,QAAQ,2BACR,OAAO,iCACD,aAAa,0BACpB,OAAO,8BACH,SAAS,6BACV,SAAS,iCACL,OAAO,CAAC,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,uBACpD,IAAI,EACvB,SAAS,EAAC,SAAS,oBACH,aAAa,sBACZ,SAAS,qBACT,EAAE,+BACQ,WAAW;QAErC,CAAC,SAAS,IAAI,8BAAC,oBAAY,OAAG;QAC/B,uCAAK,SAAS,EAAC,0BAA0B;YAEvC,8BAAC,mCAAgB,IACf,KAAK,EAAE,UAAoB,EAC3B,MAAM,EAAE,WAAqB,EAC7B,OAAO,EAAC,OAAO,EACf,SAAS,EAAC,gBAAgB,EAC1B,QAAQ,QACR,YAAY,EAAC,4CAA4C,EACzD,uBAAuB,QACvB,qBAAqB,QACrB,WAAW,QACX,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,QAAQ,EAAE,EAAE,EAChB,WAAW,EAAC,WAAW;gBAEtB,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE;oBACzD,OAAO,CACL,0CACE,EAAE,EAAE,gBAAgB,KAAK,IAAI,EAAE,EAAE,uBACf,uBAAuB,EACzC,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAC9C,GAAG,EAAE,SAAS,GACN,CACX,CAAA;gBACH,CAAC,CAAC;gBACF,8BAAC,sBAAc,IAAC,aAAa,EAAE,aAAa,GAAI,CAC/B,CACf;QACL,CAAC,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,IAAI,CACjC,uCAAK,SAAS,EAAC,0BAA0B;YACtC,CAAC,aAAa,IAAI,CACjB,8BAAC,wBAAgB,IACf,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,GAC5B,CACH;YACA,CAAC,SAAS,IAAI,8BAAC,eAAO,IAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAI,CAC1D,CACP,CACG,CACP,CAAA;AACH,CAAC,CAAA;AAzFY,QAAA,OAAO,WAyFnB"}
1
+ {"version":3,"file":"ClipTag.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/Clip/components/ClipTag.tsx"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ type Preset = 'full-player' | 'thumbnail';
5
5
  export interface ClipProps extends ContentProps<ComponentWorkarounds.ClipSet> {
6
6
  preload?: string;
7
7
  preset?: Preset;
8
+ maxClipWidth?: number;
8
9
  }
9
10
  export interface ClipPropsOld {
10
11
  url?: string;
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
7
  const components_1 = require("../components");
8
- const ClipComponent = ({ content, preset = 'full-player', preload = 'auto', }) => {
8
+ const ClipComponent = ({ content, preset = 'full-player', preload = 'auto', maxClipWidth = 0, }) => {
9
9
  let poster = 'poster' in content ? content.poster : '';
10
10
  let id;
11
11
  // We support currently a single clip, with multiple sources.
@@ -36,11 +36,11 @@ const ClipComponent = ({ content, preset = 'full-player', preload = 'auto', }) =
36
36
  const accessibility = content.accessibility ?? {};
37
37
  const systemTitle = content.systemTitle ?? '';
38
38
  if (preset === 'thumbnail') {
39
- return (react_1.default.createElement(components_1.ClipTag, { id: id, clip: clip, poster: poster, accessibility: accessibility, autoplay: content.autoplay, loop: content.loop, noAudio: noAudio, muted: content.muted, preload: preload, noCaption: true, noDescription: true, noInfoBox: true, systemTitle: systemTitle }));
39
+ return (react_1.default.createElement(components_1.ClipTag, { id: id, clip: clip, poster: poster, accessibility: accessibility, autoplay: content.autoplay, loop: content.loop, noAudio: noAudio, muted: content.muted, preload: preload, noCaption: true, noDescription: true, noInfoBox: true, systemTitle: systemTitle, maxClipWidth: maxClipWidth }));
40
40
  }
41
41
  return (react_1.default.createElement(components_1.ContentLayout, { dataLayout: content.dataLayout },
42
42
  react_1.default.createElement(components_1.Container, { dataLayout: content.dataLayout },
43
- react_1.default.createElement(components_1.ClipTag, { id: id, dataLayout: content.dataLayout, description: content.description ?? '', poster: posterAttribute, autoplay: content.autoplay, noAudio: noAudio, loop: content.loop, muted: content.muted, clip: clip, credits: content.credits ?? '', caption: content.caption ?? '', systemTitle: systemTitle, accessibility: accessibility, preload: preload, dataTrackable: "next-article-cp-clip" }))));
43
+ react_1.default.createElement(components_1.ClipTag, { id: id, dataLayout: content.dataLayout, description: content.description ?? '', poster: posterAttribute, autoplay: content.autoplay, noAudio: noAudio, loop: content.loop, muted: content.muted, clip: clip, credits: content.credits ?? '', caption: content.caption ?? '', systemTitle: systemTitle, accessibility: accessibility, preload: preload, dataTrackable: "next-article-cp-clip", maxClipWidth: maxClipWidth, fragmentIdentifier: content.fragmentIdentifier ?? '' }))));
44
44
  };
45
45
  exports.default = ClipComponent;
46
46
  //# sourceMappingURL=component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/Clip/template/component.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/Clip/template/component.tsx"],"names":[],"mappings":"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"}
@@ -6,18 +6,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
7
  //HACK: worked around missing Teaser type by declaring a module x-teaser.d.ts
8
8
  const x_teaser_1 = require("@financial-times/x-teaser");
9
- const RecommendedList = ({ content: { heading, teasers }, }) => {
10
- if (!teasers || teasers.length === 0) {
9
+ const RecommendedList = ({ content }) => {
10
+ const { heading, children } = content;
11
+ if (!children || children.length === 0) {
11
12
  return null;
12
13
  }
13
14
  return (react_1.default.createElement("aside", { "aria-labelledby": "aside-label", className: "n-content-recommended-list", "data-component": "recommended-list" },
14
15
  react_1.default.createElement("p", { className: "n-content-recommended-list__title o3-type-title-lg" }, heading),
15
- react_1.default.createElement("div", { className: "n-content-recommended-list__teasers" }, teasers.map((teaser, index) => (react_1.default.createElement(x_teaser_1.Teaser, { key: teaser?.id || index, modifiers: ['stacked'], ...x_teaser_1.presets.SmallHeavy, ...teaser, metaPrefixText: 'By', metaLink: {
16
- prefLabel: teaser?.clientName,
16
+ react_1.default.createElement("div", { className: "n-content-recommended-list__teasers" }, children.map((child, index) => (react_1.default.createElement(x_teaser_1.Teaser, { key: child?.id || index, modifiers: ['stacked'], ...x_teaser_1.presets.SmallHeavy, ...child.teaser, metaPrefixText: 'By', metaLink: {
17
+ prefLabel: child.teaser?.clientName,
17
18
  // clientName is a free form text field. Currently, there is no way to map it to an organisation
18
19
  // from the annotations. For now, we're linking it to the article url.
19
20
  // A property like isSponsoredBy could be added in future to support this properly.
20
- url: teaser?.url,
21
+ url: child.teaser?.url,
21
22
  } }))))));
22
23
  };
23
24
  exports.default = RecommendedList;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/content-tree/RecommendedList/index.tsx"],"names":[],"mappings":";;;;;AAAA,kDAAyB;AAEzB,6EAA6E;AAC7E,wDAA2D;AAW3D,MAAM,eAAe,GAAmC,CAAC,EACvD,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAC9B,EAAE,EAAE;IACH,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,CACL,4DACkB,aAAa,EAC7B,SAAS,EAAC,4BAA4B,oBACvB,kBAAkB;QAEjC,qCAAG,SAAS,EAAC,oDAAoD,IAC9D,OAAO,CACN;QACJ,uCAAK,SAAS,EAAC,qCAAqC,IACjD,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9B,8BAAC,iBAAM,IACL,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,KAAK,EACxB,SAAS,EAAE,CAAC,SAAS,CAAC,KAClB,kBAAO,CAAC,UAAU,KAClB,MAAM,EACV,cAAc,EAAE,IAAI,EACpB,QAAQ,EAAE;gBACR,SAAS,EAAE,MAAM,EAAE,UAAU;gBAC7B,gGAAgG;gBAChG,sEAAsE;gBACtE,mFAAmF;gBACnF,GAAG,EAAE,MAAM,EAAE,GAAG;aACjB,GACD,CACH,CAAC,CACE,CACA,CACT,CAAA;AACH,CAAC,CAAA;AAED,kBAAe,eAAe,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/content-tree/RecommendedList/index.tsx"],"names":[],"mappings":";;;;;AAAA,kDAAyB;AAEzB,6EAA6E;AAC7E,wDAA2D;AAW3D,MAAM,eAAe,GAAmC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;IACtE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IACrC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,CACL,4DACkB,aAAa,EAC7B,SAAS,EAAC,4BAA4B,oBACvB,kBAAkB;QAEjC,qCAAG,SAAS,EAAC,oDAAoD,IAC9D,OAAO,CACN;QACJ,uCAAK,SAAS,EAAC,qCAAqC,IACjD,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9B,8BAAC,iBAAM,IACL,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,KAAK,EACvB,SAAS,EAAE,CAAC,SAAS,CAAC,KAClB,kBAAO,CAAC,UAAU,KAClB,KAAK,CAAC,MAAM,EAChB,cAAc,EAAE,IAAI,EACpB,QAAQ,EAAE;gBACR,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU;gBACnC,gGAAgG;gBAChG,sEAAsE;gBACtE,mFAAmF;gBACnF,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,GAAG;aACvB,GACD,CACH,CAAC,CACE,CACA,CACT,CAAA;AACH,CAAC,CAAA;AAED,kBAAe,eAAe,CAAA"}
@@ -50,6 +50,9 @@ interface ClipSource {
50
50
  pixelHeight?: number;
51
51
  pixelWidth?: number;
52
52
  videoCodec?: string;
53
+ quality?: string;
54
+ dppx?: number;
55
+ previousSourceWidth?: number;
53
56
  }
54
57
  export type Clip = PartialToMaybeDeep<ReadonlyArrays<{
55
58
  format?: ClipFormat;
@@ -80,6 +83,7 @@ interface ClipSetReferences {
80
83
  subtitle?: string;
81
84
  publishedDate?: string;
82
85
  clips?: Clip[];
86
+ fragmentIdentifier?: string | undefined;
83
87
  }
84
88
  export type ClipSet = PartialToMaybeDeep<ReadonlyArrays<(ContentTreeWorkarounds.OldClip | ContentTreeWorkarounds.ClipSet) & ClipSetReferences>>;
85
89
  export type RawImage = ContentTreeWorkarounds.RawImage & {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/cp-content-pipeline-ui",
3
- "version": "9.10.0",
3
+ "version": "9.12.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -16,8 +16,8 @@
16
16
  "@babel/preset-env": "^7.22.5",
17
17
  "@babel/preset-react": "^7.22.5",
18
18
  "@financial-times/content-tree": "github:financial-times/content-tree#3f77ec4",
19
- "@financial-times/cp-content-pipeline-client": "^4.19.0",
20
- "@financial-times/cp-content-pipeline-schema": "^3.18.0",
19
+ "@financial-times/cp-content-pipeline-client": "^4.20.1",
20
+ "@financial-times/cp-content-pipeline-schema": "^3.20.0",
21
21
  "@financial-times/cp-content-pipeline-styles": "^4.5.0",
22
22
  "@financial-times/n-scrollytelling-image": "^1.1.0",
23
23
  "@financial-times/o-grid": "^6.1.8",
@@ -21,6 +21,7 @@ interface ClipTagProps {
21
21
  noDescription?: boolean
22
22
  noInfoBox?: boolean
23
23
  noCaption?: boolean
24
+ maxClipWidth?: number
24
25
  noClosedCaption?: boolean
25
26
  accessibility?: ComponentWorkarounds.ClipAccessibility
26
27
  muted?: boolean
@@ -28,6 +29,7 @@ interface ClipTagProps {
28
29
  caption?: string
29
30
  preload?: string
30
31
  systemTitle?: string
32
+ fragmentIdentifier?: string //a unique identifier used to locate the component inside a page for features like scrolling to it
31
33
  }
32
34
 
33
35
  export const ClipTag: React.FC<ClipTagProps> = ({
@@ -47,13 +49,46 @@ export const ClipTag: React.FC<ClipTagProps> = ({
47
49
  noDescription = false,
48
50
  noInfoBox = false,
49
51
  noCaption = false,
52
+ maxClipWidth = 0,
50
53
  dataTrackable,
51
54
  systemTitle,
55
+ fragmentIdentifier,
52
56
  }) => {
53
57
  const { pixelWidth, pixelHeight } = clip?.dataSource?.[0]
54
58
  ? clip.dataSource[0]
55
59
  : { pixelWidth: 0, pixelHeight: 0 }
56
60
 
61
+ const mediaQuery = ({
62
+ dppx,
63
+ previousSourceWidth,
64
+ }: {
65
+ dppx: number | null | undefined
66
+ previousSourceWidth: number | null | undefined
67
+ }) => {
68
+ const mqOptions = []
69
+ if (dppx && dppx > 1) {
70
+ mqOptions.push(`(min-resolution: ${dppx}dppx)`)
71
+ }
72
+ if (previousSourceWidth) {
73
+ mqOptions.push(`(min-width: ${previousSourceWidth}px)`)
74
+ }
75
+ if (mqOptions.length > 0) {
76
+ return mqOptions.join(' and ')
77
+ }
78
+ }
79
+
80
+ // get the index of the last source that is a video
81
+ const getLastVideoIndex = (): number => {
82
+ for (let i = clip?.dataSource.length - 1; i >= 0; i--) {
83
+ if (clip?.dataSource[i]?.mediaType.startsWith('video/')) {
84
+ return i
85
+ }
86
+ }
87
+ return 0
88
+ }
89
+
90
+ const lastVideoIndex: number = getLastVideoIndex()
91
+
57
92
  return (
58
93
  <div
59
94
  data-cp-clip-layout={dataLayout}
@@ -71,6 +106,7 @@ export const ClipTag: React.FC<ClipTagProps> = ({
71
106
  data-o-component="cp-clip"
72
107
  data-cp-clip-id={id}
73
108
  data-cp-clip-system-title={systemTitle}
109
+ id={fragmentIdentifier}
74
110
  >
75
111
  {!noInfoBox && <VideoInfoBox />}
76
112
  <div className="cp-clip__video-container">
@@ -92,17 +128,31 @@ export const ClipTag: React.FC<ClipTagProps> = ({
92
128
  id={`clip-${id}`}
93
129
  crossOrigin="anonymous"
94
130
  >
95
- {clip?.dataSource?.map(({ binaryUrl, mediaType }, index) => {
96
- return (
97
- <source
98
- id={`video-source-${index}-${id}`}
99
- data-cp-component="cp-clip__video-source"
100
- src={binaryUrl}
101
- type={mediaType !== '' ? mediaType : undefined}
102
- key={binaryUrl}
103
- ></source>
104
- )
105
- })}
131
+ {clip?.dataSource?.map(
132
+ ({ binaryUrl, mediaType, dppx, previousSourceWidth }, index) => {
133
+ // allow user to set a max width for clip sources to avoid loading very large videos on places like the homepage
134
+ if (
135
+ maxClipWidth &&
136
+ previousSourceWidth &&
137
+ previousSourceWidth > maxClipWidth &&
138
+ index < lastVideoIndex
139
+ ) {
140
+ return null
141
+ }
142
+
143
+ return (
144
+ <source
145
+ id={`video-source-${index}-${id}`}
146
+ data-cp-component="cp-clip__video-source"
147
+ src={binaryUrl}
148
+ type={mediaType !== '' ? mediaType : undefined}
149
+ key={binaryUrl}
150
+ media={mediaQuery({ dppx, previousSourceWidth })}
151
+ ></source>
152
+ )
153
+ }
154
+ )}
155
+
106
156
  <ClosedCaptions accessibility={accessibility} />
107
157
  </FixedAspectRatio>
108
158
  </div>
@@ -8,6 +8,7 @@ type Preset = 'full-player' | 'thumbnail'
8
8
  export interface ClipProps extends ContentProps<ComponentWorkarounds.ClipSet> {
9
9
  preload?: string
10
10
  preset?: Preset
11
+ maxClipWidth?: number
11
12
  }
12
13
 
13
14
  export interface ClipPropsOld {
@@ -34,6 +35,7 @@ const ClipComponent: React.FC<ClipProps> = ({
34
35
  content,
35
36
  preset = 'full-player',
36
37
  preload = 'auto',
38
+ maxClipWidth = 0,
37
39
  }) => {
38
40
  let poster = 'poster' in content ? content.poster : ''
39
41
  let id: string
@@ -82,6 +84,7 @@ const ClipComponent: React.FC<ClipProps> = ({
82
84
  noDescription
83
85
  noInfoBox
84
86
  systemTitle={systemTitle}
87
+ maxClipWidth={maxClipWidth}
85
88
  />
86
89
  )
87
90
  }
@@ -105,6 +108,8 @@ const ClipComponent: React.FC<ClipProps> = ({
105
108
  accessibility={accessibility}
106
109
  preload={preload}
107
110
  dataTrackable="next-article-cp-clip"
111
+ maxClipWidth={maxClipWidth}
112
+ fragmentIdentifier={content.fragmentIdentifier ?? ''}
108
113
  />
109
114
  </Container>
110
115
  </ContentLayout>
@@ -17,6 +17,7 @@ exports[`Clip Snapshot component rendered on server full-grid default render 1`]
17
17
  data-o-component="cp-clip"
18
18
  data-cp-clip-id="localhost:8080/fakevideo.mpg"
19
19
  data-cp-clip-system-title=""
20
+ id=""
20
21
  >
21
22
  <div
22
23
  data-o-component="o-expander"
@@ -87,6 +88,7 @@ exports[`Clip Snapshot component rendered on server full-grid render with attrib
87
88
  data-o-component="cp-clip"
88
89
  data-cp-clip-id="localhost:8080/fakevideo.mpg"
89
90
  data-cp-clip-system-title=""
91
+ id=""
90
92
  >
91
93
  <div
92
94
  data-o-component="o-expander"
@@ -188,6 +190,7 @@ exports[`Clip Snapshot component rendered on server in-line render 1`] = `
188
190
  data-o-component="cp-clip"
189
191
  data-cp-clip-id="localhost:8080/fakevideo.mpg"
190
192
  data-cp-clip-system-title=""
193
+ id=""
191
194
  >
192
195
  <div
193
196
  data-o-component="o-expander"
@@ -256,6 +259,7 @@ exports[`Clip Snapshot component rendered on server in-line render with attribut
256
259
  data-o-component="cp-clip"
257
260
  data-cp-clip-id="localhost:8080/fakevideo.mpg"
258
261
  data-cp-clip-system-title=""
262
+ id=""
259
263
  >
260
264
  <div
261
265
  data-o-component="o-expander"
@@ -361,6 +365,7 @@ exports[`Clip Snapshot component rendered on server mid-grid default render 1`]
361
365
  data-o-component="cp-clip"
362
366
  data-cp-clip-id="localhost:8080/fakevideo.mpg"
363
367
  data-cp-clip-system-title=""
368
+ id=""
364
369
  >
365
370
  <div
366
371
  data-o-component="o-expander"
@@ -436,6 +441,7 @@ exports[`Clip Snapshot component rendered on server mid-grid render with attribu
436
441
  data-o-component="cp-clip"
437
442
  data-cp-clip-id="localhost:8080/fakevideo.mpg"
438
443
  data-cp-clip-system-title=""
444
+ id=""
439
445
  >
440
446
  <div
441
447
  data-o-component="o-expander"
@@ -544,6 +550,7 @@ exports[`Clip Snapshot component rendered on server renders multiple video sourc
544
550
  data-o-component="cp-clip"
545
551
  data-cp-clip-id="84d7e1b0-e8b2-4ffc-a798-306f29dc9d52"
546
552
  data-cp-clip-system-title=""
553
+ id=""
547
554
  >
548
555
  <div
549
556
  data-o-component="o-expander"
@@ -655,6 +662,7 @@ exports[`Clip Snapshot component rendered on server supports new Origami images,
655
662
  data-o-component="cp-clip"
656
663
  data-cp-clip-id="localhost:8080/fakevideo.mpg"
657
664
  data-cp-clip-system-title=""
665
+ id=""
658
666
  >
659
667
  <div
660
668
  data-o-component="o-expander"
@@ -5,17 +5,16 @@ import { presets, Teaser } from '@financial-times/x-teaser'
5
5
  import { ContentProps } from '../../types'
6
6
  import type * as ComponentWorkarounds from '../Workarounds'
7
7
 
8
- // Renders a Recommended teaser component
8
+ // Renders a Recommended teaser componentx
9
9
  // `<Teaser>` is imported from x-dash
10
10
  // https://github.com/Financial-Times/x-dash/tree/main/components/x-teaser)
11
11
 
12
12
  interface RecommendedListProps
13
13
  extends ContentProps<ComponentWorkarounds.RecommendedList> {}
14
14
 
15
- const RecommendedList: React.FC<RecommendedListProps> = ({
16
- content: { heading, teasers },
17
- }) => {
18
- if (!teasers || teasers.length === 0) {
15
+ const RecommendedList: React.FC<RecommendedListProps> = ({ content }) => {
16
+ const { heading, children } = content
17
+ if (!children || children.length === 0) {
19
18
  return null
20
19
  }
21
20
 
@@ -29,19 +28,19 @@ const RecommendedList: React.FC<RecommendedListProps> = ({
29
28
  {heading}
30
29
  </p>
31
30
  <div className="n-content-recommended-list__teasers">
32
- {teasers.map((teaser, index) => (
31
+ {children.map((child, index) => (
33
32
  <Teaser
34
- key={teaser?.id || index}
33
+ key={child?.id || index}
35
34
  modifiers={['stacked']}
36
35
  {...presets.SmallHeavy}
37
- {...teaser}
36
+ {...child.teaser}
38
37
  metaPrefixText={'By'}
39
38
  metaLink={{
40
- prefLabel: teaser?.clientName,
39
+ prefLabel: child.teaser?.clientName,
41
40
  // clientName is a free form text field. Currently, there is no way to map it to an organisation
42
41
  // from the annotations. For now, we're linking it to the article url.
43
42
  // A property like isSponsoredBy could be added in future to support this properly.
44
- url: teaser?.url,
43
+ url: child.teaser?.url,
45
44
  }}
46
45
  />
47
46
  ))}
@@ -87,7 +87,7 @@ export type Teaser = PartialToMaybeDeep<
87
87
  >
88
88
 
89
89
  export type Recommended = PartialToMaybe<
90
- ContentTreeWorkarounds.Recommended & {
90
+ ContentTreeWorkarounds.Recommended & {
91
91
  teaser?: Teaser
92
92
  }
93
93
  >
@@ -95,11 +95,10 @@ ContentTreeWorkarounds.Recommended & {
95
95
  export type RecommendedList = PartialToMaybe<
96
96
  ReadonlyArrays<
97
97
  Omit<ContentTree.RecommendedList, 'children'> & {
98
- teasers?: (Teaser | null)[]
99
- children: Recommended[]
100
- }
98
+ teasers?: (Teaser | null)[]
99
+ children: Recommended[]
100
+ }
101
101
  >
102
-
103
102
  >
104
103
 
105
104
  export type ImageSetPicture = PartialToMaybe<
@@ -144,6 +143,9 @@ interface ClipSource {
144
143
  pixelHeight?: number
145
144
  pixelWidth?: number
146
145
  videoCodec?: string
146
+ quality?: string
147
+ dppx?: number
148
+ previousSourceWidth?: number
147
149
  }
148
150
  export type Clip = PartialToMaybeDeep<
149
151
  ReadonlyArrays<{
@@ -178,6 +180,7 @@ interface ClipSetReferences {
178
180
  subtitle?: string
179
181
  publishedDate?: string
180
182
  clips?: Clip[]
183
+ fragmentIdentifier?: string | undefined
181
184
  }
182
185
 
183
186
  export type ClipSet = PartialToMaybeDeep<