@financial-times/content-tree 0.1.0 → 0.5.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,12 +329,14 @@ type StoryBlock =
288
329
  | Layout
289
330
  | Pullquote
290
331
  | ScrollyBlock
332
+ | ClipSet
291
333
  | Table
292
334
  | Recommended
293
335
  | RecommendedList
294
336
  | Tweet
295
337
  | Video
296
338
  | YoutubeVideo
339
+ | VimeoVideo
297
340
  | Timeline
298
341
  | ImagePair
299
342
  | InNumbers
@@ -358,14 +401,7 @@ type Image = {
358
401
  id: string
359
402
  width: number
360
403
  height: number
361
- format:
362
- | "desktop"
363
- | "mobile"
364
- | "square"
365
- | "square-ftedit"
366
- | "standard"
367
- | "wide"
368
- | "standard-inline"
404
+ format: AssetFormat
369
405
  url: string
370
406
  sourceSet?: ImageSource[]
371
407
  }
@@ -539,8 +575,6 @@ interface Video extends Node {
539
575
 
540
576
  The `title` can be obtained by fetching the Video from the content API.
541
577
 
542
- TODO: Figure out how Clips work, how they are different?
543
-
544
578
  ### `YoutubeVideo`
545
579
 
546
580
  ```ts
@@ -552,6 +586,72 @@ interface YoutubeVideo extends Node {
552
586
 
553
587
  **YoutubeVideo** represents a video referenced by a Youtube URL.
554
588
 
589
+ ### `VimeoVideo`
590
+
591
+ ```ts
592
+ interface VimeoVideo extends Node {
593
+ type: "vimeo-video"
594
+ /** Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>*/
595
+ url: string
596
+ }
597
+ ```
598
+
599
+ **VimeoVideo** represents a video referenced by a Vimeo URL.
600
+
601
+ _Note: this is currently only used by Specialist Titles_
602
+
603
+ ### `ClipSet`
604
+ ```ts
605
+ interface ClipSet extends Node {
606
+ type: "clip-set"
607
+ id: string
608
+ layoutWidth: ClipSetLayoutWidth
609
+ autoplay?: boolean
610
+ fragmentIdentifier?: string
611
+ loop?: boolean
612
+ muted?: boolean
613
+ external clips: Clip[]
614
+ external publishedDate: string
615
+ external accessibility?: ClipAccessibility
616
+ external caption?: string
617
+ external contentWarning?: string[]
618
+ external credits?: string
619
+ external description?: string
620
+ external displayTitle?: string
621
+ external noAudio?: boolean
622
+ external systemTitle?: string
623
+ external source?: string
624
+ external subtitle?: string
625
+ }
626
+
627
+ type Clip = {
628
+ id: string
629
+ dataSource: VideoSource[]
630
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">
631
+ poster?: string
632
+ }
633
+
634
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
635
+ type ClipCaption = {
636
+ /** Caption file content type */
637
+ mediaType?: string
638
+ /** Caption file location */
639
+ url?: string
640
+ }
641
+
642
+ type ClipAccessibility = {
643
+ captions?: ClipCaption[]
644
+ transcript?: Body
645
+ }
646
+
647
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">
648
+ ```
649
+
650
+ **ClipSet** represents a short piece of possibly-looping video content for an article.
651
+
652
+ 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.
653
+
654
+
555
655
  ### `ScrollyBlock`
556
656
 
557
657
  ```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 | VimeoVideo | 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,50 @@ export declare namespace ContentTree {
189
201
  type: "youtube-video";
190
202
  url: string;
191
203
  }
204
+ interface VimeoVideo extends Node {
205
+ type: "vimeo-video";
206
+ /** Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>*/
207
+ url: string;
208
+ }
209
+ interface ClipSet extends Node {
210
+ type: "clip-set";
211
+ id: string;
212
+ layoutWidth: ClipSetLayoutWidth;
213
+ autoplay?: boolean;
214
+ fragmentIdentifier?: string;
215
+ loop?: boolean;
216
+ muted?: boolean;
217
+ clips: Clip[];
218
+ publishedDate: string;
219
+ accessibility?: ClipAccessibility;
220
+ caption?: string;
221
+ contentWarning?: string[];
222
+ credits?: string;
223
+ description?: string;
224
+ displayTitle?: string;
225
+ noAudio?: boolean;
226
+ systemTitle?: string;
227
+ source?: string;
228
+ subtitle?: string;
229
+ }
230
+ type Clip = {
231
+ id: string;
232
+ dataSource: VideoSource[];
233
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
234
+ poster?: string;
235
+ };
236
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
237
+ type ClipCaption = {
238
+ /** Caption file content type */
239
+ mediaType?: string;
240
+ /** Caption file location */
241
+ url?: string;
242
+ };
243
+ type ClipAccessibility = {
244
+ captions?: ClipCaption[];
245
+ transcript?: Body;
246
+ };
247
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
192
248
  interface ScrollyBlock extends Parent {
193
249
  type: "scrolly-block";
194
250
  theme: "sans" | "serif";
@@ -367,7 +423,19 @@ export declare namespace ContentTree {
367
423
  children: [Card, Card];
368
424
  }
369
425
  namespace full {
426
+ type AssetFormat = "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
370
427
  type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
428
+ type AVSource = {
429
+ binaryUrl: string;
430
+ mediaType: string;
431
+ audioCodec?: string;
432
+ duration?: number;
433
+ };
434
+ type VideoSource = AVSource & {
435
+ pixelHeight?: number;
436
+ pixelWidth?: number;
437
+ videoCodec?: string;
438
+ };
371
439
  interface Node {
372
440
  type: string;
373
441
  data?: any;
@@ -429,7 +497,7 @@ export declare namespace ContentTree {
429
497
  type: "find-out-more-link";
430
498
  url: string;
431
499
  title: string;
432
- children: Phrasing[];
500
+ children: [Text | Strong | Emphasis];
433
501
  }
434
502
  interface List extends Parent {
435
503
  type: "list";
@@ -444,7 +512,7 @@ export declare namespace ContentTree {
444
512
  type: "blockquote";
445
513
  children: (Paragraph | Phrasing)[];
446
514
  }
447
- type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
515
+ type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | ClipSet | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | VimeoVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
448
516
  interface Pullquote extends Node {
449
517
  type: "pullquote";
450
518
  text: string;
@@ -469,7 +537,7 @@ export declare namespace ContentTree {
469
537
  id: string;
470
538
  width: number;
471
539
  height: number;
472
- format: "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
540
+ format: AssetFormat;
473
541
  url: string;
474
542
  sourceSet?: ImageSource[];
475
543
  };
@@ -557,6 +625,50 @@ export declare namespace ContentTree {
557
625
  type: "youtube-video";
558
626
  url: string;
559
627
  }
628
+ interface VimeoVideo extends Node {
629
+ type: "vimeo-video";
630
+ /** Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>*/
631
+ url: string;
632
+ }
633
+ interface ClipSet extends Node {
634
+ type: "clip-set";
635
+ id: string;
636
+ layoutWidth: ClipSetLayoutWidth;
637
+ autoplay?: boolean;
638
+ fragmentIdentifier?: string;
639
+ loop?: boolean;
640
+ muted?: boolean;
641
+ clips: Clip[];
642
+ publishedDate: string;
643
+ accessibility?: ClipAccessibility;
644
+ caption?: string;
645
+ contentWarning?: string[];
646
+ credits?: string;
647
+ description?: string;
648
+ displayTitle?: string;
649
+ noAudio?: boolean;
650
+ systemTitle?: string;
651
+ source?: string;
652
+ subtitle?: string;
653
+ }
654
+ type Clip = {
655
+ id: string;
656
+ dataSource: VideoSource[];
657
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
658
+ poster?: string;
659
+ };
660
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
661
+ type ClipCaption = {
662
+ /** Caption file content type */
663
+ mediaType?: string;
664
+ /** Caption file location */
665
+ url?: string;
666
+ };
667
+ type ClipAccessibility = {
668
+ captions?: ClipCaption[];
669
+ transcript?: Body;
670
+ };
671
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
560
672
  interface ScrollyBlock extends Parent {
561
673
  type: "scrolly-block";
562
674
  theme: "sans" | "serif";
@@ -736,7 +848,19 @@ export declare namespace ContentTree {
736
848
  }
737
849
  }
738
850
  namespace transit {
851
+ type AssetFormat = "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
739
852
  type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
853
+ type AVSource = {
854
+ binaryUrl: string;
855
+ mediaType: string;
856
+ audioCodec?: string;
857
+ duration?: number;
858
+ };
859
+ type VideoSource = AVSource & {
860
+ pixelHeight?: number;
861
+ pixelWidth?: number;
862
+ videoCodec?: string;
863
+ };
740
864
  interface Node {
741
865
  type: string;
742
866
  data?: any;
@@ -798,7 +922,7 @@ export declare namespace ContentTree {
798
922
  type: "find-out-more-link";
799
923
  url: string;
800
924
  title: string;
801
- children: Phrasing[];
925
+ children: [Text | Strong | Emphasis];
802
926
  }
803
927
  interface List extends Parent {
804
928
  type: "list";
@@ -813,7 +937,7 @@ export declare namespace ContentTree {
813
937
  type: "blockquote";
814
938
  children: (Paragraph | Phrasing)[];
815
939
  }
816
- type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
940
+ type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | ClipSet | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | VimeoVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
817
941
  interface Pullquote extends Node {
818
942
  type: "pullquote";
819
943
  text: string;
@@ -837,7 +961,7 @@ export declare namespace ContentTree {
837
961
  id: string;
838
962
  width: number;
839
963
  height: number;
840
- format: "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
964
+ format: AssetFormat;
841
965
  url: string;
842
966
  sourceSet?: ImageSource[];
843
967
  };
@@ -921,6 +1045,38 @@ export declare namespace ContentTree {
921
1045
  type: "youtube-video";
922
1046
  url: string;
923
1047
  }
1048
+ interface VimeoVideo extends Node {
1049
+ type: "vimeo-video";
1050
+ /** Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>*/
1051
+ url: string;
1052
+ }
1053
+ interface ClipSet extends Node {
1054
+ type: "clip-set";
1055
+ id: string;
1056
+ layoutWidth: ClipSetLayoutWidth;
1057
+ autoplay?: boolean;
1058
+ fragmentIdentifier?: string;
1059
+ loop?: boolean;
1060
+ muted?: boolean;
1061
+ }
1062
+ type Clip = {
1063
+ id: string;
1064
+ dataSource: VideoSource[];
1065
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
1066
+ poster?: string;
1067
+ };
1068
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
1069
+ type ClipCaption = {
1070
+ /** Caption file content type */
1071
+ mediaType?: string;
1072
+ /** Caption file location */
1073
+ url?: string;
1074
+ };
1075
+ type ClipAccessibility = {
1076
+ captions?: ClipCaption[];
1077
+ transcript?: Body;
1078
+ };
1079
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
924
1080
  interface ScrollyBlock extends Parent {
925
1081
  type: "scrolly-block";
926
1082
  theme: "sans" | "serif";
@@ -1090,7 +1246,19 @@ export declare namespace ContentTree {
1090
1246
  }
1091
1247
  }
1092
1248
  namespace loose {
1249
+ type AssetFormat = "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
1093
1250
  type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
1251
+ type AVSource = {
1252
+ binaryUrl: string;
1253
+ mediaType: string;
1254
+ audioCodec?: string;
1255
+ duration?: number;
1256
+ };
1257
+ type VideoSource = AVSource & {
1258
+ pixelHeight?: number;
1259
+ pixelWidth?: number;
1260
+ videoCodec?: string;
1261
+ };
1094
1262
  interface Node {
1095
1263
  type: string;
1096
1264
  data?: any;
@@ -1152,7 +1320,7 @@ export declare namespace ContentTree {
1152
1320
  type: "find-out-more-link";
1153
1321
  url: string;
1154
1322
  title: string;
1155
- children: Phrasing[];
1323
+ children: [Text | Strong | Emphasis];
1156
1324
  }
1157
1325
  interface List extends Parent {
1158
1326
  type: "list";
@@ -1167,7 +1335,7 @@ export declare namespace ContentTree {
1167
1335
  type: "blockquote";
1168
1336
  children: (Paragraph | Phrasing)[];
1169
1337
  }
1170
- type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
1338
+ type StoryBlock = ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | Pullquote | ScrollyBlock | ClipSet | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | VimeoVideo | Timeline | ImagePair | InNumbers | Definition | InfoBox | InfoPair;
1171
1339
  interface Pullquote extends Node {
1172
1340
  type: "pullquote";
1173
1341
  text: string;
@@ -1192,7 +1360,7 @@ export declare namespace ContentTree {
1192
1360
  id: string;
1193
1361
  width: number;
1194
1362
  height: number;
1195
- format: "desktop" | "mobile" | "square" | "square-ftedit" | "standard" | "wide" | "standard-inline";
1363
+ format: AssetFormat;
1196
1364
  url: string;
1197
1365
  sourceSet?: ImageSource[];
1198
1366
  };
@@ -1280,6 +1448,50 @@ export declare namespace ContentTree {
1280
1448
  type: "youtube-video";
1281
1449
  url: string;
1282
1450
  }
1451
+ interface VimeoVideo extends Node {
1452
+ type: "vimeo-video";
1453
+ /** Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>*/
1454
+ url: string;
1455
+ }
1456
+ interface ClipSet extends Node {
1457
+ type: "clip-set";
1458
+ id: string;
1459
+ layoutWidth: ClipSetLayoutWidth;
1460
+ autoplay?: boolean;
1461
+ fragmentIdentifier?: string;
1462
+ loop?: boolean;
1463
+ muted?: boolean;
1464
+ clips?: Clip[];
1465
+ publishedDate?: string;
1466
+ accessibility?: ClipAccessibility;
1467
+ caption?: string;
1468
+ contentWarning?: string[];
1469
+ credits?: string;
1470
+ description?: string;
1471
+ displayTitle?: string;
1472
+ noAudio?: boolean;
1473
+ systemTitle?: string;
1474
+ source?: string;
1475
+ subtitle?: string;
1476
+ }
1477
+ type Clip = {
1478
+ id: string;
1479
+ dataSource: VideoSource[];
1480
+ format?: Extract<AssetFormat, "standard-inline" | "mobile">;
1481
+ poster?: string;
1482
+ };
1483
+ /** Clip captions are files that provide the text captions on the video and their synchronisation timings */
1484
+ type ClipCaption = {
1485
+ /** Caption file content type */
1486
+ mediaType?: string;
1487
+ /** Caption file location */
1488
+ url?: string;
1489
+ };
1490
+ type ClipAccessibility = {
1491
+ captions?: ClipCaption[];
1492
+ transcript?: Body;
1493
+ };
1494
+ type ClipSetLayoutWidth = Extract<LayoutWidth, "in-line" | "mid-grid" | "full-grid">;
1283
1495
  interface ScrollyBlock extends Parent {
1284
1496
  type: "scrolly-block";
1285
1497
  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.5.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
  },
@@ -129,6 +132,9 @@
129
132
  {
130
133
  "$ref": "#/definitions/ContentTree.transit.YoutubeVideo"
131
134
  },
135
+ {
136
+ "$ref": "#/definitions/ContentTree.transit.VimeoVideo"
137
+ },
132
138
  {
133
139
  "$ref": "#/definitions/ContentTree.transit.Timeline"
134
140
  },
@@ -212,6 +218,48 @@
212
218
  ],
213
219
  "description": "Allowed children for a card"
214
220
  },
221
+ "ContentTree.transit.ClipSet": {
222
+ "additionalProperties": false,
223
+ "properties": {
224
+ "autoplay": {
225
+ "type": "boolean"
226
+ },
227
+ "data": {},
228
+ "fragmentIdentifier": {
229
+ "type": "string"
230
+ },
231
+ "id": {
232
+ "type": "string"
233
+ },
234
+ "layoutWidth": {
235
+ "$ref": "#/definitions/ContentTree.transit.ClipSetLayoutWidth"
236
+ },
237
+ "loop": {
238
+ "type": "boolean"
239
+ },
240
+ "muted": {
241
+ "type": "boolean"
242
+ },
243
+ "type": {
244
+ "const": "clip-set",
245
+ "type": "string"
246
+ }
247
+ },
248
+ "required": [
249
+ "id",
250
+ "layoutWidth",
251
+ "type"
252
+ ],
253
+ "type": "object"
254
+ },
255
+ "ContentTree.transit.ClipSetLayoutWidth": {
256
+ "enum": [
257
+ "full-grid",
258
+ "in-line",
259
+ "mid-grid"
260
+ ],
261
+ "type": "string"
262
+ },
215
263
  "ContentTree.transit.CustomCodeComponent": {
216
264
  "additionalProperties": false,
217
265
  "properties": {
@@ -285,9 +333,23 @@
285
333
  "additionalProperties": false,
286
334
  "properties": {
287
335
  "children": {
288
- "items": {
289
- "$ref": "#/definitions/ContentTree.transit.Phrasing"
290
- },
336
+ "items": [
337
+ {
338
+ "anyOf": [
339
+ {
340
+ "$ref": "#/definitions/ContentTree.transit.Text"
341
+ },
342
+ {
343
+ "$ref": "#/definitions/ContentTree.transit.Strong"
344
+ },
345
+ {
346
+ "$ref": "#/definitions/ContentTree.transit.Emphasis"
347
+ }
348
+ ]
349
+ }
350
+ ],
351
+ "maxItems": 1,
352
+ "minItems": 1,
291
353
  "type": "array"
292
354
  },
293
355
  "data": {},
@@ -1478,6 +1540,25 @@
1478
1540
  ],
1479
1541
  "type": "object"
1480
1542
  },
1543
+ "ContentTree.transit.VimeoVideo": {
1544
+ "additionalProperties": false,
1545
+ "properties": {
1546
+ "data": {},
1547
+ "type": {
1548
+ "const": "vimeo-video",
1549
+ "type": "string"
1550
+ },
1551
+ "url": {
1552
+ "description": "Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>",
1553
+ "type": "string"
1554
+ }
1555
+ },
1556
+ "required": [
1557
+ "type",
1558
+ "url"
1559
+ ],
1560
+ "type": "object"
1561
+ },
1481
1562
  "ContentTree.transit.YoutubeVideo": {
1482
1563
  "additionalProperties": false,
1483
1564
  "properties": {
@@ -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
  },
@@ -154,6 +169,9 @@
154
169
  {
155
170
  "$ref": "#/definitions/ContentTree.full.YoutubeVideo"
156
171
  },
172
+ {
173
+ "$ref": "#/definitions/ContentTree.full.VimeoVideo"
174
+ },
157
175
  {
158
176
  "$ref": "#/definitions/ContentTree.full.Timeline"
159
177
  },
@@ -237,6 +255,138 @@
237
255
  ],
238
256
  "description": "Allowed children for a card"
239
257
  },
258
+ "ContentTree.full.ClipSet": {
259
+ "additionalProperties": false,
260
+ "properties": {
261
+ "accessibility": {
262
+ "additionalProperties": false,
263
+ "properties": {
264
+ "captions": {
265
+ "items": {
266
+ "additionalProperties": false,
267
+ "description": "Clip captions are files that provide the text captions on the video and their synchronisation timings",
268
+ "properties": {
269
+ "mediaType": {
270
+ "description": "Caption file content type",
271
+ "type": "string"
272
+ },
273
+ "url": {
274
+ "description": "Caption file location",
275
+ "type": "string"
276
+ }
277
+ },
278
+ "type": "object"
279
+ },
280
+ "type": "array"
281
+ },
282
+ "transcript": {
283
+ "$ref": "#/definitions/ContentTree.full.Body"
284
+ }
285
+ },
286
+ "type": "object"
287
+ },
288
+ "autoplay": {
289
+ "type": "boolean"
290
+ },
291
+ "caption": {
292
+ "type": "string"
293
+ },
294
+ "clips": {
295
+ "items": {
296
+ "additionalProperties": false,
297
+ "properties": {
298
+ "dataSource": {
299
+ "items": {
300
+ "$ref": "#/definitions/ContentTree.full.VideoSource"
301
+ },
302
+ "type": "array"
303
+ },
304
+ "format": {
305
+ "$ref": "#/definitions/Extract"
306
+ },
307
+ "id": {
308
+ "type": "string"
309
+ },
310
+ "poster": {
311
+ "type": "string"
312
+ }
313
+ },
314
+ "required": [
315
+ "dataSource",
316
+ "id"
317
+ ],
318
+ "type": "object"
319
+ },
320
+ "type": "array"
321
+ },
322
+ "contentWarning": {
323
+ "items": {
324
+ "type": "string"
325
+ },
326
+ "type": "array"
327
+ },
328
+ "credits": {
329
+ "type": "string"
330
+ },
331
+ "data": {},
332
+ "description": {
333
+ "type": "string"
334
+ },
335
+ "displayTitle": {
336
+ "type": "string"
337
+ },
338
+ "fragmentIdentifier": {
339
+ "type": "string"
340
+ },
341
+ "id": {
342
+ "type": "string"
343
+ },
344
+ "layoutWidth": {
345
+ "$ref": "#/definitions/ContentTree.full.ClipSetLayoutWidth"
346
+ },
347
+ "loop": {
348
+ "type": "boolean"
349
+ },
350
+ "muted": {
351
+ "type": "boolean"
352
+ },
353
+ "noAudio": {
354
+ "type": "boolean"
355
+ },
356
+ "publishedDate": {
357
+ "type": "string"
358
+ },
359
+ "source": {
360
+ "type": "string"
361
+ },
362
+ "subtitle": {
363
+ "type": "string"
364
+ },
365
+ "systemTitle": {
366
+ "type": "string"
367
+ },
368
+ "type": {
369
+ "const": "clip-set",
370
+ "type": "string"
371
+ }
372
+ },
373
+ "required": [
374
+ "clips",
375
+ "id",
376
+ "layoutWidth",
377
+ "publishedDate",
378
+ "type"
379
+ ],
380
+ "type": "object"
381
+ },
382
+ "ContentTree.full.ClipSetLayoutWidth": {
383
+ "enum": [
384
+ "full-grid",
385
+ "in-line",
386
+ "mid-grid"
387
+ ],
388
+ "type": "string"
389
+ },
240
390
  "ContentTree.full.CustomCodeComponent": {
241
391
  "additionalProperties": false,
242
392
  "properties": {
@@ -336,9 +486,23 @@
336
486
  "additionalProperties": false,
337
487
  "properties": {
338
488
  "children": {
339
- "items": {
340
- "$ref": "#/definitions/ContentTree.full.Phrasing"
341
- },
489
+ "items": [
490
+ {
491
+ "anyOf": [
492
+ {
493
+ "$ref": "#/definitions/ContentTree.full.Text"
494
+ },
495
+ {
496
+ "$ref": "#/definitions/ContentTree.full.Strong"
497
+ },
498
+ {
499
+ "$ref": "#/definitions/ContentTree.full.Emphasis"
500
+ }
501
+ ]
502
+ }
503
+ ],
504
+ "maxItems": 1,
505
+ "minItems": 1,
342
506
  "type": "array"
343
507
  },
344
508
  "data": {},
@@ -372,16 +536,7 @@
372
536
  "additionalProperties": false,
373
537
  "properties": {
374
538
  "format": {
375
- "enum": [
376
- "desktop",
377
- "mobile",
378
- "square",
379
- "square-ftedit",
380
- "standard",
381
- "standard-inline",
382
- "wide"
383
- ],
384
- "type": "string"
539
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
385
540
  },
386
541
  "height": {
387
542
  "type": "number"
@@ -550,16 +705,7 @@
550
705
  "additionalProperties": false,
551
706
  "properties": {
552
707
  "format": {
553
- "enum": [
554
- "desktop",
555
- "mobile",
556
- "square",
557
- "square-ftedit",
558
- "standard",
559
- "standard-inline",
560
- "wide"
561
- ],
562
- "type": "string"
708
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
563
709
  },
564
710
  "height": {
565
711
  "type": "number"
@@ -618,16 +764,7 @@
618
764
  "additionalProperties": false,
619
765
  "properties": {
620
766
  "format": {
621
- "enum": [
622
- "desktop",
623
- "mobile",
624
- "square",
625
- "square-ftedit",
626
- "standard",
627
- "standard-inline",
628
- "wide"
629
- ],
630
- "type": "string"
767
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
631
768
  },
632
769
  "height": {
633
770
  "type": "number"
@@ -908,16 +1045,7 @@
908
1045
  "additionalProperties": false,
909
1046
  "properties": {
910
1047
  "format": {
911
- "enum": [
912
- "desktop",
913
- "mobile",
914
- "square",
915
- "square-ftedit",
916
- "standard",
917
- "standard-inline",
918
- "wide"
919
- ],
920
- "type": "string"
1048
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
921
1049
  },
922
1050
  "height": {
923
1051
  "type": "number"
@@ -976,16 +1104,7 @@
976
1104
  "additionalProperties": false,
977
1105
  "properties": {
978
1106
  "format": {
979
- "enum": [
980
- "desktop",
981
- "mobile",
982
- "square",
983
- "square-ftedit",
984
- "standard",
985
- "standard-inline",
986
- "wide"
987
- ],
988
- "type": "string"
1107
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
989
1108
  },
990
1109
  "height": {
991
1110
  "type": "number"
@@ -1629,16 +1748,7 @@
1629
1748
  "additionalProperties": false,
1630
1749
  "properties": {
1631
1750
  "format": {
1632
- "enum": [
1633
- "desktop",
1634
- "mobile",
1635
- "square",
1636
- "square-ftedit",
1637
- "standard",
1638
- "standard-inline",
1639
- "wide"
1640
- ],
1641
- "type": "string"
1751
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
1642
1752
  },
1643
1753
  "height": {
1644
1754
  "type": "number"
@@ -1697,16 +1807,7 @@
1697
1807
  "additionalProperties": false,
1698
1808
  "properties": {
1699
1809
  "format": {
1700
- "enum": [
1701
- "desktop",
1702
- "mobile",
1703
- "square",
1704
- "square-ftedit",
1705
- "standard",
1706
- "standard-inline",
1707
- "wide"
1708
- ],
1709
- "type": "string"
1810
+ "$ref": "#/definitions/ContentTree.full.AssetFormat"
1710
1811
  },
1711
1812
  "height": {
1712
1813
  "type": "number"
@@ -2267,6 +2368,56 @@
2267
2368
  ],
2268
2369
  "type": "object"
2269
2370
  },
2371
+ "ContentTree.full.VideoSource": {
2372
+ "additionalProperties": false,
2373
+ "properties": {
2374
+ "audioCodec": {
2375
+ "type": "string"
2376
+ },
2377
+ "binaryUrl": {
2378
+ "type": "string"
2379
+ },
2380
+ "duration": {
2381
+ "type": "number"
2382
+ },
2383
+ "mediaType": {
2384
+ "type": "string"
2385
+ },
2386
+ "pixelHeight": {
2387
+ "type": "number"
2388
+ },
2389
+ "pixelWidth": {
2390
+ "type": "number"
2391
+ },
2392
+ "videoCodec": {
2393
+ "type": "string"
2394
+ }
2395
+ },
2396
+ "required": [
2397
+ "binaryUrl",
2398
+ "mediaType"
2399
+ ],
2400
+ "type": "object"
2401
+ },
2402
+ "ContentTree.full.VimeoVideo": {
2403
+ "additionalProperties": false,
2404
+ "properties": {
2405
+ "data": {},
2406
+ "type": {
2407
+ "const": "vimeo-video",
2408
+ "type": "string"
2409
+ },
2410
+ "url": {
2411
+ "description": "Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>",
2412
+ "type": "string"
2413
+ }
2414
+ },
2415
+ "required": [
2416
+ "type",
2417
+ "url"
2418
+ ],
2419
+ "type": "object"
2420
+ },
2270
2421
  "ContentTree.full.YoutubeVideo": {
2271
2422
  "additionalProperties": false,
2272
2423
  "properties": {
@@ -2284,6 +2435,13 @@
2284
2435
  "url"
2285
2436
  ],
2286
2437
  "type": "object"
2438
+ },
2439
+ "Extract": {
2440
+ "enum": [
2441
+ "mobile",
2442
+ "standard-inline"
2443
+ ],
2444
+ "type": "string"
2287
2445
  }
2288
2446
  },
2289
2447
  "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
  },
@@ -154,6 +157,9 @@
154
157
  {
155
158
  "$ref": "#/definitions/ContentTree.transit.YoutubeVideo"
156
159
  },
160
+ {
161
+ "$ref": "#/definitions/ContentTree.transit.VimeoVideo"
162
+ },
157
163
  {
158
164
  "$ref": "#/definitions/ContentTree.transit.Timeline"
159
165
  },
@@ -237,6 +243,48 @@
237
243
  ],
238
244
  "description": "Allowed children for a card"
239
245
  },
246
+ "ContentTree.transit.ClipSet": {
247
+ "additionalProperties": false,
248
+ "properties": {
249
+ "autoplay": {
250
+ "type": "boolean"
251
+ },
252
+ "data": {},
253
+ "fragmentIdentifier": {
254
+ "type": "string"
255
+ },
256
+ "id": {
257
+ "type": "string"
258
+ },
259
+ "layoutWidth": {
260
+ "$ref": "#/definitions/ContentTree.transit.ClipSetLayoutWidth"
261
+ },
262
+ "loop": {
263
+ "type": "boolean"
264
+ },
265
+ "muted": {
266
+ "type": "boolean"
267
+ },
268
+ "type": {
269
+ "const": "clip-set",
270
+ "type": "string"
271
+ }
272
+ },
273
+ "required": [
274
+ "id",
275
+ "layoutWidth",
276
+ "type"
277
+ ],
278
+ "type": "object"
279
+ },
280
+ "ContentTree.transit.ClipSetLayoutWidth": {
281
+ "enum": [
282
+ "full-grid",
283
+ "in-line",
284
+ "mid-grid"
285
+ ],
286
+ "type": "string"
287
+ },
240
288
  "ContentTree.transit.CustomCodeComponent": {
241
289
  "additionalProperties": false,
242
290
  "properties": {
@@ -310,9 +358,23 @@
310
358
  "additionalProperties": false,
311
359
  "properties": {
312
360
  "children": {
313
- "items": {
314
- "$ref": "#/definitions/ContentTree.transit.Phrasing"
315
- },
361
+ "items": [
362
+ {
363
+ "anyOf": [
364
+ {
365
+ "$ref": "#/definitions/ContentTree.transit.Text"
366
+ },
367
+ {
368
+ "$ref": "#/definitions/ContentTree.transit.Strong"
369
+ },
370
+ {
371
+ "$ref": "#/definitions/ContentTree.transit.Emphasis"
372
+ }
373
+ ]
374
+ }
375
+ ],
376
+ "maxItems": 1,
377
+ "minItems": 1,
316
378
  "type": "array"
317
379
  },
318
380
  "data": {},
@@ -1503,6 +1565,25 @@
1503
1565
  ],
1504
1566
  "type": "object"
1505
1567
  },
1568
+ "ContentTree.transit.VimeoVideo": {
1569
+ "additionalProperties": false,
1570
+ "properties": {
1571
+ "data": {},
1572
+ "type": {
1573
+ "const": "vimeo-video",
1574
+ "type": "string"
1575
+ },
1576
+ "url": {
1577
+ "description": "Vimeo embed URL e.g. https://player.vimeo.com/player/<id> or https://vimeo.com/<id>",
1578
+ "type": "string"
1579
+ }
1580
+ },
1581
+ "required": [
1582
+ "type",
1583
+ "url"
1584
+ ],
1585
+ "type": "object"
1586
+ },
1506
1587
  "ContentTree.transit.YoutubeVideo": {
1507
1588
  "additionalProperties": false,
1508
1589
  "properties": {