@financial-times/content-tree 0.1.0 → 0.3.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/README.md CHANGED
@@ -185,7 +185,7 @@ To make a change to the content tree spec:
185
185
  - Clone this repo and run `npm install`
186
186
  - Update [SPEC.md](./SPEC.md) with your changes:
187
187
  - To add a new formatting node, add the definition under the [`Formatting Blocks`](./SPEC.md#formatting-blocks). If it is formatting that can be applied to text in a paragraph, ensure it is added to the [`Phrasing`](./SPEC.md#phrasing) type
188
- - To add a new storyblock, add the definition under the [`Storyblocks`](./SPEC.md#storyblocks). If the block can appear at the top level of the article body, ensure it is also added to the [`BodyBlock`](./SPEC.md#bodyblock) type definition
188
+ - To add a new storyblock, add the definition under the [`Storyblocks`](./SPEC.md#storyblocks).
189
189
  - Run `npm run build` to update `content-tree.d.ts` and (if required) the `schemas` files
190
190
 
191
191
  Once the PR is created, liaise with the [Content & Metadata](https://biz-ops.in.ft.com/Team/content) team to ensure the relevant changes are made in the Go libraries and transformers.
package/SPEC.md CHANGED
@@ -5,6 +5,23 @@
5
5
  These abstract helper types define special types a [Parent](#parent) can use as
6
6
  [children][term-child].
7
7
 
8
+
9
+ ### `AssetFormat`
10
+
11
+ ```ts
12
+ type AssetFormat =
13
+ | "desktop"
14
+ | "mobile"
15
+ | "square"
16
+ | "square-ftedit"
17
+ | "standard"
18
+ | "wide"
19
+ | "standard-inline"
20
+
21
+ ```
22
+
23
+ `AssetFormat` defines the chosen responsive setting for an asset like an image or clip
24
+
8
25
  ### `LayoutWidth`
9
26
 
10
27
  ```ts
@@ -21,6 +38,30 @@ type LayoutWidth =
21
38
 
22
39
  `LayoutWidth` defines how the component should be presented in the article page according to the column layout system.
23
40
 
41
+ ### `AVSource`
42
+
43
+ ```ts
44
+ type AVSource = {
45
+ binaryUrl: string
46
+ mediaType: string
47
+ audioCodec?: string
48
+ duration?: number
49
+ }
50
+ ```
51
+
52
+ `AVSource` defines the properties for the source of an audio or video asset
53
+
54
+ ### `VideoSource`
55
+
56
+ ```ts
57
+ type VideoSource = AVSource & {
58
+ pixelHeight?: number
59
+ pixelWidth?: number
60
+ videoCodec?: string
61
+ }
62
+ ```
63
+
64
+ `VideoSource` extends AVSource to add in the properties relevant just to videos
24
65
 
25
66
  ## Core Nodes
26
67
 
@@ -237,7 +278,7 @@ interface FindOutMoreLink extends Parent {
237
278
  type: "find-out-more-link"
238
279
  url: string
239
280
  title: string
240
- children: Phrasing[]
281
+ children: [Text | Strong | Emphasis]
241
282
  }
242
283
  ```
243
284
 
@@ -288,6 +329,7 @@ type StoryBlock =
288
329
  | Layout
289
330
  | Pullquote
290
331
  | ScrollyBlock
332
+ | ClipSet
291
333
  | Table
292
334
  | Recommended
293
335
  | RecommendedList
@@ -358,14 +400,7 @@ type Image = {
358
400
  id: string
359
401
  width: number
360
402
  height: number
361
- format:
362
- | "desktop"
363
- | "mobile"
364
- | "square"
365
- | "square-ftedit"
366
- | "standard"
367
- | "wide"
368
- | "standard-inline"
403
+ format: AssetFormat
369
404
  url: string
370
405
  sourceSet?: ImageSource[]
371
406
  }
@@ -539,8 +574,6 @@ interface Video extends Node {
539
574
 
540
575
  The `title` can be obtained by fetching the Video from the content API.
541
576
 
542
- TODO: Figure out how Clips work, how they are different?
543
-
544
577
  ### `YoutubeVideo`
545
578
 
546
579
  ```ts
@@ -552,6 +585,58 @@ interface YoutubeVideo extends Node {
552
585
 
553
586
  **YoutubeVideo** represents a video referenced by a Youtube URL.
554
587
 
588
+ ### `ClipSet`
589
+ ```ts
590
+ interface ClipSet extends Node {
591
+ type: "clip-set"
592
+ id: string
593
+ layoutWidth: ClipSetLayoutWidth
594
+ autoplay?: boolean
595
+ fragmentIdentifier?: string
596
+ loop?: boolean
597
+ muted?: boolean
598
+ external clips: Clip[]
599
+ external publishedDate: string
600
+ external accessibility?: ClipAccessibility
601
+ external caption?: string
602
+ external contentWarning?: string[]
603
+ external credits?: string
604
+ external description?: string
605
+ external displayTitle?: string
606
+ external noAudio?: boolean
607
+ external systemTitle?: string
608
+ external source?: string
609
+ external subtitle?: string
610
+ }
611
+
612
+ type Clip = {
613
+ id: string
614
+ dataSource: VideoSource[]
615
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">
616
+ poster?: string
617
+ }
618
+
619
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
620
+ type ClipCaption = {
621
+ /** Caption file content type */
622
+ mediaType?: string
623
+ /** Caption file location */
624
+ url?: string
625
+ }
626
+
627
+ type ClipAccessibility = {
628
+ captions?: ClipCaption[]
629
+ transcript?: Body
630
+ }
631
+
632
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">
633
+ ```
634
+
635
+ **ClipSet** represents a short piece of possibly-looping video content for an article.
636
+
637
+ The external fields are derived from the separately published [ClipSet](https://api.ft.com/schemas/clip-set.json) and [Clip](https://api.ft.com/schemas/clip.json) objects in the Content API.
638
+
639
+
555
640
  ### `ScrollyBlock`
556
641
 
557
642
  ```ts
package/content-tree.d.ts CHANGED
@@ -1,5 +1,17 @@
1
1
  export declare namespace ContentTree {
2
+ type AssetFormat = "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
2
3
  type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
4
+ type AVSource = {
5
+ binaryUrl: string;
6
+ mediaType: string;
7
+ audioCodec?: string;
8
+ duration?: number;
9
+ };
10
+ type VideoSource = AVSource & {
11
+ pixelHeight?: number;
12
+ pixelWidth?: number;
13
+ videoCodec?: string;
14
+ };
3
15
  interface Node {
4
16
  type: string;
5
17
  data?: any;
@@ -61,7 +73,7 @@ export declare namespace ContentTree {
61
73
  type: "find-out-more-link";
62
74
  url: string;
63
75
  title: string;
64
- children: Phrasing[];
76
+ children: [Text | Strong | Emphasis];
65
77
  }
66
78
  interface List extends Parent {
67
79
  type: "list";
@@ -76,7 +88,7 @@ export declare namespace ContentTree {
76
88
  type: "blockquote";
77
89
  children: (Paragraph | Phrasing)[];
78
90
  }
79
- type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
91
+ type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | ClipSet | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
80
92
  interface Pullquote extends Node {
81
93
  type: "pullquote";
82
94
  text: string;
@@ -101,7 +113,7 @@ export declare namespace ContentTree {
101
113
  id: string;
102
114
  width: number;
103
115
  height: number;
104
- format: "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
116
+ format: AssetFormat;
105
117
  url: string;
106
118
  sourceSet?: ImageSource[];
107
119
  };
@@ -189,6 +201,45 @@ export declare namespace ContentTree {
189
201
  type: "youtube-video";
190
202
  url: string;
191
203
  }
204
+ interface ClipSet extends Node {
205
+ type: "clip-set";
206
+ id: string;
207
+ layoutWidth: ClipSetLayoutWidth;
208
+ autoplay?: boolean;
209
+ fragmentIdentifier?: string;
210
+ loop?: boolean;
211
+ muted?: boolean;
212
+ clips: Clip[];
213
+ publishedDate: string;
214
+ accessibility?: ClipAccessibility;
215
+ caption?: string;
216
+ contentWarning?: string[];
217
+ credits?: string;
218
+ description?: string;
219
+ displayTitle?: string;
220
+ noAudio?: boolean;
221
+ systemTitle?: string;
222
+ source?: string;
223
+ subtitle?: string;
224
+ }
225
+ type Clip = {
226
+ id: string;
227
+ dataSource: VideoSource[];
228
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
229
+ poster?: string;
230
+ };
231
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
232
+ type ClipCaption = {
233
+ /** Caption file content type */
234
+ mediaType?: string;
235
+ /** Caption file location */
236
+ url?: string;
237
+ };
238
+ type ClipAccessibility = {
239
+ captions?: ClipCaption[];
240
+ transcript?: Body;
241
+ };
242
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
192
243
  interface ScrollyBlock extends Parent {
193
244
  type: "scrolly-block";
194
245
  theme: "sans" | "serif";
@@ -367,7 +418,19 @@ export declare namespace ContentTree {
367
418
  children: [Card, Card];
368
419
  }
369
420
  namespace full {
421
+ type AssetFormat = "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
370
422
  type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
423
+ type AVSource = {
424
+ binaryUrl: string;
425
+ mediaType: string;
426
+ audioCodec?: string;
427
+ duration?: number;
428
+ };
429
+ type VideoSource = AVSource & {
430
+ pixelHeight?: number;
431
+ pixelWidth?: number;
432
+ videoCodec?: string;
433
+ };
371
434
  interface Node {
372
435
  type: string;
373
436
  data?: any;
@@ -429,7 +492,7 @@ export declare namespace ContentTree {
429
492
  type: "find-out-more-link";
430
493
  url: string;
431
494
  title: string;
432
- children: Phrasing[];
495
+ children: [Text | Strong | Emphasis];
433
496
  }
434
497
  interface List extends Parent {
435
498
  type: "list";
@@ -444,7 +507,7 @@ export declare namespace ContentTree {
444
507
  type: "blockquote";
445
508
  children: (Paragraph | Phrasing)[];
446
509
  }
447
- type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
510
+ type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | ClipSet | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
448
511
  interface Pullquote extends Node {
449
512
  type: "pullquote";
450
513
  text: string;
@@ -469,7 +532,7 @@ export declare namespace ContentTree {
469
532
  id: string;
470
533
  width: number;
471
534
  height: number;
472
- format: "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
535
+ format: AssetFormat;
473
536
  url: string;
474
537
  sourceSet?: ImageSource[];
475
538
  };
@@ -557,6 +620,45 @@ export declare namespace ContentTree {
557
620
  type: "youtube-video";
558
621
  url: string;
559
622
  }
623
+ interface ClipSet extends Node {
624
+ type: "clip-set";
625
+ id: string;
626
+ layoutWidth: ClipSetLayoutWidth;
627
+ autoplay?: boolean;
628
+ fragmentIdentifier?: string;
629
+ loop?: boolean;
630
+ muted?: boolean;
631
+ clips: Clip[];
632
+ publishedDate: string;
633
+ accessibility?: ClipAccessibility;
634
+ caption?: string;
635
+ contentWarning?: string[];
636
+ credits?: string;
637
+ description?: string;
638
+ displayTitle?: string;
639
+ noAudio?: boolean;
640
+ systemTitle?: string;
641
+ source?: string;
642
+ subtitle?: string;
643
+ }
644
+ type Clip = {
645
+ id: string;
646
+ dataSource: VideoSource[];
647
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
648
+ poster?: string;
649
+ };
650
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
651
+ type ClipCaption = {
652
+ /** Caption file content type */
653
+ mediaType?: string;
654
+ /** Caption file location */
655
+ url?: string;
656
+ };
657
+ type ClipAccessibility = {
658
+ captions?: ClipCaption[];
659
+ transcript?: Body;
660
+ };
661
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
560
662
  interface ScrollyBlock extends Parent {
561
663
  type: "scrolly-block";
562
664
  theme: "sans" | "serif";
@@ -736,7 +838,19 @@ export declare namespace ContentTree {
736
838
  }
737
839
  }
738
840
  namespace transit {
841
+ type AssetFormat = "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
739
842
  type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
843
+ type AVSource = {
844
+ binaryUrl: string;
845
+ mediaType: string;
846
+ audioCodec?: string;
847
+ duration?: number;
848
+ };
849
+ type VideoSource = AVSource & {
850
+ pixelHeight?: number;
851
+ pixelWidth?: number;
852
+ videoCodec?: string;
853
+ };
740
854
  interface Node {
741
855
  type: string;
742
856
  data?: any;
@@ -798,7 +912,7 @@ export declare namespace ContentTree {
798
912
  type: "find-out-more-link";
799
913
  url: string;
800
914
  title: string;
801
- children: Phrasing[];
915
+ children: [Text | Strong | Emphasis];
802
916
  }
803
917
  interface List extends Parent {
804
918
  type: "list";
@@ -813,7 +927,7 @@ export declare namespace ContentTree {
813
927
  type: "blockquote";
814
928
  children: (Paragraph | Phrasing)[];
815
929
  }
816
- type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
930
+ type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | ClipSet | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
817
931
  interface Pullquote extends Node {
818
932
  type: "pullquote";
819
933
  text: string;
@@ -837,7 +951,7 @@ export declare namespace ContentTree {
837
951
  id: string;
838
952
  width: number;
839
953
  height: number;
840
- format: "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
954
+ format: AssetFormat;
841
955
  url: string;
842
956
  sourceSet?: ImageSource[];
843
957
  };
@@ -921,6 +1035,33 @@ export declare namespace ContentTree {
921
1035
  type: "youtube-video";
922
1036
  url: string;
923
1037
  }
1038
+ interface ClipSet extends Node {
1039
+ type: "clip-set";
1040
+ id: string;
1041
+ layoutWidth: ClipSetLayoutWidth;
1042
+ autoplay?: boolean;
1043
+ fragmentIdentifier?: string;
1044
+ loop?: boolean;
1045
+ muted?: boolean;
1046
+ }
1047
+ type Clip = {
1048
+ id: string;
1049
+ dataSource: VideoSource[];
1050
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
1051
+ poster?: string;
1052
+ };
1053
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
1054
+ type ClipCaption = {
1055
+ /** Caption file content type */
1056
+ mediaType?: string;
1057
+ /** Caption file location */
1058
+ url?: string;
1059
+ };
1060
+ type ClipAccessibility = {
1061
+ captions?: ClipCaption[];
1062
+ transcript?: Body;
1063
+ };
1064
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
924
1065
  interface ScrollyBlock extends Parent {
925
1066
  type: "scrolly-block";
926
1067
  theme: "sans" | "serif";
@@ -1090,7 +1231,19 @@ export declare namespace ContentTree {
1090
1231
  }
1091
1232
  }
1092
1233
  namespace loose {
1234
+ type AssetFormat = "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
1093
1235
  type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
1236
+ type AVSource = {
1237
+ binaryUrl: string;
1238
+ mediaType: string;
1239
+ audioCodec?: string;
1240
+ duration?: number;
1241
+ };
1242
+ type VideoSource = AVSource & {
1243
+ pixelHeight?: number;
1244
+ pixelWidth?: number;
1245
+ videoCodec?: string;
1246
+ };
1094
1247
  interface Node {
1095
1248
  type: string;
1096
1249
  data?: any;
@@ -1152,7 +1305,7 @@ export declare namespace ContentTree {
1152
1305
  type: "find-out-more-link";
1153
1306
  url: string;
1154
1307
  title: string;
1155
- children: Phrasing[];
1308
+ children: [Text | Strong | Emphasis];
1156
1309
  }
1157
1310
  interface List extends Parent {
1158
1311
  type: "list";
@@ -1167,7 +1320,7 @@ export declare namespace ContentTree {
1167
1320
  type: "blockquote";
1168
1321
  children: (Paragraph | Phrasing)[];
1169
1322
  }
1170
- type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
1323
+ type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | ClipSet | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
1171
1324
  interface Pullquote extends Node {
1172
1325
  type: "pullquote";
1173
1326
  text: string;
@@ -1192,7 +1345,7 @@ export declare namespace ContentTree {
1192
1345
  id: string;
1193
1346
  width: number;
1194
1347
  height: number;
1195
- format: "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
1348
+ format: AssetFormat;
1196
1349
  url: string;
1197
1350
  sourceSet?: ImageSource[];
1198
1351
  };
@@ -1280,6 +1433,45 @@ export declare namespace ContentTree {
1280
1433
  type: "youtube-video";
1281
1434
  url: string;
1282
1435
  }
1436
+ interface ClipSet extends Node {
1437
+ type: "clip-set";
1438
+ id: string;
1439
+ layoutWidth: ClipSetLayoutWidth;
1440
+ autoplay?: boolean;
1441
+ fragmentIdentifier?: string;
1442
+ loop?: boolean;
1443
+ muted?: boolean;
1444
+ clips?: Clip[];
1445
+ publishedDate?: string;
1446
+ accessibility?: ClipAccessibility;
1447
+ caption?: string;
1448
+ contentWarning?: string[];
1449
+ credits?: string;
1450
+ description?: string;
1451
+ displayTitle?: string;
1452
+ noAudio?: boolean;
1453
+ systemTitle?: string;
1454
+ source?: string;
1455
+ subtitle?: string;
1456
+ }
1457
+ type Clip = {
1458
+ id: string;
1459
+ dataSource: VideoSource[];
1460
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
1461
+ poster?: string;
1462
+ };
1463
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
1464
+ type ClipCaption = {
1465
+ /** Caption file content type */
1466
+ mediaType?: string;
1467
+ /** Caption file location */
1468
+ url?: string;
1469
+ };
1470
+ type ClipAccessibility = {
1471
+ captions?: ClipCaption[];
1472
+ transcript?: Body;
1473
+ };
1474
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
1283
1475
  interface ScrollyBlock extends Parent {
1284
1476
  type: "scrolly-block";
1285
1477
  theme: "sans" | "serif";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@financial-times/content-tree",
3
3
  "description": "content tree format",
4
- "version": "0.1.0",
4
+ "version": "0.3.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -111,6 +111,9 @@
111
111
  {
112
112
  "$ref": "#/definitions/ContentTree.transit.ScrollyBlock"
113
113
  },
114
+ {
115
+ "$ref": "#/definitions/ContentTree.transit.ClipSet"
116
+ },
114
117
  {
115
118
  "$ref": "#/definitions/ContentTree.transit.Table"
116
119
  },
@@ -212,6 +215,48 @@
212
215
  ],
213
216
  "description": "Allowed children for a card"
214
217
  },
218
+ "ContentTree.transit.ClipSet": {
219
+ "additionalProperties": false,
220
+ "properties": {
221
+ "autoplay": {
222
+ "type": "boolean"
223
+ },
224
+ "data": {},
225
+ "fragmentIdentifier": {
226
+ "type": "string"
227
+ },
228
+ "id": {
229
+ "type": "string"
230
+ },
231
+ "layoutWidth": {
232
+ "$ref": "#/definitions/ContentTree.transit.ClipSetLayoutWidth"
233
+ },
234
+ "loop": {
235
+ "type": "boolean"
236
+ },
237
+ "muted": {
238
+ "type": "boolean"
239
+ },
240
+ "type": {
241
+ "const": "clip-set",
242
+ "type": "string"
243
+ }
244
+ },
245
+ "required": [
246
+ "id",
247
+ "layoutWidth",
248
+ "type"
249
+ ],
250
+ "type": "object"
251
+ },
252
+ "ContentTree.transit.ClipSetLayoutWidth": {
253
+ "enum": [
254
+ "full-grid",
255
+ "in-line",
256
+ "mid-grid"
257
+ ],
258
+ "type": "string"
259
+ },
215
260
  "ContentTree.transit.CustomCodeComponent": {
216
261
  "additionalProperties": false,
217
262
  "properties": {
@@ -285,9 +330,23 @@
285
330
  "additionalProperties": false,
286
331
  "properties": {
287
332
  "children": {
288
- "items": {
289
- "$ref": "#/definitions/ContentTree.transit.Phrasing"
290
- },
333
+ "items": [
334
+ {
335
+ "anyOf": [
336
+ {
337
+ "$ref": "#/definitions/ContentTree.transit.Text"
338
+ },
339
+ {
340
+ "$ref": "#/definitions/ContentTree.transit.Strong"
341
+ },
342
+ {
343
+ "$ref": "#/definitions/ContentTree.transit.Emphasis"
344
+ }
345
+ ]
346
+ }
347
+ ],
348
+ "maxItems": 1,
349
+ "minItems": 1,
291
350
  "type": "array"
292
351
  },
293
352
  "data": {},
@@ -2,6 +2,18 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "additionalProperties": false,
4
4
  "definitions": {
5
+ "ContentTree.full.AssetFormat": {
6
+ "enum": [
7
+ "desktop",
8
+ "mobile",
9
+ "square",
10
+ "square-ftedit",
11
+ "standard",
12
+ "standard-inline",
13
+ "wide"
14
+ ],
15
+ "type": "string"
16
+ },
5
17
  "ContentTree.full.BigNumber": {
6
18
  "additionalProperties": false,
7
19
  "properties": {
@@ -136,6 +148,9 @@
136
148
  {
137
149
  "$ref": "#/definitions/ContentTree.full.ScrollyBlock"
138
150
  },
151
+ {
152
+ "$ref": "#/definitions/ContentTree.full.ClipSet"
153
+ },
139
154
  {
140
155
  "$ref": "#/definitions/ContentTree.full.Table"
141
156
  },
@@ -237,6 +252,138 @@
237
252
  ],
238
253
  "description": "Allowed children for a card"
239
254
  },
255
+ "ContentTree.full.ClipSet": {
256
+ "additionalProperties": false,
257
+ "properties": {
258
+ "accessibility": {
259
+ "additionalProperties": false,
260
+ "properties": {
261
+ "captions": {
262
+ "items": {
263
+ "additionalProperties": false,
264
+ "description": "Clip captions are files that provide the text captions on the video and their synchronisation timings",
265
+ "properties": {
266
+ "mediaType": {
267
+ "description": "Caption file content type",
268
+ "type": "string"
269
+ },
270
+ "url": {
271
+ "description": "Caption file location",
272
+ "type": "string"
273
+ }
274
+ },
275
+ "type": "object"
276
+ },
277
+ "type": "array"
278
+ },
279
+ "transcript": {
280
+ "$ref": "#/definitions/ContentTree.full.Body"
281
+ }
282
+ },
283
+ "type": "object"
284
+ },
285
+ "autoplay": {
286
+ "type": "boolean"
287
+ },
288
+ "caption": {
289
+ "type": "string"
290
+ },
291
+ "clips": {
292
+ "items": {
293
+ "additionalProperties": false,
294
+ "properties": {
295
+ "dataSource": {
296
+ "items": {
297
+ "$ref": "#/definitions/ContentTree.full.VideoSource"
298
+ },
299
+ "type": "array"
300
+ },
301
+ "format": {
302
+ "$ref": "#/definitions/Extract"
303
+ },
304
+ "id": {
305
+ "type": "string"
306
+ },
307
+ "poster": {
308
+ "type": "string"
309
+ }
310
+ },
311
+ "required": [
312
+ "dataSource",
313
+ "id"
314
+ ],
315
+ "type": "object"
316
+ },
317
+ "type": "array"
318
+ },
319
+ "contentWarning": {
320
+ "items": {
321
+ "type": "string"
322
+ },
323
+ "type": "array"
324
+ },
325
+ "credits": {
326
+ "type": "string"
327
+ },
328
+ "data": {},
329
+ "description": {
330
+ "type": "string"
331
+ },
332
+ "displayTitle": {
333
+ "type": "string"
334
+ },
335
+ "fragmentIdentifier": {
336
+ "type": "string"
337
+ },
338
+ "id": {
339
+ "type": "string"
340
+ },
341
+ "layoutWidth": {
342
+ "$ref": "#/definitions/ContentTree.full.ClipSetLayoutWidth"
343
+ },
344
+ "loop": {
345
+ "type": "boolean"
346
+ },
347
+ "muted": {
348
+ "type": "boolean"
349
+ },
350
+ "noAudio": {
351
+ "type": "boolean"
352
+ },
353
+ "publishedDate": {
354
+ "type": "string"
355
+ },
356
+ "source": {
357
+ "type": "string"
358
+ },
359
+ "subtitle": {
360
+ "type": "string"
361
+ },
362
+ "systemTitle": {
363
+ "type": "string"
364
+ },
365
+ "type": {
366
+ "const": "clip-set",
367
+ "type": "string"
368
+ }
369
+ },
370
+ "required": [
371
+ "clips",
372
+ "id",
373
+ "layoutWidth",
374
+ "publishedDate",
375
+ "type"
376
+ ],
377
+ "type": "object"
378
+ },
379
+ "ContentTree.full.ClipSetLayoutWidth": {
380
+ "enum": [
381
+ "full-grid",
382
+ "in-line",
383
+ "mid-grid"
384
+ ],
385
+ "type": "string"
386
+ },
240
387
  "ContentTree.full.CustomCodeComponent": {
241
388
  "additionalProperties": false,
242
389
  "properties": {
@@ -336,9 +483,23 @@
336
483
  "additionalProperties": false,
337
484
  "properties": {
338
485
  "children": {
339
- "items": {
340
- "$ref": "#/definitions/ContentTree.full.Phrasing"
341
- },
486
+ "items": [
487
+ {
488
+ "anyOf": [
489
+ {
490
+ "$ref": "#/definitions/ContentTree.full.Text"
491
+ },
492
+ {
493
+ "$ref": "#/definitions/ContentTree.full.Strong"
494
+ },
495
+ {
496
+ "$ref": "#/definitions/ContentTree.full.Emphasis"
497
+ }
498
+ ]
499
+ }
500
+ ],
501
+ "maxItems": 1,
502
+ "minItems": 1,
342
503
  "type": "array"
343
504
  },
344
505
  "data": {},
@@ -372,16 +533,7 @@
372
533
  "additionalProperties": false,
373
534
  "properties": {
374
535
  "format": {
375
- "enum": [
376
- "desktop",
377
- "mobile",
378
- "square",
379
- "square-ftedit",
380
- "standard",
381
- "standard-inline",
382
- "wide"
383
- ],
384
- "type": "string"
536
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
385
537
  },
386
538
  "height": {
387
539
  "type": "number"
@@ -550,16 +702,7 @@
550
702
  "additionalProperties": false,
551
703
  "properties": {
552
704
  "format": {
553
- "enum": [
554
- "desktop",
555
- "mobile",
556
- "square",
557
- "square-ftedit",
558
- "standard",
559
- "standard-inline",
560
- "wide"
561
- ],
562
- "type": "string"
705
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
563
706
  },
564
707
  "height": {
565
708
  "type": "number"
@@ -618,16 +761,7 @@
618
761
  "additionalProperties": false,
619
762
  "properties": {
620
763
  "format": {
621
- "enum": [
622
- "desktop",
623
- "mobile",
624
- "square",
625
- "square-ftedit",
626
- "standard",
627
- "standard-inline",
628
- "wide"
629
- ],
630
- "type": "string"
764
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
631
765
  },
632
766
  "height": {
633
767
  "type": "number"
@@ -908,16 +1042,7 @@
908
1042
  "additionalProperties": false,
909
1043
  "properties": {
910
1044
  "format": {
911
- "enum": [
912
- "desktop",
913
- "mobile",
914
- "square",
915
- "square-ftedit",
916
- "standard",
917
- "standard-inline",
918
- "wide"
919
- ],
920
- "type": "string"
1045
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
921
1046
  },
922
1047
  "height": {
923
1048
  "type": "number"
@@ -976,16 +1101,7 @@
976
1101
  "additionalProperties": false,
977
1102
  "properties": {
978
1103
  "format": {
979
- "enum": [
980
- "desktop",
981
- "mobile",
982
- "square",
983
- "square-ftedit",
984
- "standard",
985
- "standard-inline",
986
- "wide"
987
- ],
988
- "type": "string"
1104
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
989
1105
  },
990
1106
  "height": {
991
1107
  "type": "number"
@@ -1629,16 +1745,7 @@
1629
1745
  "additionalProperties": false,
1630
1746
  "properties": {
1631
1747
  "format": {
1632
- "enum": [
1633
- "desktop",
1634
- "mobile",
1635
- "square",
1636
- "square-ftedit",
1637
- "standard",
1638
- "standard-inline",
1639
- "wide"
1640
- ],
1641
- "type": "string"
1748
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
1642
1749
  },
1643
1750
  "height": {
1644
1751
  "type": "number"
@@ -1697,16 +1804,7 @@
1697
1804
  "additionalProperties": false,
1698
1805
  "properties": {
1699
1806
  "format": {
1700
- "enum": [
1701
- "desktop",
1702
- "mobile",
1703
- "square",
1704
- "square-ftedit",
1705
- "standard",
1706
- "standard-inline",
1707
- "wide"
1708
- ],
1709
- "type": "string"
1807
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
1710
1808
  },
1711
1809
  "height": {
1712
1810
  "type": "number"
@@ -2267,6 +2365,37 @@
2267
2365
  ],
2268
2366
  "type": "object"
2269
2367
  },
2368
+ "ContentTree.full.VideoSource": {
2369
+ "additionalProperties": false,
2370
+ "properties": {
2371
+ "audioCodec": {
2372
+ "type": "string"
2373
+ },
2374
+ "binaryUrl": {
2375
+ "type": "string"
2376
+ },
2377
+ "duration": {
2378
+ "type": "number"
2379
+ },
2380
+ "mediaType": {
2381
+ "type": "string"
2382
+ },
2383
+ "pixelHeight": {
2384
+ "type": "number"
2385
+ },
2386
+ "pixelWidth": {
2387
+ "type": "number"
2388
+ },
2389
+ "videoCodec": {
2390
+ "type": "string"
2391
+ }
2392
+ },
2393
+ "required": [
2394
+ "binaryUrl",
2395
+ "mediaType"
2396
+ ],
2397
+ "type": "object"
2398
+ },
2270
2399
  "ContentTree.full.YoutubeVideo": {
2271
2400
  "additionalProperties": false,
2272
2401
  "properties": {
@@ -2284,6 +2413,13 @@
2284
2413
  "url"
2285
2414
  ],
2286
2415
  "type": "object"
2416
+ },
2417
+ "Extract": {
2418
+ "enum": [
2419
+ "mobile",
2420
+ "standard-inline"
2421
+ ],
2422
+ "type": "string"
2287
2423
  }
2288
2424
  },
2289
2425
  "properties": {
@@ -136,6 +136,9 @@
136
136
  {
137
137
  "$ref": "#/definitions/ContentTree.transit.ScrollyBlock"
138
138
  },
139
+ {
140
+ "$ref": "#/definitions/ContentTree.transit.ClipSet"
141
+ },
139
142
  {
140
143
  "$ref": "#/definitions/ContentTree.transit.Table"
141
144
  },
@@ -237,6 +240,48 @@
237
240
  ],
238
241
  "description": "Allowed children for a card"
239
242
  },
243
+ "ContentTree.transit.ClipSet": {
244
+ "additionalProperties": false,
245
+ "properties": {
246
+ "autoplay": {
247
+ "type": "boolean"
248
+ },
249
+ "data": {},
250
+ "fragmentIdentifier": {
251
+ "type": "string"
252
+ },
253
+ "id": {
254
+ "type": "string"
255
+ },
256
+ "layoutWidth": {
257
+ "$ref": "#/definitions/ContentTree.transit.ClipSetLayoutWidth"
258
+ },
259
+ "loop": {
260
+ "type": "boolean"
261
+ },
262
+ "muted": {
263
+ "type": "boolean"
264
+ },
265
+ "type": {
266
+ "const": "clip-set",
267
+ "type": "string"
268
+ }
269
+ },
270
+ "required": [
271
+ "id",
272
+ "layoutWidth",
273
+ "type"
274
+ ],
275
+ "type": "object"
276
+ },
277
+ "ContentTree.transit.ClipSetLayoutWidth": {
278
+ "enum": [
279
+ "full-grid",
280
+ "in-line",
281
+ "mid-grid"
282
+ ],
283
+ "type": "string"
284
+ },
240
285
  "ContentTree.transit.CustomCodeComponent": {
241
286
  "additionalProperties": false,
242
287
  "properties": {
@@ -310,9 +355,23 @@
310
355
  "additionalProperties": false,
311
356
  "properties": {
312
357
  "children": {
313
- "items": {
314
- "$ref": "#/definitions/ContentTree.transit.Phrasing"
315
- },
358
+ "items": [
359
+ {
360
+ "anyOf": [
361
+ {
362
+ "$ref": "#/definitions/ContentTree.transit.Text"
363
+ },
364
+ {
365
+ "$ref": "#/definitions/ContentTree.transit.Strong"
366
+ },
367
+ {
368
+ "$ref": "#/definitions/ContentTree.transit.Emphasis"
369
+ }
370
+ ]
371
+ }
372
+ ],
373
+ "maxItems": 1,
374
+ "minItems": 1,
316
375
  "type": "array"
317
376
  },
318
377
  "data": {},