@financial-times/cp-content-pipeline-ui 6.14.1 → 6.15.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.
Files changed (238) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/lib/components/ArticleBody/index.d.ts +2 -1
  3. package/lib/components/ArticleBody/index.js +2 -2
  4. package/lib/components/ArticleBody/index.js.map +1 -1
  5. package/lib/components/ArticleInfo/index.d.ts +3 -3
  6. package/lib/components/ArticleInfo/index.js +2 -2
  7. package/lib/components/ArticleInfo/index.js.map +1 -1
  8. package/lib/components/BackToTopButton/client/index.d.ts +4 -2
  9. package/lib/components/BackToTopButton/client/index.js +2 -11
  10. package/lib/components/BackToTopButton/client/index.js.map +1 -1
  11. package/lib/components/BackToTopButton/client/utils.js +1 -2
  12. package/lib/components/BackToTopButton/client/utils.js.map +1 -1
  13. package/lib/components/BigNumber/index.d.ts +2 -1
  14. package/lib/components/BigNumber/index.js +2 -2
  15. package/lib/components/BigNumber/index.js.map +1 -1
  16. package/lib/components/Body/index.d.ts +2 -1
  17. package/lib/components/Body/index.js +2 -2
  18. package/lib/components/Body/index.js.map +1 -1
  19. package/lib/components/Byline/index.d.ts +2 -2
  20. package/lib/components/Byline/index.js +2 -2
  21. package/lib/components/Byline/index.js.map +1 -1
  22. package/lib/components/Clip/client/index.js.map +1 -1
  23. package/lib/components/Clip/client/progressBar.js.map +1 -1
  24. package/lib/components/Clip/client/utils.js +4 -5
  25. package/lib/components/Clip/client/utils.js.map +1 -1
  26. package/lib/components/Clip/components/Caption.d.ts +1 -1
  27. package/lib/components/Clip/components/Caption.js.map +1 -1
  28. package/lib/components/Clip/components/ClipTag.d.ts +1 -1
  29. package/lib/components/Clip/components/ClipTag.js.map +1 -1
  30. package/lib/components/Clip/components/ClosedCaptions.d.ts +2 -2
  31. package/lib/components/Clip/components/ClosedCaptions.js +1 -1
  32. package/lib/components/Clip/components/ClosedCaptions.js.map +1 -1
  33. package/lib/components/Clip/components/Container.d.ts +2 -3
  34. package/lib/components/Clip/components/Container.js +1 -1
  35. package/lib/components/Clip/components/Container.js.map +1 -1
  36. package/lib/components/Clip/components/ContentLayout.d.ts +2 -3
  37. package/lib/components/Clip/components/ContentLayout.js.map +1 -1
  38. package/lib/components/Clip/components/Credit.d.ts +1 -1
  39. package/lib/components/Clip/components/Credit.js.map +1 -1
  40. package/lib/components/Clip/components/VideoDescription.d.ts +1 -1
  41. package/lib/components/Clip/components/VideoDescription.js.map +1 -1
  42. package/lib/components/Clip/components/VideoInfoBox.d.ts +1 -1
  43. package/lib/components/Clip/components/VideoInfoBox.js.map +1 -1
  44. package/lib/components/Clip/template/component.d.ts +2 -2
  45. package/lib/components/Clip/template/component.js +2 -2
  46. package/lib/components/Clip/template/component.js.map +1 -1
  47. package/lib/components/Clip/template/index.js +1 -1
  48. package/lib/components/Clip/template/index.js.map +1 -1
  49. package/lib/components/Clip/test/fixtures.js.map +1 -1
  50. package/lib/components/Clip/test/index.spec.js.map +1 -1
  51. package/lib/components/Clip/test/snapshot.spec.js +2 -2
  52. package/lib/components/Clip/test/snapshot.spec.js.map +1 -1
  53. package/lib/components/ContentPackageBody/index.d.ts +2 -2
  54. package/lib/components/ContentPackageBody/index.js +9 -9
  55. package/lib/components/ContentPackageBody/index.js.map +1 -1
  56. package/lib/components/Expander/client/index.js.map +1 -1
  57. package/lib/components/Expander/test/client/index.spec.js.map +1 -1
  58. package/lib/components/FixedAspectRatio/FixedAspectRatio.d.ts +3 -1622
  59. package/lib/components/FixedAspectRatio/FixedAspectRatio.js +3 -3
  60. package/lib/components/FixedAspectRatio/FixedAspectRatio.js.map +1 -1
  61. package/lib/components/Flourish/client/index.js.map +1 -1
  62. package/lib/components/Flourish/index.d.ts +2 -2
  63. package/lib/components/Flourish/index.js +2 -2
  64. package/lib/components/Flourish/index.js.map +1 -1
  65. package/lib/components/Heading/index.d.ts +2 -5
  66. package/lib/components/Heading/index.js +2 -1
  67. package/lib/components/Heading/index.js.map +1 -1
  68. package/lib/components/Headshot/index.d.ts +2 -2
  69. package/lib/components/Headshot/index.js +2 -2
  70. package/lib/components/Headshot/index.js.map +1 -1
  71. package/lib/components/ImageSet/index.d.ts +8 -6
  72. package/lib/components/ImageSet/index.js +11 -11
  73. package/lib/components/ImageSet/index.js.map +1 -1
  74. package/lib/components/Layout/index.d.ts +4 -10
  75. package/lib/components/Layout/index.js +7 -7
  76. package/lib/components/Layout/index.js.map +1 -1
  77. package/lib/components/LiveBlogBody/index.d.ts +2 -2
  78. package/lib/components/LiveBlogBody/index.js +2 -2
  79. package/lib/components/LiveBlogBody/index.js.map +1 -1
  80. package/lib/components/LiveBlogPost/ShareButtons.d.ts +4 -3
  81. package/lib/components/LiveBlogPost/ShareButtons.js +2 -1
  82. package/lib/components/LiveBlogPost/ShareButtons.js.map +1 -1
  83. package/lib/components/LiveBlogPost/Timestamp.d.ts +2 -2
  84. package/lib/components/LiveBlogPost/Timestamp.js +2 -1
  85. package/lib/components/LiveBlogPost/Timestamp.js.map +1 -1
  86. package/lib/components/LiveBlogPost/index.d.ts +1 -1
  87. package/lib/components/LiveBlogPost/index.js +1 -1
  88. package/lib/components/LiveBlogPost/index.js.map +1 -1
  89. package/lib/components/LiveBlogPost/svgIcons.d.ts +3 -3
  90. package/lib/components/LiveBlogPost/svgIcons.js +6 -6
  91. package/lib/components/LiveBlogPost/svgIcons.js.map +1 -1
  92. package/lib/components/LiveBlogWrapper/dispatchEvent.js.map +1 -1
  93. package/lib/components/LiveBlogWrapper/index.js.map +1 -1
  94. package/lib/components/LiveBlogWrapper/normalisePost.js.map +1 -1
  95. package/lib/components/LiveBlogWrapper/post-tracker.js +2 -2
  96. package/lib/components/LiveBlogWrapper/post-tracker.js.map +1 -1
  97. package/lib/components/MainImage/index.d.ts +2 -2
  98. package/lib/components/MainImage/index.js +2 -2
  99. package/lib/components/MainImage/index.js.map +1 -1
  100. package/lib/components/Paragraph/index.d.ts +2 -1
  101. package/lib/components/Paragraph/index.js +3 -3
  102. package/lib/components/Paragraph/index.js.map +1 -1
  103. package/lib/components/PodcastBody/index.d.ts +4 -2
  104. package/lib/components/PodcastBody/index.js +2 -2
  105. package/lib/components/PodcastBody/index.js.map +1 -1
  106. package/lib/components/Pullquote/index.d.ts +2 -2
  107. package/lib/components/Pullquote/index.js +2 -1
  108. package/lib/components/Pullquote/index.js.map +1 -1
  109. package/lib/components/Recommended/index.d.ts +2 -1
  110. package/lib/components/Recommended/index.js +2 -2
  111. package/lib/components/Recommended/index.js.map +1 -1
  112. package/lib/components/RichText/BasicComponents.d.ts +13 -13
  113. package/lib/components/RichText/BasicComponents.js +2 -2
  114. package/lib/components/RichText/BasicComponents.js.map +1 -1
  115. package/lib/components/RichText/index.d.ts +2 -2
  116. package/lib/components/RichText/index.js +2 -2
  117. package/lib/components/RichText/index.js.map +1 -1
  118. package/lib/components/Scrollytelling/ScrollyImage.d.ts +1 -1
  119. package/lib/components/Scrollytelling/ScrollyImage.js +2 -2
  120. package/lib/components/Scrollytelling/ScrollyImage.js.map +1 -1
  121. package/lib/components/Scrollytelling/index.d.ts +5 -5
  122. package/lib/components/Scrollytelling/index.js +1 -1
  123. package/lib/components/Scrollytelling/index.js.map +1 -1
  124. package/lib/components/Table/TableBody.d.ts +2 -1
  125. package/lib/components/Table/TableBody.js +2 -2
  126. package/lib/components/Table/TableBody.js.map +1 -1
  127. package/lib/components/Table/TableCell.d.ts +4 -2
  128. package/lib/components/Table/TableCell.js.map +1 -1
  129. package/lib/components/Table/index.d.ts +2 -1
  130. package/lib/components/Table/index.js +2 -2
  131. package/lib/components/Table/index.js.map +1 -1
  132. package/lib/components/Topper/Columnist.d.ts +2 -2
  133. package/lib/components/Topper/Columnist.js +2 -2
  134. package/lib/components/Topper/Columnist.js.map +1 -1
  135. package/lib/components/Topper/FollowButtonSlot.d.ts +0 -1
  136. package/lib/components/Topper/Headline.d.ts +2 -2
  137. package/lib/components/Topper/Headline.js +2 -2
  138. package/lib/components/Topper/Headline.js.map +1 -1
  139. package/lib/components/Topper/Intro.d.ts +2 -1
  140. package/lib/components/Topper/Intro.js +2 -2
  141. package/lib/components/Topper/Intro.js.map +1 -1
  142. package/lib/components/Topper/LiveBlogIndicator.d.ts +2 -2
  143. package/lib/components/Topper/LiveBlogIndicator.js +2 -2
  144. package/lib/components/Topper/LiveBlogIndicator.js.map +1 -1
  145. package/lib/components/Topper/Picture.d.ts +2 -2
  146. package/lib/components/Topper/Picture.js +2 -2
  147. package/lib/components/Topper/Picture.js.map +1 -1
  148. package/lib/components/Topper/Tags.d.ts +2 -2
  149. package/lib/components/Topper/Tags.js +7 -7
  150. package/lib/components/Topper/Tags.js.map +1 -1
  151. package/lib/components/Topper/Wrapper.d.ts +3 -4
  152. package/lib/components/Topper/Wrapper.js +2 -2
  153. package/lib/components/Topper/Wrapper.js.map +1 -1
  154. package/lib/components/Topper/client/tracking.js.map +1 -1
  155. package/lib/components/Topper/index.d.ts +2 -1
  156. package/lib/components/Topper/index.js +2 -2
  157. package/lib/components/Topper/index.js.map +1 -1
  158. package/lib/components/Tweet/index.d.ts +2 -1
  159. package/lib/components/Tweet/index.js +2 -2
  160. package/lib/components/Tweet/index.js.map +1 -1
  161. package/lib/components/Video/index.d.ts +2 -1
  162. package/lib/components/Video/index.js +2 -2
  163. package/lib/components/Video/index.js.map +1 -1
  164. package/lib/components/YoutubeVideo/index.d.ts +2 -1
  165. package/lib/components/YoutubeVideo/index.js +2 -2
  166. package/lib/components/YoutubeVideo/index.js.map +1 -1
  167. package/lib/context.d.ts +0 -1
  168. package/lib/extensions/scrollIntoView.js +1 -1
  169. package/lib/extensions/scrollIntoView.js.map +1 -1
  170. package/lib/stories/BackToTop.stories.d.ts +5 -2
  171. package/lib/stories/BackToTop.stories.js.map +1 -1
  172. package/lib/stories/Clip.stories.d.ts +1 -2
  173. package/lib/stories/Clip.stories.js +1 -1
  174. package/lib/stories/Clip.stories.js.map +1 -1
  175. package/lib/stories/Expander.stories.d.ts +37 -25
  176. package/lib/stories/Expander.stories.js +207 -36
  177. package/lib/stories/Expander.stories.js.map +1 -1
  178. package/lib/stories/LiveBlogPost.stories.d.ts +1 -1
  179. package/lib/stories/LiveBlogPost.stories.js +6 -6
  180. package/lib/stories/LiveBlogPost.stories.js.map +1 -1
  181. package/lib/stories/Topper.stories.d.ts +2 -2
  182. package/package.json +1 -1
  183. package/src/components/ArticleBody/index.tsx +3 -4
  184. package/src/components/ArticleInfo/index.tsx +5 -3
  185. package/src/components/BackToTopButton/client/index.tsx +11 -6
  186. package/src/components/BigNumber/index.tsx +6 -9
  187. package/src/components/Body/index.tsx +4 -2
  188. package/src/components/Byline/index.tsx +3 -4
  189. package/src/components/Clip/components/Caption.tsx +1 -1
  190. package/src/components/Clip/components/ClipTag.tsx +2 -2
  191. package/src/components/Clip/components/ClosedCaptions.tsx +4 -2
  192. package/src/components/Clip/components/Container.tsx +5 -3
  193. package/src/components/Clip/components/ContentLayout.tsx +4 -3
  194. package/src/components/Clip/components/Credit.tsx +1 -1
  195. package/src/components/Clip/components/VideoDescription.tsx +2 -2
  196. package/src/components/Clip/components/VideoInfoBox.tsx +1 -1
  197. package/src/components/Clip/template/component.tsx +4 -2
  198. package/src/components/ContentPackageBody/index.tsx +9 -7
  199. package/src/components/Expander/client/main.scss +27 -17
  200. package/src/components/FixedAspectRatio/FixedAspectRatio.tsx +6 -5
  201. package/src/components/Flourish/index.tsx +4 -2
  202. package/src/components/Heading/index.tsx +5 -2
  203. package/src/components/Headshot/index.tsx +4 -2
  204. package/src/components/ImageSet/index.tsx +25 -21
  205. package/src/components/Layout/index.tsx +8 -15
  206. package/src/components/LiveBlogBody/index.tsx +4 -2
  207. package/src/components/LiveBlogPost/ShareButtons.tsx +10 -5
  208. package/src/components/LiveBlogPost/Timestamp.tsx +6 -1
  209. package/src/components/LiveBlogPost/index.tsx +6 -4
  210. package/src/components/LiveBlogPost/svgIcons.tsx +3 -3
  211. package/src/components/MainImage/index.tsx +3 -1
  212. package/src/components/Paragraph/index.tsx +5 -3
  213. package/src/components/PodcastBody/index.tsx +9 -2
  214. package/src/components/Pullquote/index.tsx +5 -3
  215. package/src/components/Recommended/index.tsx +5 -2
  216. package/src/components/RichText/BasicComponents.tsx +35 -30
  217. package/src/components/RichText/index.tsx +12 -8
  218. package/src/components/Scrollytelling/ScrollyImage.tsx +4 -4
  219. package/src/components/Scrollytelling/index.tsx +10 -10
  220. package/src/components/Table/TableBody.tsx +5 -3
  221. package/src/components/Table/TableCell.tsx +3 -3
  222. package/src/components/Table/index.tsx +6 -2
  223. package/src/components/Topper/Columnist.tsx +4 -2
  224. package/src/components/Topper/Headline.tsx +4 -2
  225. package/src/components/Topper/Intro.tsx +3 -1
  226. package/src/components/Topper/LiveBlogIndicator.tsx +4 -2
  227. package/src/components/Topper/Picture.tsx +8 -6
  228. package/src/components/Topper/Tags.tsx +6 -4
  229. package/src/components/Topper/Wrapper.tsx +5 -4
  230. package/src/components/Topper/index.tsx +4 -2
  231. package/src/components/Tweet/index.tsx +3 -1
  232. package/src/components/Video/index.tsx +4 -2
  233. package/src/components/YoutubeVideo/index.tsx +4 -2
  234. package/src/stories/Clip.stories.tsx +2 -6
  235. package/src/stories/Expander.stories.tsx +231 -51
  236. package/src/stories/article-page.scss +21 -1
  237. package/src/stories/tsconfig.json +7 -0
  238. package/tsconfig.tsbuildinfo +1 -1
