@financial-times/cp-content-pipeline-ui 6.8.1 → 6.9.1

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.
@@ -0,0 +1,352 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Body content type override renderers renders override renderer for Article 1`] = `
4
+ <DocumentFragment>
5
+ body override Article
6
+ </DocumentFragment>
7
+ `;
8
+
9
+ exports[`Body content type override renderers renders override renderer for Audio 1`] = `
10
+ <DocumentFragment>
11
+ body override Audio
12
+ </DocumentFragment>
13
+ `;
14
+
15
+ exports[`Body content type override renderers renders override renderer for ContentPackage 1`] = `
16
+ <DocumentFragment>
17
+ body override ContentPackage
18
+ </DocumentFragment>
19
+ `;
20
+
21
+ exports[`Body content type override renderers renders override renderer for LiveBlogPackage 1`] = `
22
+ <DocumentFragment>
23
+ body override LiveBlogPackage
24
+ </DocumentFragment>
25
+ `;
26
+
27
+ exports[`Body content type override renderers renders override renderer for Video 1`] = `
28
+ <DocumentFragment>
29
+ body override Video
30
+ </DocumentFragment>
31
+ `;
32
+
33
+ exports[`Body default renderers renders default renderer for Article 1`] = `
34
+ <DocumentFragment>
35
+ <article
36
+ class="n-content-body"
37
+ >
38
+ <p>
39
+ Lorem ipsum dolor sit amet
40
+ </p>
41
+ </article>
42
+ </DocumentFragment>
43
+ `;
44
+
45
+ exports[`Body default renderers renders default renderer for Audio 1`] = `
46
+ <DocumentFragment>
47
+ <div
48
+ class="article__content-body n-content-body js-article__content-body"
49
+ data-attribute="article-content-body"
50
+ data-trackable="article-body"
51
+ >
52
+ <div
53
+ class="article__media"
54
+ >
55
+ <audio
56
+ controls=""
57
+ data-audio-subtype="podcast"
58
+ data-content-id="00000000-0000-0000-0000-000000000000"
59
+ data-dispatch-listened-event-on-unload="true"
60
+ data-o-component="o-audio"
61
+ >
62
+ <source
63
+ src="https://open.spotify.com/album/34a7B1mPM7RqlwsjPPmzEg?si=aHxMBJ1zRES6Z0iIrTrwBQ"
64
+ type="audio/mpeg"
65
+ />
66
+ <p>
67
+ Your browser does not support playing this file but you can still
68
+ <a
69
+ href="https://open.spotify.com/album/34a7B1mPM7RqlwsjPPmzEg?si=aHxMBJ1zRES6Z0iIrTrwBQ"
70
+ >
71
+ download the MP3 file
72
+ </a>
73
+ to play locally.
74
+ </p>
75
+ </audio>
76
+ </div>
77
+ <article
78
+ class="n-content-body"
79
+ >
80
+ <p>
81
+ Lorem ipsum dolor sit amet
82
+ </p>
83
+ <p>
84
+ <a
85
+ href="/accessibility#podcast-transcriptions"
86
+ >
87
+ View our accessibility guide
88
+ </a>
89
+ .
90
+ </p>
91
+ </article>
92
+ </div>
93
+ </DocumentFragment>
94
+ `;
95
+
96
+ exports[`Body default renderers renders default renderer for ContentPackage 1`] = `
97
+ <DocumentFragment>
98
+ <article
99
+ class="article n-content-body js-article__content-body n-content-body"
100
+ data-attribute="article-content-body"
101
+ data-content-id="00000000-0000-0000-0000-000000000000"
102
+ id="site-content"
103
+ role="main"
104
+ >
105
+ <div
106
+ class="package-container package-grid-1-column"
107
+ >
108
+ <div
109
+ class="package-contents package-teasers--large"
110
+ >
111
+ <ul
112
+ class="package-contents package-teasers__list"
113
+ >
114
+ <li
115
+ class="package-contents__item o-teaser-collection__item o-teaser-collection__item--stretched"
116
+ >
117
+ <div
118
+ class="o-teaser o-teaser--hero o-teaser--centre o-teaser--stretched js-teaser"
119
+ >
120
+ <div
121
+ class="o-teaser__content"
122
+ >
123
+ <div
124
+ class="o-teaser__heading"
125
+ >
126
+ <a
127
+ class="js-teaser-heading-link"
128
+ data-trackable="heading-link"
129
+ href="/content/00000000-0000-0000-0000-000000000000"
130
+ >
131
+ teaser
132
+ </a>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ </li>
137
+ </ul>
138
+ </div>
139
+ </div>
140
+ </article>
141
+ </DocumentFragment>
142
+ `;
143
+
144
+ exports[`Body default renderers renders default renderer for LiveBlogPackage 1`] = `
145
+ <DocumentFragment>
146
+ <div
147
+ class="x-live-blog-wrapper"
148
+ data-live-blog-wrapper-id="live-blog-wrapper"
149
+ >
150
+ <article
151
+ class="x-live-blog-post"
152
+ data-trackable="live-post"
153
+ data-x-component="live-blog-post"
154
+ id="post-00000000-0000-0000-0000-000000000000"
155
+ >
156
+ <div
157
+ class="x-live-blog-post__standout"
158
+ >
159
+ <span
160
+ class=""
161
+ />
162
+ <div
163
+ class="x-live-blog-post__meta-container"
164
+ >
165
+ <div
166
+ class="x-live-blog-post__meta"
167
+ >
168
+ <span>
169
+ <span
170
+ class="x-live-blog-post__timestamp-container"
171
+ >
172
+ <time
173
+ class="o-date x-live-blog-post__timestamp"
174
+ data-o-component="o-date"
175
+ data-o-date-format="time-ago-no-seconds"
176
+ data-o-date-text-case="sentence"
177
+ datetime="2024-06-11T14:13:25.527Z"
178
+ itemprop="datePublished"
179
+ >
180
+ <span
181
+ data-o-date-printer="true"
182
+ >
183
+ 6/11/2024, 2:13:25 PM
184
+ </span>
185
+ </time>
186
+ </span>
187
+ </span>
188
+ </div>
189
+ <div
190
+ class="x-live-blog-post__byline"
191
+ >
192
+ <p
193
+ class="article-info__byline"
194
+ />
195
+ </div>
196
+ </div>
197
+ </div>
198
+ <h2
199
+ class="x-live-blog-post__title"
200
+ >
201
+ live post 1
202
+ </h2>
203
+ <div
204
+ class="x-live-blog-post__body n-content-body article--body"
205
+ >
206
+ <p>
207
+ Lorem ipsum dolor sit amet
208
+ </p>
209
+ </div>
210
+ <div
211
+ class="x-live-blog-post__controls"
212
+ >
213
+ <div>
214
+ <div
215
+ class="o-share o-share--small"
216
+ data-o-component="o-share"
217
+ data-o-share-location="live-blog-post-00000000-0000-0000-0000-000000000000"
218
+ >
219
+ <ul
220
+ data-toolbar="share"
221
+ >
222
+ <li
223
+ class="o-share__action"
224
+ data-share="twitter"
225
+ >
226
+ <a
227
+ class="o-share__icon o-share__icon--x"
228
+ data-trackable="twitter"
229
+ href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.ft.com%2Fcontent%2F00000000-0000-0000-0000-000000000000%23post-00000000-0000-0000-0000-000000000000&text=live%20post%201&via=ft"
230
+ rel="noopener"
231
+ >
232
+ <div
233
+ class="o-share__icon__image"
234
+ >
235
+ <svg
236
+ viewBox="0 0 40 40"
237
+ xmlns="http://www.w3.org/2000/svg"
238
+ >
239
+ <path
240
+ 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"
241
+ />
242
+ </svg>
243
+ </div>
244
+ <span
245
+ class="o-share__text"
246
+ >
247
+ Share $live post 1 on X (opens in a new window)
248
+ </span>
249
+ </a>
250
+ </li>
251
+ <li
252
+ class="o-share__action"
253
+ data-share="facebook"
254
+ >
255
+ <a
256
+ class="o-share__icon o-share__icon--facebook"
257
+ data-trackable="facebook"
258
+ href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.ft.com%2Fcontent%2F00000000-0000-0000-0000-000000000000%23post-00000000-0000-0000-0000-000000000000&t=live%20post%201"
259
+ rel="noopener"
260
+ >
261
+ <div
262
+ class="o-share__icon__image"
263
+ >
264
+ <svg
265
+ viewBox="0 0 1024 1024"
266
+ xmlns="http://www.w3.org/2000/svg"
267
+ >
268
+ <path
269
+ 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"
270
+ />
271
+ </svg>
272
+ </div>
273
+ <span
274
+ class="o-share__text"
275
+ >
276
+ Share $live post 1 on Facebook (opens in a new window)
277
+ </span>
278
+ </a>
279
+ </li>
280
+ <li
281
+ class="o-share__action"
282
+ data-share="linkedin"
283
+ >
284
+ <a
285
+ class="o-share__icon o-share__icon--linkedin"
286
+ data-trackable="linkedin"
287
+ href="http://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.ft.com%2Fcontent%2F00000000-0000-0000-0000-000000000000%23post-00000000-0000-0000-0000-000000000000&title=live%20post%201&source=Financial+Times"
288
+ rel="noopener"
289
+ >
290
+ <div
291
+ class="o-share__icon__image"
292
+ >
293
+ <svg
294
+ viewBox="0 0 1024 1024"
295
+ xmlns="http://www.w3.org/2000/svg"
296
+ >
297
+ <path
298
+ 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"
299
+ />
300
+ </svg>
301
+ </div>
302
+ <span
303
+ class="o-share__text"
304
+ >
305
+ Share $live post 1 on LinkedIn (opens in a new window)
306
+ </span>
307
+ </a>
308
+ </li>
309
+ </ul>
310
+ </div>
311
+ </div>
312
+ </div>
313
+ </article>
314
+ </div>
315
+ </DocumentFragment>
316
+ `;
317
+
318
+ exports[`Body default renderers renders default renderer for Video 1`] = `
319
+ <DocumentFragment>
320
+ <article
321
+ class="n-content-body"
322
+ >
323
+ <p>
324
+ Lorem ipsum dolor sit amet
325
+ </p>
326
+ </article>
327
+ </DocumentFragment>
328
+ `;
329
+
330
+ exports[`Body legacy override renderers renders override renderer for Article 1`] = `
331
+ <DocumentFragment>
332
+ body override Article
333
+ </DocumentFragment>
334
+ `;
335
+
336
+ exports[`Body legacy override renderers renders override renderer for Audio 1`] = `
337
+ <DocumentFragment>
338
+ body override Audio
339
+ </DocumentFragment>
340
+ `;
341
+
342
+ exports[`Body legacy override renderers renders override renderer for ContentPackage 1`] = `
343
+ <DocumentFragment>
344
+ body override ContentPackage
345
+ </DocumentFragment>
346
+ `;
347
+
348
+ exports[`Body legacy override renderers renders override renderer for LiveBlogPackage 1`] = `
349
+ <DocumentFragment>
350
+ body override LiveBlogPackage
351
+ </DocumentFragment>
352
+ `;
@@ -0,0 +1,159 @@
1
+ import React from 'react'
2
+ import { render } from '@testing-library/react'
3
+ import Body, { BodyComponentMapRecord } from '.'
4
+ import { ArticleQuery } from '@financial-times/cp-content-pipeline-client'
5
+
6
+ const baseContent: ArticleQuery['content'] = {
7
+ __typename: 'Article',
8
+ title: 'title',
9
+ id: '00000000-0000-0000-0000-000000000000',
10
+ url: 'https://www.ft.com/content/00000000-0000-0000-0000-000000000000',
11
+ publishedDate: '2024-06-11T14:13:25.527Z',
12
+ publishedTimestamp: 1718115205527,
13
+ firstPublishedDate: '2024-06-11T14:13:25.527Z',
14
+ body: {
15
+ structured: {
16
+ tree: {
17
+ type: 'body',
18
+ version: 1,
19
+ children: [
20
+ {
21
+ type: 'paragraph',
22
+ children: [
23
+ {
24
+ type: 'text',
25
+ value: 'Lorem ipsum dolor sit amet',
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ },
31
+ references: [],
32
+ },
33
+ },
34
+ }
35
+
36
+ const extraContentForType: Partial<
37
+ Record<
38
+ ArticleQuery['content']['__typename'],
39
+ Partial<ArticleQuery['content']>
40
+ >
41
+ > = {
42
+ Audio: {
43
+ __typename: 'Audio',
44
+ media: [
45
+ {
46
+ mediaType: 'audio/mpeg',
47
+ url: 'https://open.spotify.com/album/34a7B1mPM7RqlwsjPPmzEg?si=aHxMBJ1zRES6Z0iIrTrwBQ',
48
+ },
49
+ ],
50
+ },
51
+ ContentPackage: {
52
+ __typename: 'ContentPackage',
53
+ contains: [
54
+ {
55
+ title: 'teaser',
56
+ url: 'https://www.ft.com/content/00000000-0000-0000-0000-000000000000',
57
+ relativeUrl: '/content/00000000-0000-0000-0000-000000000000',
58
+ },
59
+ ],
60
+ },
61
+ LiveBlogPackage: {
62
+ __typename: 'LiveBlogPackage',
63
+ liveBlogPosts: [
64
+ {
65
+ ...baseContent,
66
+ __typename: 'LiveBlogPost',
67
+ title: 'live post 1',
68
+ },
69
+ ],
70
+ },
71
+ Video: {
72
+ __typename: 'Video',
73
+ },
74
+ }
75
+
76
+ const extraPropsForType: Partial<
77
+ Record<ArticleQuery['content']['__typename'], Record<string, unknown>>
78
+ > = {
79
+ LiveBlogPackage: {
80
+ postTrackerConfig: {
81
+ usePostTracker: false,
82
+ },
83
+ },
84
+ }
85
+
86
+ // these are the only content types we currently care about rendering bodies for
87
+ const typesToTest: ArticleQuery['content']['__typename'][] = [
88
+ 'Article',
89
+ 'Video',
90
+ 'Audio',
91
+ 'LiveBlogPackage',
92
+ 'ContentPackage',
93
+ ]
94
+
95
+ const legacyOverridesToTest: [
96
+ ArticleQuery['content']['__typename'],
97
+ keyof BodyComponentMapRecord
98
+ ][] = [
99
+ ['Article', 'article-body'],
100
+ ['LiveBlogPackage', 'live-blog-body'],
101
+ ['ContentPackage', 'content-package-body'],
102
+ ['Audio', 'podcast-body'],
103
+ ]
104
+
105
+ describe('Body', () => {
106
+ describe('default renderers', () => {
107
+ test.each(typesToTest)('renders default renderer for %s', (type) => {
108
+ const { asFragment } = render(
109
+ <Body
110
+ content={{ ...baseContent, ...(extraContentForType[type] ?? {}) }}
111
+ {...(extraPropsForType[type] ?? {})}
112
+ />
113
+ )
114
+
115
+ expect(asFragment()).toMatchSnapshot()
116
+ })
117
+ })
118
+
119
+ describe('legacy override renderers', () => {
120
+ test.each(legacyOverridesToTest)(
121
+ 'renders override renderer for %s',
122
+ (type, overrideName) => {
123
+ const { asFragment } = render(
124
+ <Body
125
+ content={{ ...baseContent, ...(extraContentForType[type] ?? {}) }}
126
+ {...(extraPropsForType[type] ?? {})}
127
+ bodyComponents={{
128
+ [overrideName]: ({
129
+ content,
130
+ }: {
131
+ content: ArticleQuery['content']
132
+ }) => <>body override {content.__typename}</>,
133
+ }}
134
+ />
135
+ )
136
+
137
+ expect(asFragment()).toMatchSnapshot()
138
+ }
139
+ )
140
+ })
141
+
142
+ describe('content type override renderers', () => {
143
+ test.each(typesToTest)('renders override renderer for %s', (type) => {
144
+ const { asFragment } = render(
145
+ <Body
146
+ content={{ ...baseContent, ...(extraContentForType[type] ?? {}) }}
147
+ {...(extraPropsForType[type] ?? {})}
148
+ bodyComponents={{
149
+ [type]: ({ content }: { content: ArticleQuery['content'] }) => (
150
+ <>body override {content.__typename}</>
151
+ ),
152
+ }}
153
+ />
154
+ )
155
+
156
+ expect(asFragment()).toMatchSnapshot()
157
+ })
158
+ })
159
+ })
@@ -5,74 +5,74 @@ import PodcastBody from '../PodcastBody'
5
5
  import ContentPackageBody from '../ContentPackageBody'
6
6
  import type { ArticleQuery } from '@financial-times/cp-content-pipeline-client'
7
7
  import type { RichTextComponentMapRecord } from '../RichText'
8
- import type { Serialiser } from '@financial-times/x-interaction'
9
8
 
10
- type PostTrackerConfig = {
11
- usePostTracker: boolean
12
- onEntersViewport: () => void
13
- onRead: () => void
14
- onError: () => void
15
- }
16
-
17
- type BodyComponentMapRecord = Partial<
9
+ export type BodyComponentMapRecord = Partial<
18
10
  Record<
19
- 'live-blog-body' | 'article-body' | 'podcast-body' | 'content-package-body',
11
+ | ArticleQuery['content']['__typename']
12
+ // these are here for backwards compatibility:
13
+ | 'live-blog-body'
14
+ | 'article-body'
15
+ | 'podcast-body'
16
+ | 'content-package-body'
17
+ // this will be used for any content type without a default or override body
18
+ | 'fallback',
20
19
  // using any here, no easy way to make a type that works for all the potential renderers
21
20
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
21
  JSXElementConstructor<any>
23
22
  >
24
23
  >
25
24
 
25
+ const contentTypeLegacyOverrideMap: Partial<
26
+ Record<
27
+ ArticleQuery['content']['__typename'],
28
+ Exclude<
29
+ keyof BodyComponentMapRecord,
30
+ ArticleQuery['content']['__typename'] | 'fallback'
31
+ >
32
+ >
33
+ > = {
34
+ Audio: 'podcast-body',
35
+ LiveBlogPackage: 'live-blog-body',
36
+ ContentPackage: 'content-package-body',
37
+ }
38
+
39
+ const defaultBodyComponents = {
40
+ Audio: PodcastBody,
41
+ LiveBlogPackage: LiveBlogBody,
42
+ ContentPackage: ContentPackageBody,
43
+ fallback: ArticleBody,
44
+ } satisfies BodyComponentMapRecord
45
+
26
46
  export type BodyProps = {
27
47
  content: ArticleQuery['content']
28
48
  richTextComponents?: RichTextComponentMapRecord
29
49
  bodyComponents?: BodyComponentMapRecord
30
- showShareButtons?: boolean
31
- xInteractionSerialiser?: Serialiser
32
- postTrackerConfig?: PostTrackerConfig
33
- AdSlot?: React.FC
50
+ [key: string]: unknown
34
51
  }
35
52
 
36
53
  export default function Body({
37
54
  content,
38
- richTextComponents,
39
55
  bodyComponents,
40
- showShareButtons,
41
- xInteractionSerialiser,
42
- postTrackerConfig,
43
- AdSlot,
56
+ ...extraProps
44
57
  }: BodyProps) {
45
58
  if (!content?.body?.structured) {
46
59
  return null
47
60
  }
48
61
 
49
- const LiveBlog = bodyComponents?.['live-blog-body'] ?? LiveBlogBody
50
- const Article = bodyComponents?.['article-body'] ?? ArticleBody
51
- const Podcast = bodyComponents?.['podcast-body'] ?? PodcastBody
52
- const ContentPackage =
53
- bodyComponents?.['content-package-body'] ?? ContentPackageBody
54
-
55
- if (content.__typename === 'LiveBlogPackage') {
56
- return (
57
- <LiveBlog
58
- content={content}
59
- richTextComponents={richTextComponents}
60
- showShareButtons={showShareButtons}
61
- xInteractionSerialiser={xInteractionSerialiser}
62
- postTrackerConfig={postTrackerConfig}
63
- />
64
- )
65
- } else if (content.__typename === 'Audio') {
66
- return <Podcast content={content} richTextComponents={richTextComponents} />
67
- } else if (content.__typename === 'ContentPackage') {
68
- return (
69
- <ContentPackage
70
- content={content}
71
- richTextComponents={richTextComponents}
72
- AdSlot={AdSlot}
73
- />
74
- )
62
+ const bodyComponentsWithOverrides = {
63
+ ...defaultBodyComponents,
64
+ ...bodyComponents,
75
65
  }
76
66
 
77
- return <Article content={content} richTextComponents={richTextComponents} />
67
+ const legacyOverrideKey =
68
+ contentTypeLegacyOverrideMap[content.__typename] ?? 'article-body'
69
+ const overrideComponent =
70
+ legacyOverrideKey in bodyComponentsWithOverrides
71
+ ? bodyComponentsWithOverrides[legacyOverrideKey]
72
+ : bodyComponentsWithOverrides[content.__typename]
73
+
74
+ const BodyComponent =
75
+ overrideComponent ?? bodyComponentsWithOverrides.fallback ?? ArticleBody
76
+
77
+ return <BodyComponent content={content} {...extraProps} />
78
78
  }
@@ -33,11 +33,15 @@ type SecondaryTeasersProps = {
33
33
  AdSlot?: React.FC
34
34
  }
35
35
 
36
+ type ContentPackageBodyProps = BodyProps & {
37
+ AdSlot?: React.FC
38
+ }
39
+
36
40
  export default function ContentPackageBody({
37
41
  content,
38
42
  richTextComponents,
39
43
  AdSlot,
40
- }: BodyProps) {
44
+ }: ContentPackageBodyProps) {
41
45
  if (content.__typename !== 'ContentPackage') {
42
46
  return null
43
47
  }
@@ -3,11 +3,20 @@
3
3
  @include oGridRespondTo(XL) {
4
4
  max-width: oGridColspan(12);
5
5
  }
6
- margin-bottom: 0;
7
- margin-top: oSpacingByName("s4")
6
+ .flourish__i-frame {
7
+ border: 0;
8
+ @media screen and (max-width: 739px) {
9
+ // We need to enforce this otherwise it will use the inline styling
10
+ aspect-ratio: 3/4 !important;
11
+ }
12
+ }
13
+ .flourish__figure {
14
+ display: none;
15
+ }
8
16
  }
9
17
  // We need to force the iframe to be hidden if we turn the feature flag off
10
- &.disable-iframe {
18
+ &.disable-iframe,
19
+ .no-js & {
11
20
  .flourish__i-frame {
12
21
  display: none;
13
22
  }
@@ -17,22 +26,3 @@
17
26
  }
18
27
  }
19
28
  }
20
- // Without JS the i-frame will not work, so we hide it
21
- .no-js {
22
- .flourish__i-frame {
23
- display: none;
24
- }
25
- }
26
- .js {
27
- .flourish__i-frame {
28
- display: block;
29
- border: 0;
30
- @media screen and (max-width: 739px) {
31
- // We need to enforce this otherwise it will use the inline styling
32
- aspect-ratio: 3/4 !important;
33
- }
34
- }
35
- .flourish__figure {
36
- display: none;
37
- }
38
- }
@@ -11,7 +11,7 @@ interface ContentTreeLayoutSlot extends ContentTree.Node {
11
11
  }
12
12
 
13
13
  interface BaseLayoutProps {
14
- layoutWidth: 'inset-left' | 'full-width' | 'full-grid'
14
+ layoutWidth: 'inset-left' | 'full-width' | 'full-grid' | 'in-line'
15
15
  layoutName?: string
16
16
  }
17
17