@financial-times/cp-content-pipeline-ui 9.12.1 → 9.14.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 (64) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/lib/components/ContentLayout/index.d.ts +25 -0
  3. package/lib/components/ContentLayout/index.js +34 -0
  4. package/lib/components/ContentLayout/index.js.map +1 -0
  5. package/lib/components/ContentLayout/test/index.spec.d.ts +1 -0
  6. package/lib/components/ContentLayout/test/index.spec.js +57 -0
  7. package/lib/components/ContentLayout/test/index.spec.js.map +1 -0
  8. package/lib/components/ContentLayout/test/snapshot.spec.d.ts +1 -0
  9. package/lib/components/ContentLayout/test/snapshot.spec.js +33 -0
  10. package/lib/components/ContentLayout/test/snapshot.spec.js.map +1 -0
  11. package/lib/components/RichText/index.js +4 -0
  12. package/lib/components/RichText/index.js.map +1 -1
  13. package/lib/components/content-tree/Clip/components/index.d.ts +0 -2
  14. package/lib/components/content-tree/Clip/components/index.js +1 -5
  15. package/lib/components/content-tree/Clip/components/index.js.map +1 -1
  16. package/lib/components/content-tree/Clip/template/component.d.ts +1 -1
  17. package/lib/components/content-tree/Clip/template/component.js +3 -3
  18. package/lib/components/content-tree/Clip/template/component.js.map +1 -1
  19. package/lib/components/content-tree/Clip/test/snapshot.spec.js +26 -0
  20. package/lib/components/content-tree/Clip/test/snapshot.spec.js.map +1 -1
  21. package/lib/components/content-tree/Timeline/TimelineEvent.d.ts +7 -0
  22. package/lib/components/content-tree/Timeline/TimelineEvent.js +17 -0
  23. package/lib/components/content-tree/Timeline/TimelineEvent.js.map +1 -0
  24. package/lib/components/content-tree/Timeline/index.d.ts +6 -0
  25. package/lib/components/content-tree/Timeline/index.js +17 -0
  26. package/lib/components/content-tree/Timeline/index.js.map +1 -0
  27. package/lib/components/content-tree/Timeline/test/TimelineEvent.spec.d.ts +1 -0
  28. package/lib/components/content-tree/Timeline/test/TimelineEvent.spec.js +48 -0
  29. package/lib/components/content-tree/Timeline/test/TimelineEvent.spec.js.map +1 -0
  30. package/lib/components/content-tree/Timeline/test/snapshot.spec.d.ts +1 -0
  31. package/lib/components/content-tree/Timeline/test/snapshot.spec.js +17 -0
  32. package/lib/components/content-tree/Timeline/test/snapshot.spec.js.map +1 -0
  33. package/lib/index.d.ts +2 -0
  34. package/lib/index.js +5 -1
  35. package/lib/index.js.map +1 -1
  36. package/lib/main.scss +1 -0
  37. package/package.json +6 -6
  38. package/src/components/ContentLayout/index.tsx +87 -0
  39. package/src/components/ContentLayout/test/__snapshots__/index.spec.tsx.snap +96 -0
  40. package/src/components/ContentLayout/test/__snapshots__/snapshot.spec.tsx.snap +80 -0
  41. package/src/components/ContentLayout/test/index.spec.tsx +81 -0
  42. package/src/components/ContentLayout/test/snapshot.spec.tsx +47 -0
  43. package/src/components/RichText/index.tsx +4 -0
  44. package/src/components/content-tree/Clip/components/index.tsx +0 -2
  45. package/src/components/content-tree/Clip/template/component.tsx +23 -24
  46. package/src/components/content-tree/Clip/test/__snapshots__/snapshot.spec.tsx.snap +277 -0
  47. package/src/components/content-tree/Clip/test/snapshot.spec.tsx +40 -0
  48. package/src/components/content-tree/Timeline/TimelineEvent.tsx +25 -0
  49. package/src/components/content-tree/Timeline/client/main.scss +55 -0
  50. package/src/components/content-tree/Timeline/index.tsx +19 -0
  51. package/src/components/content-tree/Timeline/test/TimelineEvent.spec.tsx +66 -0
  52. package/src/components/content-tree/Timeline/test/__snapshots__/TimelineEvent.spec.tsx.snap +94 -0
  53. package/src/components/content-tree/Timeline/test/__snapshots__/snapshot.spec.tsx.snap +20 -0
  54. package/src/components/content-tree/Timeline/test/snapshot.spec.tsx +15 -0
  55. package/src/index.ts +2 -0
  56. package/tsconfig.tsbuildinfo +1 -1
  57. package/lib/components/content-tree/Clip/components/Container.d.ts +0 -6
  58. package/lib/components/content-tree/Clip/components/Container.js +0 -13
  59. package/lib/components/content-tree/Clip/components/Container.js.map +0 -1
  60. package/lib/components/content-tree/Clip/components/ContentLayout.d.ts +0 -6
  61. package/lib/components/content-tree/Clip/components/ContentLayout.js +0 -13
  62. package/lib/components/content-tree/Clip/components/ContentLayout.js.map +0 -1
  63. package/src/components/content-tree/Clip/components/Container.tsx +0 -32
  64. package/src/components/content-tree/Clip/components/ContentLayout.tsx +0 -18