@@ -26,7 +26,7 @@ export interface ClipProps {
26
26
  preload?: string
27
27
  preset?: Preset
28
28
  }
29
- export default function ClipComponent({
29
+ const ClipComponent: React.FC<ClipProps> = ({
30
30
  url,
31
31
  id,
32
32
  autoplay = false,
@@ -42,7 +42,7 @@ export default function ClipComponent({
42
42
  accessibility = {},
43
43
  preset = 'full-player',
44
44
  preload = 'auto',
45
- }: ClipProps) {
45
+ }) => {
46
46
  // We support currently a single clip, with multiple sources.
47
47
  let clip = {} as Clip
48
48
  // V2 has an array of clips
@@ -109,3 +109,5 @@ export default function ClipComponent({
109
109
  </ContentLayout>
110
110
  )
111
111
  }
112
+
113
+ export default ClipComponent
@@ -37,11 +37,11 @@ type ContentPackageBodyProps = BodyProps & {
37
37
  AdSlot?: React.FC
38
38
  }
39
39
 
40
- export default function ContentPackageBody({
40
+ const ContentPackageBody: React.FC<ContentPackageBodyProps> = ({
41
41
  content,
42
42
  richTextComponents,
43
43
  AdSlot,
44
- }: ContentPackageBodyProps) {
44
+ }) => {
45
45
  if (content.__typename !== 'ContentPackage') {
46
46
  return null
47
47
  }
@@ -88,13 +88,13 @@ export default function ContentPackageBody({
88
88
  )
89
89
  }
90
90
 
91
- function PackageTeasers({
91
+ const PackageTeasers: React.FC<PackageTeasersProps> = ({
92
92
  primaryTeasers,
93
93
  secondaryTeasers,
94
94
  secondaryTeaserTitle,
95
95
  secondaryTeaserMods,
96
96
  AdSlot,
97
- }: PackageTeasersProps) {
97
+ }) => {
98
98
  return (
99
99
  <div
100
100
  className={classnames('package-container', {
@@ -117,7 +117,7 @@ function PackageTeasers({
117
117
  )
118
118
  }
119
119
 
120
- function PrimaryTeasers({ teasers }: PrimaryTeasersProps) {
120
+ const PrimaryTeasers: React.FC<PrimaryTeasersProps> = ({ teasers }) => {
121
121
  return (
122
122
  <div className="package-contents package-teasers--large">
123
123
  <ul className="package-contents package-teasers__list">
@@ -145,11 +145,11 @@ function PrimaryTeasers({ teasers }: PrimaryTeasersProps) {
145
145
  )
146
146
  }
147
147
 
148
- function SecondaryTeasers({
148
+ const SecondaryTeasers: React.FC<SecondaryTeasersProps> = ({
149
149
  teaserTitle,
150
150
  teasers,
151
151
  teaserMods,
152
- }: SecondaryTeasersProps) {
152
+ }) => {
153
153
  return (
154
154
  <div className="o-teaser-collection package-more">
155
155
  {teaserTitle && (
@@ -172,3 +172,5 @@ function SecondaryTeasers({
172
172
  </div>
173
173
  )
174
174
  }
175
+
176
+ export default ContentPackageBody
@@ -3,7 +3,6 @@
3
3
  @import '@financial-times/o-grid/main';
4
4
  @import '@financial-times/o-spacing/main';
5
5
 
6
- $numberIntroductoryElements: 1;
7
6
  $dataComponentVisibleElements: (
8
7
  'clip-set',
9
8
  'recommended',
@@ -23,28 +22,30 @@ $alwaysVisibleComponentSelectors: ();
23
22
  }
24
23
  @mixin AlwaysVisibleElements {
25
24
  @each $component in $alwaysVisibleComponentSelectors {
26
- #{$component} {
25
+ & > p:first-of-type ~ #{$component} {
27
26
  display: block;
28
27
  }
29
28
  }
30
29
  }
31
- @mixin IntroductoryElements {
32
- & > :nth-child(-n + #{$numberIntroductoryElements }):not(.cp-expander__expand) {
33
- display: block;
30
+ @mixin OrderElements {
31
+ & > * {
34
32
  order:1
35
33
  }
36
- & > :nth-child(n + #{$numberIntroductoryElements }) {
34
+ & > p:first-of-type ~ * {
37
35
  order:3
38
36
  }
37
+ & > p:first-of-type ~ .cp-expander__expand {
38
+ order:2
39
+ }
39
40
  }
40
41
  @mixin expandeAndCollapse {
41
42
  &[data-state='expanded'] {
42
43
  .cp-expander-content {
43
44
  // Show all the hidden children...
44
- & > * {
45
+ & > *:not(.cp-expander__expand) {
45
46
  display: block;
46
47
  }
47
- > .cp-expander__expand {
48
+ & > .cp-expander__expand {
48
49
  display: none;
49
50
  }
50
51
  }
@@ -56,19 +57,27 @@ $alwaysVisibleComponentSelectors: ();
56
57
  .cp-expander-content {
57
58
  // Hide everything that comes after the expander...
58
59
  // ... except the always visible children
59
- & > * {
60
+ > p:first-of-type ~ * {
60
61
  display: none;
61
62
  }
62
- &:target > * {
63
- display: block;
63
+ //when target truncated post show everything
64
+ &:target > p:first-of-type {
65
+ ~ * {
66
+ display: block;
67
+
68
+ }
69
+
70
+ ~ .cp-expander__expand {
71
+ display: none;
72
+ }
64
73
  }
74
+
65
75
  //show expand only when there is a p element, in this case we supose all other elements are exclusions that will be shown always
66
- > p ~ .cp-expander__expand {
76
+ > p:first-of-type ~ .cp-expander__expand {
67
77
  display: block;
68
- order: 2;
69
78
  }
70
- //If expander button is the second element means that there is only one element and therefore we don't have nothing to expand
71
- > :nth-child(#{$numberIntroductoryElements + 1}).cp-expander__expand {
79
+
80
+ > p:first-of-type + .cp-expander__expand {
72
81
  display: none;
73
82
  }
74
83
 
@@ -76,9 +85,10 @@ $alwaysVisibleComponentSelectors: ();
76
85
  display: none;
77
86
  }
78
87
 
88
+
79
89
  @include AlwaysVisibleElements;
80
-
81
- @include IntroductoryElements;
90
+
91
+ @include OrderElements;
82
92
 
83
93
  }
84
94
 
@@ -1,24 +1,25 @@
1
- import React, { PropsWithChildren } from 'react'
1
+ import React from 'react'
2
2
 
3
3
  type FixedAspectRatioProps = {
4
4
  width: number
5
5
  height: number
6
6
  style?: React.CSSProperties
7
7
  element?: string
8
+ [key:string]: string | boolean | React.ReactNode | React.CSSProperties
8
9
  }
9
10
 
10
11
  /**
11
12
  * High Order Component that forces a fixed aspect ratio to prevent Cumulative Layout Shift
12
13
  * for elements that have a deterministic aspect ratio server-side
13
14
  */
14
- export function FixedAspectRatio<P extends object = object>({
15
+ export const FixedAspectRatio: React.FC<React.PropsWithChildren<FixedAspectRatioProps>> = ({
15
16
  width,
16
17
  height,
17
18
  children,
18
19
  style = {},
19
20
  element = 'div',
20
- ...otherprops
21
- }: PropsWithChildren<FixedAspectRatioProps & P>) {
21
+ ...otherProps
22
+ }) => {
22
23
  let fixedAspectRatioStyles
23
24
  if (!width || !height) {
24
25
  fixedAspectRatioStyles = {
@@ -34,7 +35,7 @@ export function FixedAspectRatio<P extends object = object>({
34
35
 
35
36
  return React.createElement(
36
37
  element,
37
- { ...otherprops, style: { ...style, ...fixedAspectRatioStyles } },
38
+ { ...otherProps, style: { ...style, ...fixedAspectRatioStyles } },
38
39
  children
39
40
  )
40
41
  }
@@ -37,7 +37,7 @@ const DisclaimerNotice = ({ id }: disclaimerProps) => (
37
37
  </div>
38
38
  </div>
39
39
  )
40
- export default function Flourish({
40
+ const Flourish: React.FC<FlourishProps> = ({
41
41
  id,
42
42
  flourishType,
43
43
  description,
@@ -45,7 +45,7 @@ export default function Flourish({
45
45
  fallbackImage,
46
46
  iFrame = false,
47
47
  inArticleBody = true,
48
- }: FlourishProps) {
48
+ }) => {
49
49
  if (!id) return null
50
50
  const anchorHref = `#${id}`
51
51
  const fullGrid = layoutWidth === 'full-grid' || layoutWidth === 'grid'
@@ -115,3 +115,5 @@ export default function Flourish({
115
115
  </div>
116
116
  )
117
117
  }
118
+
119
+ export default Flourish
@@ -1,8 +1,9 @@
1
1
  import React from 'react'
2
- import type { ReactNode } from 'react'
3
2
  import type { ContentTree } from '@financial-times/content-tree'
4
3
 
5
- export default (props: ContentTree.Heading & { children: ReactNode[] }) => {
4
+ const Heading: React.FC<React.PropsWithChildren<ContentTree.Heading>> = (
5
+ props
6
+ ) => {
6
7
  if (!props.children.length) return null
7
8
 
8
9
  switch (props.level) {
@@ -14,3 +15,5 @@ export default (props: ContentTree.Heading & { children: ReactNode[] }) => {
14
15
  return <h5 className="n-content-heading-5">{props.children}</h5>
15
16
  }
16
17
  }
18
+
19
+ export default Heading
@@ -8,13 +8,13 @@ type HeadshotProps = {
8
8
  altText?: string
9
9
  }
10
10
 
11
- export default function Headshot({
11
+ const Headshot: React.FC<HeadshotProps> = ({
12
12
  headshot,
13
13
  prefLabel,
14
14
  streamPage,
15
15
  className,
16
16
  altText = `Headshot for ${prefLabel}`,
17
- }: HeadshotProps) {
17
+ }) => {
18
18
  return streamPage ? (
19
19
  <a
20
20
  target="_blank"
@@ -37,3 +37,5 @@ export default function Headshot({
37
37
  />
38
38
  )
39
39
  }
40
+
41
+ export default Headshot
@@ -80,11 +80,6 @@ function isAliasedBreakpoints(
80
80
  )
81
81
  }
82
82
 
83
- type SourceProps = {
84
- image: ImageFragment
85
- getBreakpoints?: BreakpointGetter
86
- }
87
-
88
83
  function figureWidth(picture: PictureFragment) {
89
84
  if (picture.layoutWidth === 'inset-left') {
90
85
  const DEFAULT_WIDTH = 700
@@ -101,10 +96,15 @@ function figureWidth(picture: PictureFragment) {
101
96
  }
102
97
  }
103
98
 
104
- function Source({
99
+ type SourceProps = {
100
+ image: ImageFragment
101
+ getBreakpoints?: BreakpointGetter
102
+ }
103
+
104
+ const Source: React.FC<SourceProps> = ({
105
105
  image,
106
106
  getBreakpoints = defaultGetBreakpoints,
107
- }: SourceProps) {
107
+ }) => {
108
108
  const breakpoints = getBreakpoints(image)
109
109
  if (!breakpoints) {
110
110
  return null
@@ -145,7 +145,7 @@ type SourcesProps = {
145
145
  getBreakpoints?: BreakpointGetter
146
146
  }
147
147
 
148
- export function Sources({ images, getBreakpoints }: SourcesProps) {
148
+ export const Sources: React.FC<SourcesProps> = ({ images, getBreakpoints }) => {
149
149
  return (
150
150
  <>
151
151
  {images.map((image, index) => (
@@ -155,22 +155,24 @@ export function Sources({ images, getBreakpoints }: SourcesProps) {
155
155
  )
156
156
  }
157
157
 
158
+ type FallbackImageProps = {
159
+ image: ImageFragment
160
+ imageType?: string
161
+ picture?: PictureFragment
162
+ className?: string
163
+ inSourceSet?: boolean
164
+ isMainImage?: boolean
165
+ }
166
+
158
167
  // TODO should `fallback` be added to content-tree imageset?
159
- export function FallbackImage({
168
+ export const FallbackImage: React.FC<FallbackImageProps> = ({
160
169
  image,
161
170
  imageType = 'image',
162
171
  picture,
163
172
  className,
164
173
  inSourceSet = false,
165
174
  isMainImage = false,
166
- }: {
167
- image: ImageFragment
168
- imageType?: string
169
- picture?: PictureFragment
170
- className?: string
171
- inSourceSet?: boolean
172
- isMainImage?: boolean
173
- }) {
175
+ }) => {
174
176
  const Wrapper = inSourceSet
175
177
  ? React.Fragment
176
178
  : ({ children }: PropsWithChildren) => (
@@ -199,15 +201,15 @@ export function FallbackImage({
199
201
  )
200
202
  }
201
203
 
202
- export default function ImageSet(
203
- imageSet: ImageSetFragment & { isMainImage?: boolean }
204
- ) {
205
- const { reduceFullBleedImages } = useContext(PresentationFlagsContext)
204
+ type ImageSetProps = ImageSetFragment & { isMainImage?: boolean }
206
205
 
206
+ const ImageSet: React.FC<ImageSetProps> = (imageSet) => {
207
207
  if (!imageSet.picture?.images) {
208
208
  return null
209
209
  }
210
210
 
211
+ const { reduceFullBleedImages } = useContext(PresentationFlagsContext)
212
+
211
213
  const Wrapper =
212
214
  // HACK:20240618:IM don't stretch out the main image to the full grid in
213
215
  // the app as it can clash with the right hand rail
@@ -253,3 +255,5 @@ export default function ImageSet(
253
255
  </Wrapper>
254
256
  )
255
257
  }
258
+
259
+ export default ImageSet
@@ -1,9 +1,5 @@
1
1
  import { ContentTree } from '@financial-times/content-tree'
2
- import React, { ReactNode } from 'react'
3
-
4
- type LayoutContainerProps = {
5
- children: ReactNode
6
- }
2
+ import React from 'react'
7
3
 
8
4
  interface ContentTreeLayoutSlot extends ContentTree.Node {
9
5
  type: 'slot'
@@ -21,20 +17,15 @@ interface ContentTreeCardLayout extends BaseLayoutProps, ContentTree.Node {
21
17
  children: ContentTreeLayoutSlot[]
22
18
  }
23
19
 
24
- interface StaticLayout extends BaseLayoutProps {
25
- children: ReactNode
26
- }
27
20
  /*
28
21
  * @description Layout component is used to define the layout for content. It can be used with ContentTree Layout Nodes or as a static layout.
29
22
  * @param layoutWidth - The width of the layout within the containing grid.
30
23
  * @param layoutName - The name of the layout.
31
24
  * @param children - The content to be displayed in the layout.
32
25
  */
33
- export function Layout({
34
- children,
35
- layoutWidth,
36
- layoutName = 'auto',
37
- }: React.PropsWithChildren<ContentTreeCardLayout | StaticLayout>) {
26
+ export const Layout: React.FC<
27
+ React.PropsWithChildren<ContentTreeCardLayout | BaseLayoutProps>
28
+ > = ({ children, layoutWidth, layoutName = 'auto' }) => {
38
29
  return (
39
30
  <div
40
31
  className="n-content-layout"
@@ -46,10 +37,12 @@ export function Layout({
46
37
  )
47
38
  }
48
39
 
49
- export function LayoutContainer({ children }: LayoutContainerProps) {
40
+ export const LayoutContainer: React.FC<React.PropsWithChildren> = ({
41
+ children,
42
+ }) => {
50
43
  return <div className="n-content-layout__container">{children}</div>
51
44
  }
52
45
 
53
- export function LayoutSlot({ children }: React.PropsWithChildren) {
46
+ export const LayoutSlot: React.FC<React.PropsWithChildren> = ({ children }) => {
54
47
  return <div className="n-content-layout__slot">{children}</div>
55
48
  }
@@ -10,13 +10,13 @@ type LiveBlogBodyProps = BodyProps & {
10
10
  xInteractionSerialiser?: any
11
11
  }
12
12
 
13
- export default function LiveBlogBody({
13
+ const LiveBlogBody: React.FC<LiveBlogBodyProps> = ({
14
14
  content,
15
15
  richTextComponents,
16
16
  xInteractionSerialiser,
17
17
  showShareButtons,
18
18
  postTrackerConfig,
19
- }: LiveBlogBodyProps) {
19
+ }) => {
20
20
  if (content.__typename !== 'LiveBlogPackage') return null
21
21
 
22
22
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -35,3 +35,5 @@ export default function LiveBlogBody({
35
35
  </ComponentsContext.Provider>
36
36
  )
37
37
  }
38
+
39
+ export default LiveBlogBody
@@ -1,13 +1,16 @@
1
1
  import React from 'react'
2
2
  import { FacebookSVG, LinkedInSVG, TwitterSVG } from './svgIcons'
3
- export default ({
4
- postId,
5
- articleUrl,
6
- title,
7
- }: {
3
+
4
+ type ShareButtonsProps = {
8
5
  postId: string
9
6
  articleUrl: string
10
7
  title: string
8
+ }
9
+
10
+ const ShareButtons: React.FC<ShareButtonsProps> = ({
11
+ postId,
12
+ articleUrl,
13
+ title,
11
14
  }) => {
12
15
  const shareUrl = articleUrl ? new URL(articleUrl) : null
13
16
  if (shareUrl) {
@@ -84,3 +87,5 @@ export default ({
84
87
  </div>
85
88
  )
86
89
  }
90
+
91
+ export default ShareButtons
@@ -5,7 +5,10 @@ type TimestampProps = {
5
5
  textCase?: 'sentence'
6
6
  }
7
7
 
8
- export default ({ publishedTimestamp, textCase }: TimestampProps) => {
8
+ const TimeStamp: React.FC<TimestampProps> = ({
9
+ publishedTimestamp,
10
+ textCase,
11
+ }) => {
9
12
  const now = new Date()
10
13
  const oneDay = 24 * 60 * 60 * 1000
11
14
  const date = new Date(publishedTimestamp)
@@ -38,3 +41,5 @@ export default ({ publishedTimestamp, textCase }: TimestampProps) => {
38
41
  </span>
39
42
  )
40
43
  }
44
+
45
+ export default TimeStamp
@@ -16,7 +16,10 @@ type indicators = {
16
16
  isOpinion?: boolean
17
17
  }
18
18
 
19
- const TruncatedPost = ({ id, children }: { id: string; children: any }) => {
19
+ const TruncatedPost: React.FC<React.PropsWithChildren<{ id: string }>> = ({
20
+ id,
21
+ children,
22
+ }) => {
20
23
  return (
21
24
  <div
22
25
  data-trackable="truncated-post"
@@ -77,8 +80,7 @@ export type LiveBlogPostProps = {
77
80
  indicators?: indicators
78
81
  authors: Array<any>
79
82
  }
80
-
81
- const LiveBlogPost = ({
83
+ const LiveBlogPost: React.FC<LiveBlogPostProps> = ({
82
84
  id,
83
85
  postId, // Remove once wordpress is no longer in use
84
86
  title,
@@ -96,7 +98,7 @@ const LiveBlogPost = ({
96
98
  isPinned,
97
99
  indicators = {},
98
100
  authors,
99
- }: LiveBlogPostProps) => {
101
+ }) => {
100
102
  const showBreakingNewsLabel = standout.breakingNews || isBreakingNews
101
103
 
102
104
  let postBody
@@ -5,7 +5,7 @@ TODO: CI-1975 given the below comment, once we are happy this migration works, w
5
5
  These icons have been copied from Origami as their TSX components are currently incompatible with next-article.
6
6
  Once this is resolved, these components should be replaced with o-share https://github.com/Financial-Times/origami/tree/main/components/o-share.
7
7
  */
8
- export function TwitterSVG() {
8
+ export const TwitterSVG: React.FC = () => {
9
9
  return (
10
10
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">
11
11
  <path d="M21.647 18.469 28.932 10h-1.726l-6.326 7.353L15.827 10H10l7.64 11.12L10 30h1.726l6.68-7.765L23.744 30h5.827l-7.924-11.531Zm-2.365 2.748-.774-1.107-6.16-8.81H15l4.971 7.11.774 1.107 6.462 9.242h-2.652l-5.273-7.541Z" />
@@ -13,7 +13,7 @@ export function TwitterSVG() {
13
13
  )
14
14
  }
15
15
 
16
- export function FacebookSVG() {
16
+ export const FacebookSVG: React.FC = () => {
17
17
  return (
18
18
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
19
19
  <path d="M643.9 342h-48.2c-37.8 0-45.1 18-45.1 44.3v58.1h90.1l-11.7 91h-78.4V769h-94V535.5H378v-91h78.6v-67.1c0-77.9 47.6-120.3 117.1-120.3 33.3 0 61.9 2.5 70.2 3.6V342z" />
@@ -21,7 +21,7 @@ export function FacebookSVG() {
21
21
  )
22
22
  }
23
23
 
24
- export function LinkedInSVG() {
24
+ export const LinkedInSVG: React.FC = () => {
25
25
  return (
26
26
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
27
27
  <path d="M264.4 426.2h106.2v341.4H264.4V426.2zm53.2-169.7c-34.1 0-61.6 27.6-61.6 61.5 0 34 27.5 61.5 61.6 61.5 33.9 0 61.5-27.6 61.5-61.5-.1-34-27.6-61.5-61.5-61.5zm323.1 161.2c-51.6 0-86.2 28.3-100.4 55.1h-1.5v-46.7H437.2v341.4h106V598.7c0-44.5 8.4-87.7 63.6-87.7 54.5 0 55.1 50.9 55.1 90.5v166H768V580.3c0-91.9-19.9-162.6-127.3-162.6z" />
@@ -10,7 +10,7 @@ import { ContentTree } from '@financial-times/content-tree'
10
10
  type MainImageProps = {
11
11
  content: ArticleQuery['content']
12
12
  }
13
- export default function MainImage({ content }: MainImageProps) {
13
+ const MainImage: React.FC<MainImageProps> = ({ content }) => {
14
14
  const references = content.body?.structured.references
15
15
 
16
16
  /* Spark publishes the MainImage at the top of the <body>. if the image is expected to be rendered at all
@@ -37,3 +37,5 @@ export default function MainImage({ content }: MainImageProps) {
37
37
 
38
38
  return null
39
39
  }
40
+
41
+ export default MainImage
@@ -5,10 +5,12 @@ export const ParagraphContext = createContext<{ className: string } | null>(
5
5
  null
6
6
  )
7
7
 
8
- export default function Paragraph(
9
- props: React.PropsWithChildren<ContentTree.Paragraph>
10
- ) {
8
+ const Paragraph: React.FC<React.PropsWithChildren<ContentTree.Paragraph>> = (
9
+ props
10
+ ) => {
11
11
  const { className } = useContext(ParagraphContext) ?? { className: undefined }
12
12
 
13
13
  return <p {...{ className }}>{props.children}</p>
14
14
  }
15
+
16
+ export default Paragraph
@@ -2,12 +2,17 @@ import React from 'react'
2
2
  import RichText from '../RichText'
3
3
  import type { BodyProps } from '../Body'
4
4
 
5
- export default function PodcastBody({
5
+ type PodcastBodyProps = BodyProps & {
6
+ showPlayer?: boolean
7
+ showAccessibilityGuide?: boolean
8
+ }
9
+
10
+ const PodcastBody: React.FC<PodcastBodyProps> = ({
6
11
  content,
7
12
  richTextComponents,
8
13
  showPlayer = true,
9
14
  showAccessibilityGuide = true,
10
- }: BodyProps & { showPlayer?: boolean; showAccessibilityGuide?: boolean }) {
15
+ }) => {
11
16
  if (content.__typename !== 'Audio') {
12
17
  return null
13
18
  }
@@ -60,3 +65,5 @@ export default function PodcastBody({
60
65
  </div>
61
66
  )
62
67
  }
68
+
69
+ export default PodcastBody
@@ -2,9 +2,9 @@ import React from 'react'
2
2
  import { ContentTreeWorkarounds } from '@financial-times/cp-content-pipeline-schema'
3
3
  import classnames from 'classnames'
4
4
 
5
- export default (
6
- props: React.PropsWithChildren<ContentTreeWorkarounds.ContentTreePullquote>
7
- ) => {
5
+ const Pullquote: React.FC<
6
+ React.PropsWithChildren<ContentTreeWorkarounds.ContentTreePullquote>
7
+ > = (props) => {
8
8
  return (
9
9
  <blockquote
10
10
  className={classnames('n-content-pullquote', {
@@ -22,3 +22,5 @@ export default (
22
22
  </blockquote>
23
23
  )
24
24
  }
25
+
26
+ export default Pullquote
@@ -10,11 +10,12 @@ import classnames from 'classnames'
10
10
  * `<Teaser>` is imported from x-dash
11
11
  * https://github.com/Financial-Times/x-dash/tree/main/components/x-teaser)
12
12
  */
13
- export default function Recommended({
13
+
14
+ const Recommended: React.FC<ContentTree.Recommended & RecommendedFragment> = ({
14
15
  heading,
15
16
  teaser,
16
17
  isInLiveBlog,
17
- }: ContentTree.Recommended & RecommendedFragment) {
18
+ }) => {
18
19
  if (!teaser) {
19
20
  return null
20
21
  }
@@ -38,3 +39,5 @@ export default function Recommended({
38
39
  </aside>
39
40
  )
40
41
  }
42
+
43
+ export default Recommended