@@ -1,5 +1,282 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`Clip Snapshot component rendered on server ContentLayout integration tests edge case: custom dataLayout value should wrap in ContentLayout 1`] = `
4
+ "<div class="n-content-layout__container--in-line" data-component="clip-set">
5
+ <div
6
+ data-cp-clip-layout="custom-layout"
7
+ data-cp-clip-poster=""
8
+ data-cp-clip-no-audio="false"
9
+ data-cp-clip-no-description="false"
10
+ data-cp-clip-caption=""
11
+ data-cp-clip-no-info-box="false"
12
+ data-cp-clip-no-caption="false"
13
+ data-cp-clip-closed-caption="false"
14
+ class="cp-clip"
15
+ data-trackable="next-article-cp-clip"
16
+ data-o-component="cp-clip"
17
+ data-cp-clip-id="localhost:8080/fakevideo.mpg"
18
+ data-cp-clip-system-title=""
19
+ id=""
20
+ >
21
+ <div
22
+ data-o-component="o-expander"
23
+ class="o-expander o-expander__info-box"
24
+ data-o-expander-shrink-to="hidden"
25
+ data-trackable="clip-info-box"
26
+ data-o-expander-collapsed-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Show video info&lt;/span&gt;"
27
+ data-o-expander-expanded-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Hide video info&lt;/span&gt;"
28
+ >
29
+ <button
30
+ data-trackable="toggle-open-close"
31
+ class="o-expander__toggle o-expander__toggle-empty"
32
+ >
33
+ <span class="o-expander__visually-hidden o3-type-detail"
34
+ >Show video info</span
35
+ >
36
+ </button>
37
+ <div class="o-expander__content video-info"></div>
38
+ </div>
39
+ <div class="cp-clip__video-container">
40
+ <video
41
+ class="cp-clip__video"
42
+ controls=""
43
+ controlsList="nodownload noremoteplayback noplaybackrate"
44
+ disablepictureinpicture=""
45
+ disableremoteplayback=""
46
+ playsinline=""
47
+ poster=""
48
+ preload="auto"
49
+ id="clip-localhost:8080/fakevideo.mpg"
50
+ crossorigin="anonymous"
51
+ style="height: fit-content; width: 100%"
52
+ >
53
+ <source
54
+ id="video-source-0-localhost:8080/fakevideo.mpg"
55
+ data-cp-component="cp-clip__video-source"
56
+ src="localhost:8080/fakevideo.mpg"
57
+ type="video/mp4"
58
+ />
59
+ </video>
60
+ </div>
61
+ <div
62
+ class="cp-clip__video-meta-info"
63
+ data-cp-clip-video-meta-info="true"
64
+ ></div>
65
+ </div>
66
+ </div>
67
+ "
68
+ `;
69
+
70
+ exports[`Clip Snapshot component rendered on server ContentLayout integration tests full-grid default render - should wrap in ContentLayout with proper classes 1`] = `
71
+ "<div class="n-content-layout" data-layout-width="full-grid">
72
+ <div class="n-content-layout__container" data-component="clip-set">
73
+ <div
74
+ data-cp-clip-layout="full-grid"
75
+ data-cp-clip-poster=""
76
+ data-cp-clip-no-audio="false"
77
+ data-cp-clip-no-description="false"
78
+ data-cp-clip-caption=""
79
+ data-cp-clip-no-info-box="false"
80
+ data-cp-clip-no-caption="false"
81
+ data-cp-clip-closed-caption="false"
82
+ class="cp-clip"
83
+ data-trackable="next-article-cp-clip"
84
+ data-o-component="cp-clip"
85
+ data-cp-clip-id="localhost:8080/fakevideo.mpg"
86
+ data-cp-clip-system-title=""
87
+ id=""
88
+ >
89
+ <div
90
+ data-o-component="o-expander"
91
+ class="o-expander o-expander__info-box"
92
+ data-o-expander-shrink-to="hidden"
93
+ data-trackable="clip-info-box"
94
+ data-o-expander-collapsed-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Show video info&lt;/span&gt;"
95
+ data-o-expander-expanded-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Hide video info&lt;/span&gt;"
96
+ >
97
+ <button
98
+ data-trackable="toggle-open-close"
99
+ class="o-expander__toggle o-expander__toggle-empty"
100
+ >
101
+ <span class="o-expander__visually-hidden o3-type-detail"
102
+ >Show video info</span
103
+ >
104
+ </button>
105
+ <div class="o-expander__content video-info"></div>
106
+ </div>
107
+ <div class="cp-clip__video-container">
108
+ <video
109
+ class="cp-clip__video"
110
+ controls=""
111
+ controlsList="nodownload noremoteplayback noplaybackrate"
112
+ disablepictureinpicture=""
113
+ disableremoteplayback=""
114
+ playsinline=""
115
+ poster=""
116
+ preload="auto"
117
+ id="clip-localhost:8080/fakevideo.mpg"
118
+ crossorigin="anonymous"
119
+ style="height: fit-content; width: 100%"
120
+ >
121
+ <source
122
+ id="video-source-0-localhost:8080/fakevideo.mpg"
123
+ data-cp-component="cp-clip__video-source"
124
+ src="localhost:8080/fakevideo.mpg"
125
+ type="video/mp4"
126
+ />
127
+ </video>
128
+ </div>
129
+ <div
130
+ class="cp-clip__video-meta-info"
131
+ data-cp-clip-video-meta-info="true"
132
+ ></div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ "
137
+ `;
138
+
139
+ exports[`Clip Snapshot component rendered on server ContentLayout integration tests in-line render - should not wrap in ContentLayout div 1`] = `
140
+ "<div class="n-content-layout__container--in-line" data-component="clip-set">
141
+ <div
142
+ data-cp-clip-layout="in-line"
143
+ data-cp-clip-poster=""
144
+ data-cp-clip-no-audio="false"
145
+ data-cp-clip-no-description="false"
146
+ data-cp-clip-caption=""
147
+ data-cp-clip-no-info-box="false"
148
+ data-cp-clip-no-caption="false"
149
+ data-cp-clip-closed-caption="false"
150
+ class="cp-clip"
151
+ data-trackable="next-article-cp-clip"
152
+ data-o-component="cp-clip"
153
+ data-cp-clip-id="localhost:8080/fakevideo.mpg"
154
+ data-cp-clip-system-title=""
155
+ id=""
156
+ >
157
+ <div
158
+ data-o-component="o-expander"
159
+ class="o-expander o-expander__info-box"
160
+ data-o-expander-shrink-to="hidden"
161
+ data-trackable="clip-info-box"
162
+ data-o-expander-collapsed-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Show video info&lt;/span&gt;"
163
+ data-o-expander-expanded-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Hide video info&lt;/span&gt;"
164
+ >
165
+ <button
166
+ data-trackable="toggle-open-close"
167
+ class="o-expander__toggle o-expander__toggle-empty"
168
+ >
169
+ <span class="o-expander__visually-hidden o3-type-detail"
170
+ >Show video info</span
171
+ >
172
+ </button>
173
+ <div class="o-expander__content video-info"></div>
174
+ </div>
175
+ <div class="cp-clip__video-container">
176
+ <video
177
+ class="cp-clip__video"
178
+ controls=""
179
+ controlsList="nodownload noremoteplayback noplaybackrate"
180
+ disablepictureinpicture=""
181
+ disableremoteplayback=""
182
+ playsinline=""
183
+ poster=""
184
+ preload="auto"
185
+ id="clip-localhost:8080/fakevideo.mpg"
186
+ crossorigin="anonymous"
187
+ style="height: fit-content; width: 100%"
188
+ >
189
+ <source
190
+ id="video-source-0-localhost:8080/fakevideo.mpg"
191
+ data-cp-component="cp-clip__video-source"
192
+ src="localhost:8080/fakevideo.mpg"
193
+ type="video/mp4"
194
+ />
195
+ </video>
196
+ </div>
197
+ <div
198
+ class="cp-clip__video-meta-info"
199
+ data-cp-clip-video-meta-info="true"
200
+ ></div>
201
+ </div>
202
+ </div>
203
+ "
204
+ `;
205
+
206
+ exports[`Clip Snapshot component rendered on server ContentLayout integration tests mid-grid default render - should wrap in ContentLayout with nested Container structure 1`] = `
207
+ "<div class="n-content-layout" data-layout-width="full-grid">
208
+ <div class="n-content-layout__container" data-component="clip-set">
209
+ <div
210
+ data-o-grid-colspan="12 S12 M12 L10 XL10"
211
+ class="n-content-layout__container--mid-grid"
212
+ >
213
+ <div
214
+ data-cp-clip-layout="mid-grid"
215
+ data-cp-clip-poster=""
216
+ data-cp-clip-no-audio="false"
217
+ data-cp-clip-no-description="false"
218
+ data-cp-clip-caption=""
219
+ data-cp-clip-no-info-box="false"
220
+ data-cp-clip-no-caption="false"
221
+ data-cp-clip-closed-caption="false"
222
+ class="cp-clip"
223
+ data-trackable="next-article-cp-clip"
224
+ data-o-component="cp-clip"
225
+ data-cp-clip-id="localhost:8080/fakevideo.mpg"
226
+ data-cp-clip-system-title=""
227
+ id=""
228
+ >
229
+ <div
230
+ data-o-component="o-expander"
231
+ class="o-expander o-expander__info-box"
232
+ data-o-expander-shrink-to="hidden"
233
+ data-trackable="clip-info-box"
234
+ data-o-expander-collapsed-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Show video info&lt;/span&gt;"
235
+ data-o-expander-expanded-toggle-text="&lt;span class=&#x27;o-expander__visually-hidden&#x27;&gt;Hide video info&lt;/span&gt;"
236
+ >
237
+ <button
238
+ data-trackable="toggle-open-close"
239
+ class="o-expander__toggle o-expander__toggle-empty"
240
+ >
241
+ <span class="o-expander__visually-hidden o3-type-detail"
242
+ >Show video info</span
243
+ >
244
+ </button>
245
+ <div class="o-expander__content video-info"></div>
246
+ </div>
247
+ <div class="cp-clip__video-container">
248
+ <video
249
+ class="cp-clip__video"
250
+ controls=""
251
+ controlsList="nodownload noremoteplayback noplaybackrate"
252
+ disablepictureinpicture=""
253
+ disableremoteplayback=""
254
+ playsinline=""
255
+ poster=""
256
+ preload="auto"
257
+ id="clip-localhost:8080/fakevideo.mpg"
258
+ crossorigin="anonymous"
259
+ style="height: fit-content; width: 100%"
260
+ >
261
+ <source
262
+ id="video-source-0-localhost:8080/fakevideo.mpg"
263
+ data-cp-component="cp-clip__video-source"
264
+ src="localhost:8080/fakevideo.mpg"
265
+ type="video/mp4"
266
+ />
267
+ </video>
268
+ </div>
269
+ <div
270
+ class="cp-clip__video-meta-info"
271
+ data-cp-clip-video-meta-info="true"
272
+ ></div>
273
+ </div>
274
+ </div>
275
+ </div>
276
+ </div>
277
+ "
278
+ `;
279
+
3
280
  exports[`Clip Snapshot component rendered on server full-grid default render 1`] = `
4
281
  "<div class="n-content-layout" data-layout-width="full-grid">
5
282
  <div class="n-content-layout__container" data-component="clip-set">
@@ -25,6 +25,46 @@ describe('Clip Snapshot', () => {
25
25
  const url = 'localhost:8080/fakevideo.mpg'
26
26
  const poster = 'localhost:8080/fakeposter.jpg'
27
27
 
28
+ describe('ContentLayout integration tests', () => {
29
+ it('in-line render - should not wrap in ContentLayout div', () => {
30
+ const tree = renderer
31
+ .create(
32
+ <ClipServer content={{ url, dataLayout: 'in-line' }}></ClipServer>
33
+ )
34
+ .toJSON()
35
+ expect(formatString(tree)).toMatchSnapshot()
36
+ })
37
+
38
+ it('full-grid default render - should wrap in ContentLayout with proper classes', () => {
39
+ const tree = renderer
40
+ .create(
41
+ <ClipServer content={{ url, dataLayout: 'full-grid' }}></ClipServer>
42
+ )
43
+ .toJSON()
44
+ expect(formatString(tree)).toMatchSnapshot()
45
+ })
46
+
47
+ it('mid-grid default render - should wrap in ContentLayout with nested Container structure', () => {
48
+ const tree = renderer
49
+ .create(
50
+ <ClipServer content={{ url, dataLayout: 'mid-grid' }}></ClipServer>
51
+ )
52
+ .toJSON()
53
+ expect(formatString(tree)).toMatchSnapshot()
54
+ })
55
+
56
+ it('edge case: custom dataLayout value should wrap in ContentLayout', () => {
57
+ const tree = renderer
58
+ .create(
59
+ <ClipServer
60
+ content={{ url, dataLayout: 'custom-layout' }}
61
+ ></ClipServer>
62
+ )
63
+ .toJSON()
64
+ expect(formatString(tree)).toMatchSnapshot()
65
+ })
66
+ })
67
+
28
68
  it('in-line render', () => {
29
69
  const tree = renderer
30
70
  .create(
@@ -0,0 +1,25 @@
1
+ import { ContentTree } from '@financial-times/content-tree'
2
+ import React from 'react'
3
+ import { ContentProps } from '../../types'
4
+
5
+ interface TimelineEventProps
6
+ extends ContentProps<Omit<ContentTree.TimelineEvent, 'children'>> {}
7
+
8
+ /*
9
+ * @description Event component is used to render a single event.
10
+ */
11
+ const TimelineEvent: React.FC<React.PropsWithChildren<TimelineEventProps>> = ({
12
+ content: { title },
13
+ children,
14
+ }) => {
15
+ return (
16
+ <div className="cp-timeline-event">
17
+ <h5 className="cp-timeline-event__heading o3-type-label">
18
+ <span className="cp-timeline-event__heading-title">{title}</span>
19
+ </h5>
20
+ {children}
21
+ </div>
22
+ )
23
+ }
24
+
25
+ export default TimelineEvent
@@ -0,0 +1,55 @@
1
+ @import "@financial-times/o3-foundation/css/core.css";
2
+
3
+ .cp-timeline {
4
+ display: flex;
5
+ flex-direction: column;
6
+
7
+ .cp-timeline-event {
8
+ flex-basis: 100%;
9
+ padding-left: var(--o3-spacing-s);
10
+ margin-left: 0;
11
+ margin-top: 0;
12
+ margin-bottom: 0;
13
+ position: relative;
14
+
15
+ &::before {
16
+ content: "";
17
+ width: 2px;
18
+ background: var(--o3-color-palette-black);
19
+ height: 100%;
20
+ display: block;
21
+ position: absolute;
22
+ left: var(--o3-spacing-5xs);
23
+ top: 0;
24
+ }
25
+
26
+ .cp-timeline-event__heading {
27
+ position: relative;
28
+ margin-top: var(--o3-spacing-s);
29
+ margin-bottom: var(--o3-spacing-5xs);
30
+
31
+ .cp-timeline-event__heading-title {
32
+ font-weight: var(--o3-font-weight-semibold);
33
+ &::before {
34
+ content: "";
35
+ position: absolute;
36
+ top: 6px;
37
+ left: -23px;
38
+ height: var(--o3-spacing-4xs);
39
+ width: var(--o3-spacing-4xs);
40
+ border-radius: 50%;
41
+ background-color: var(--o3-color-palette-black);
42
+ }
43
+ }
44
+ }
45
+
46
+ p {
47
+ margin-bottom: var(--o3-spacing-4xs);
48
+ margin-top: var(--o3-spacing-5xs);
49
+ font-family: var(--o3-type-body-base-font-family);
50
+ font-size: var(--o3-type-body-base-font-size);
51
+ font-weight: var(--o3-type-body-base-font-weight);
52
+ line-height: var(--o3-type-body-base-line-height);
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+ import { ContentLayout } from '../../ContentLayout'
3
+
4
+ interface TimelineProps {
5
+ children?: React.ReactNode
6
+ }
7
+ /*
8
+ * @description Timeline component is used to render a simple timeline of events.
9
+ * @param children - The content to be displayed in the layout.
10
+ */
11
+ const Timeline: React.FC<TimelineProps> = ({ children }) => {
12
+ return (
13
+ <ContentLayout>
14
+ <div className="cp-timeline">{children}</div>
15
+ </ContentLayout>
16
+ )
17
+ }
18
+
19
+ export default Timeline
@@ -0,0 +1,66 @@
1
+ import React from 'react'
2
+ import { render } from '@testing-library/react'
3
+ import TimelineEvent from '../TimelineEvent'
4
+
5
+ describe('TimelineEvent', () => {
6
+ it('renders with date label and children', () => {
7
+ const { container } = render(
8
+ <TimelineEvent
9
+ content={{
10
+ type: 'timeline-event',
11
+ title: 'Significant Event',
12
+ }}
13
+ >
14
+ <p>This is the event content</p>
15
+ </TimelineEvent>
16
+ )
17
+ expect(container).toMatchSnapshot()
18
+ })
19
+
20
+ it('renders with minimal children content', () => {
21
+ const { container } = render(
22
+ <TimelineEvent
23
+ content={{
24
+ type: 'timeline-event',
25
+ title: 'Short Event',
26
+ }}
27
+ >
28
+ <p>Brief event description</p>
29
+ </TimelineEvent>
30
+ )
31
+ expect(container).toMatchSnapshot()
32
+ })
33
+
34
+ it('renders with long date label', () => {
35
+ const { container } = render(
36
+ <TimelineEvent
37
+ content={{
38
+ type: 'timeline-event',
39
+ title: 'Wednesday, December 25, 2024 - Christmas Day',
40
+ }}
41
+ >
42
+ <p>Christmas celebration details</p>
43
+ </TimelineEvent>
44
+ )
45
+ expect(container).toMatchSnapshot()
46
+ })
47
+
48
+ it('renders with complex nested children', () => {
49
+ const { container } = render(
50
+ <TimelineEvent
51
+ content={{
52
+ type: 'timeline-event',
53
+ title: 'Q4 2024',
54
+ }}
55
+ >
56
+ <div>
57
+ <h3>Quarterly Results</h3>
58
+ <p>
59
+ The company announced <strong>strong</strong> Q4 results.
60
+ </p>
61
+ </div>
62
+ </TimelineEvent>
63
+ )
64
+ expect(container).toMatchSnapshot()
65
+ })
66
+ })
@@ -0,0 +1,94 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`TimelineEvent renders with complex nested children 1`] = `
4
+ <div>
5
+ <div
6
+ class="cp-timeline-event"
7
+ >
8
+ <h5
9
+ class="cp-timeline-event__heading o3-type-label"
10
+ >
11
+ <span
12
+ class="cp-timeline-event__heading-title"
13
+ >
14
+ Q4 2024
15
+ </span>
16
+ </h5>
17
+ <div>
18
+ <h3>
19
+ Quarterly Results
20
+ </h3>
21
+ <p>
22
+ The company announced
23
+ <strong>
24
+ strong
25
+ </strong>
26
+ Q4 results.
27
+ </p>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ `;
32
+
33
+ exports[`TimelineEvent renders with date label and children 1`] = `
34
+ <div>
35
+ <div
36
+ class="cp-timeline-event"
37
+ >
38
+ <h5
39
+ class="cp-timeline-event__heading o3-type-label"
40
+ >
41
+ <span
42
+ class="cp-timeline-event__heading-title"
43
+ >
44
+ Significant Event
45
+ </span>
46
+ </h5>
47
+ <p>
48
+ This is the event content
49
+ </p>
50
+ </div>
51
+ </div>
52
+ `;
53
+
54
+ exports[`TimelineEvent renders with long date label 1`] = `
55
+ <div>
56
+ <div
57
+ class="cp-timeline-event"
58
+ >
59
+ <h5
60
+ class="cp-timeline-event__heading o3-type-label"
61
+ >
62
+ <span
63
+ class="cp-timeline-event__heading-title"
64
+ >
65
+ Wednesday, December 25, 2024 - Christmas Day
66
+ </span>
67
+ </h5>
68
+ <p>
69
+ Christmas celebration details
70
+ </p>
71
+ </div>
72
+ </div>
73
+ `;
74
+
75
+ exports[`TimelineEvent renders with minimal children content 1`] = `
76
+ <div>
77
+ <div
78
+ class="cp-timeline-event"
79
+ >
80
+ <h5
81
+ class="cp-timeline-event__heading o3-type-label"
82
+ >
83
+ <span
84
+ class="cp-timeline-event__heading-title"
85
+ >
86
+ Short Event
87
+ </span>
88
+ </h5>
89
+ <p>
90
+ Brief event description
91
+ </p>
92
+ </div>
93
+ </div>
94
+ `;
@@ -0,0 +1,20 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Timeline component renders with full-width layout and children 1`] = `
4
+ <div>
5
+ <div
6
+ class="n-content-layout__container--in-line"
7
+ >
8
+ <div
9
+ class="cp-timeline"
10
+ >
11
+ <div>
12
+ Event 1
13
+ </div>
14
+ <div>
15
+ Event 2
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ `;
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+ import { render } from '@testing-library/react'
3
+ import Timeline from '../'
4
+
5
+ describe('Timeline component', () => {
6
+ it('renders with full-width layout and children', () => {
7
+ const { container } = render(
8
+ <Timeline>
9
+ <div>Event 1</div>
10
+ <div>Event 2</div>
11
+ </Timeline>
12
+ )
13
+ expect(container).toMatchSnapshot()
14
+ })
15
+ })
package/src/index.ts CHANGED
@@ -30,6 +30,8 @@ export { default as Table } from './components/content-tree/Table'
30
30
  export { default as Tweet } from './components/content-tree/Tweet'
31
31
  export { default as Video } from './components/content-tree/Video'
32
32
  export { default as YoutubeVideo } from './components/content-tree/YoutubeVideo'
33
+ export { default as Timeline } from './components/content-tree/Timeline'
34
+ export { default as TimelineEvent } from './components/content-tree/Timeline/TimelineEvent'
33
35
  export {
34
36
  List,
35
37
  ListItem,