@financial-times/cp-content-pipeline-ui 6.9.2 → 6.10.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/CHANGELOG.md +17 -0
- package/lib/components/BackToTopButton/client/index.d.ts +1 -0
- package/lib/components/BackToTopButton/client/index.js +7 -1
- package/lib/components/BackToTopButton/client/index.js.map +1 -1
- package/lib/components/Body/index.test.js +9 -0
- package/lib/components/Body/index.test.js.map +1 -1
- package/lib/components/Clip/client/index.d.ts +2 -0
- package/lib/components/Clip/client/index.js +40 -27
- package/lib/components/Clip/client/index.js.map +1 -1
- package/lib/components/Clip/components/ClipTag.js +1 -1
- package/lib/components/Clip/components/ClipTag.js.map +1 -1
- package/lib/components/Clip/components/Container.js +2 -2
- package/lib/components/Clip/components/Container.js.map +1 -1
- package/lib/components/Clip/template/index.js +0 -1
- package/lib/components/Clip/template/index.js.map +1 -1
- package/lib/components/Clip/test/index.spec.js +21 -9
- package/lib/components/Clip/test/index.spec.js.map +1 -1
- package/lib/components/Expander/client/index.d.ts +49 -0
- package/lib/components/Expander/client/index.js +124 -0
- package/lib/components/Expander/client/index.js.map +1 -0
- package/lib/components/Expander/index.d.ts +15 -0
- package/lib/components/Expander/index.js +27 -0
- package/lib/components/Expander/index.js.map +1 -0
- package/lib/components/Expander/test/client/index.spec.d.ts +1 -0
- package/lib/components/Expander/test/client/index.spec.js +103 -0
- package/lib/components/Expander/test/client/index.spec.js.map +1 -0
- package/lib/components/Expander/test/index.spec.d.ts +1 -0
- package/lib/components/Expander/test/index.spec.js +57 -0
- package/lib/components/Expander/test/index.spec.js.map +1 -0
- package/lib/components/Expander/test/snapshot.spec.d.ts +1 -0
- package/lib/components/Expander/test/snapshot.spec.js +63 -0
- package/lib/components/Expander/test/snapshot.spec.js.map +1 -0
- package/lib/components/ImageSet/index.js +1 -1
- package/lib/components/ImageSet/index.js.map +1 -1
- package/lib/components/LiveBlogPost/client/index.d.ts +4 -0
- package/lib/components/LiveBlogPost/client/index.js +19 -0
- package/lib/components/LiveBlogPost/client/index.js.map +1 -0
- package/lib/components/LiveBlogPost/index.js +9 -21
- package/lib/components/LiveBlogPost/index.js.map +1 -1
- package/lib/components/LiveBlogWrapper/index.js +1 -1
- package/lib/components/LiveBlogWrapper/index.js.map +1 -1
- package/lib/components/Recommended/index.js +1 -1
- package/lib/components/Recommended/index.js.map +1 -1
- package/lib/components/RichText/index.d.ts +1 -1
- package/lib/components/Table/index.js +1 -1
- package/lib/components/Table/index.js.map +1 -1
- package/lib/components/Video/index.js +1 -1
- package/lib/components/Video/index.js.map +1 -1
- package/lib/components/YoutubeVideo/index.js +1 -1
- package/lib/components/YoutubeVideo/index.js.map +1 -1
- package/lib/extensions/scrollIntoView.d.ts +10 -0
- package/lib/extensions/scrollIntoView.js +32 -0
- package/lib/extensions/scrollIntoView.js.map +1 -0
- package/lib/stories/Clip.stories.d.ts +2 -1
- package/lib/stories/Clip.stories.js +5 -5
- package/lib/stories/Clip.stories.js.map +1 -1
- package/lib/stories/Expander.stories.d.ts +54 -0
- package/lib/stories/Expander.stories.js +142 -0
- package/lib/stories/Expander.stories.js.map +1 -0
- package/package.json +2 -5
- package/src/components/BackToTopButton/client/index.tsx +8 -1
- package/src/components/Body/__snapshots__/index.test.tsx.snap +55 -5
- package/src/components/Body/index.test.tsx +9 -0
- package/src/components/Clip/client/index.ts +68 -26
- package/src/components/Clip/client/main.scss +27 -12
- package/src/components/Clip/components/ClipTag.tsx +0 -1
- package/src/components/Clip/components/Container.tsx +10 -3
- package/src/components/Clip/template/index.ts +0 -1
- package/src/components/Clip/test/__snapshots__/snapshot.spec.tsx.snap +8 -16
- package/src/components/Clip/test/index.spec.ts +33 -7
- package/src/components/Expander/client/index.ts +201 -0
- package/src/components/Expander/client/main.scss +162 -0
- package/src/components/Expander/index.tsx +74 -0
- package/src/components/Expander/test/__snapshots__/snapshot.spec.tsx.snap +221 -0
- package/src/components/Expander/test/client/index.spec.tsx +129 -0
- package/src/components/Expander/test/index.spec.tsx +77 -0
- package/src/components/Expander/test/snapshot.spec.tsx +73 -0
- package/src/components/ImageSet/index.tsx +1 -0
- package/src/components/LiveBlogPost/client/index.ts +16 -0
- package/src/components/LiveBlogPost/index.tsx +29 -43
- package/src/components/LiveBlogWrapper/index.tsx +1 -0
- package/src/components/Recommended/index.tsx +1 -0
- package/src/components/Table/index.tsx +1 -0
- package/src/components/Video/index.tsx +4 -1
- package/src/components/YoutubeVideo/index.tsx +4 -1
- package/src/extensions/scrollIntoView.ts +38 -0
- package/src/stories/Clip.stories.tsx +3 -2
- package/src/stories/Expander.stories.scss +3 -0
- package/src/stories/Expander.stories.tsx +159 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`Expander Snapshot component rendered on server default render 1`] = `
|
|
4
|
+
<div
|
|
5
|
+
className="cp-expander cp-expander--all-resolutions cp-expander--not-initialised"
|
|
6
|
+
data-component="expander"
|
|
7
|
+
data-state="collapsed"
|
|
8
|
+
id="test-id__container"
|
|
9
|
+
>
|
|
10
|
+
<div
|
|
11
|
+
className="cp-expander-content"
|
|
12
|
+
id="test-id"
|
|
13
|
+
>
|
|
14
|
+
<div
|
|
15
|
+
className="cp-expander__expand"
|
|
16
|
+
>
|
|
17
|
+
<a
|
|
18
|
+
aria-controls="test-id"
|
|
19
|
+
aria-expanded={false}
|
|
20
|
+
aria-hidden={false}
|
|
21
|
+
className="cp-expander__link"
|
|
22
|
+
data-action="expand"
|
|
23
|
+
data-trackable="truncated-post"
|
|
24
|
+
data-trackable-context-truncated-id="test-id"
|
|
25
|
+
data-trackable-context-truncated-post="expand"
|
|
26
|
+
href="#test-id"
|
|
27
|
+
>
|
|
28
|
+
Expand
|
|
29
|
+
</a>
|
|
30
|
+
</div>
|
|
31
|
+
<div>
|
|
32
|
+
Children 1
|
|
33
|
+
</div>
|
|
34
|
+
<div>
|
|
35
|
+
Children 2
|
|
36
|
+
</div>
|
|
37
|
+
<div
|
|
38
|
+
className="cp-expander__collapse"
|
|
39
|
+
>
|
|
40
|
+
<a
|
|
41
|
+
aria-controls="test-id"
|
|
42
|
+
aria-expanded={false}
|
|
43
|
+
aria-hidden={true}
|
|
44
|
+
className="cp-expander__link"
|
|
45
|
+
data-action="collapse"
|
|
46
|
+
data-trackable="truncated-post"
|
|
47
|
+
data-trackable-context-truncated-id="test-id"
|
|
48
|
+
data-trackable-context-truncated-post="collapse"
|
|
49
|
+
href="#test-id__container"
|
|
50
|
+
>
|
|
51
|
+
Collapse
|
|
52
|
+
</a>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
exports[`Expander Snapshot component rendered on server only on mobile 1`] = `
|
|
59
|
+
<div
|
|
60
|
+
className="cp-expander cp-expander--mobile-only cp-expander--not-initialised"
|
|
61
|
+
data-component="expander"
|
|
62
|
+
data-state="collapsed"
|
|
63
|
+
id="test-id__container"
|
|
64
|
+
>
|
|
65
|
+
<div
|
|
66
|
+
className="cp-expander-content"
|
|
67
|
+
id="test-id"
|
|
68
|
+
>
|
|
69
|
+
<div
|
|
70
|
+
className="cp-expander__expand"
|
|
71
|
+
>
|
|
72
|
+
<a
|
|
73
|
+
aria-controls="test-id"
|
|
74
|
+
aria-expanded={false}
|
|
75
|
+
aria-hidden={false}
|
|
76
|
+
className="cp-expander__link"
|
|
77
|
+
data-action="expand"
|
|
78
|
+
data-trackable="truncated-post"
|
|
79
|
+
data-trackable-context-truncated-id="test-id"
|
|
80
|
+
data-trackable-context-truncated-post="expand"
|
|
81
|
+
href="#test-id"
|
|
82
|
+
>
|
|
83
|
+
Expand
|
|
84
|
+
</a>
|
|
85
|
+
</div>
|
|
86
|
+
<div>
|
|
87
|
+
Children 1
|
|
88
|
+
</div>
|
|
89
|
+
<div>
|
|
90
|
+
Children 2
|
|
91
|
+
</div>
|
|
92
|
+
<div
|
|
93
|
+
className="cp-expander__collapse"
|
|
94
|
+
>
|
|
95
|
+
<a
|
|
96
|
+
aria-controls="test-id"
|
|
97
|
+
aria-expanded={false}
|
|
98
|
+
aria-hidden={true}
|
|
99
|
+
className="cp-expander__link"
|
|
100
|
+
data-action="collapse"
|
|
101
|
+
data-trackable="truncated-post"
|
|
102
|
+
data-trackable-context-truncated-id="test-id"
|
|
103
|
+
data-trackable-context-truncated-post="collapse"
|
|
104
|
+
href="#test-id__container"
|
|
105
|
+
>
|
|
106
|
+
Collapse
|
|
107
|
+
</a>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
exports[`Expander Snapshot component rendered on server with different labels 1`] = `
|
|
114
|
+
<div
|
|
115
|
+
className="cp-expander cp-expander--all-resolutions cp-expander--not-initialised"
|
|
116
|
+
data-component="expander"
|
|
117
|
+
data-state="collapsed"
|
|
118
|
+
id="test-id__container"
|
|
119
|
+
>
|
|
120
|
+
<div
|
|
121
|
+
className="cp-expander-content"
|
|
122
|
+
id="test-id"
|
|
123
|
+
>
|
|
124
|
+
<div
|
|
125
|
+
className="cp-expander__expand"
|
|
126
|
+
>
|
|
127
|
+
<a
|
|
128
|
+
aria-controls="test-id"
|
|
129
|
+
aria-expanded={false}
|
|
130
|
+
aria-hidden={false}
|
|
131
|
+
className="cp-expander__link"
|
|
132
|
+
data-action="expand"
|
|
133
|
+
data-trackable="truncated-post"
|
|
134
|
+
data-trackable-context-truncated-id="test-id"
|
|
135
|
+
data-trackable-context-truncated-post="expand"
|
|
136
|
+
href="#test-id"
|
|
137
|
+
>
|
|
138
|
+
Open
|
|
139
|
+
</a>
|
|
140
|
+
</div>
|
|
141
|
+
<div>
|
|
142
|
+
Children 1
|
|
143
|
+
</div>
|
|
144
|
+
<div>
|
|
145
|
+
Children 2
|
|
146
|
+
</div>
|
|
147
|
+
<div
|
|
148
|
+
className="cp-expander__collapse"
|
|
149
|
+
>
|
|
150
|
+
<a
|
|
151
|
+
aria-controls="test-id"
|
|
152
|
+
aria-expanded={false}
|
|
153
|
+
aria-hidden={true}
|
|
154
|
+
className="cp-expander__link"
|
|
155
|
+
data-action="collapse"
|
|
156
|
+
data-trackable="truncated-post"
|
|
157
|
+
data-trackable-context-truncated-id="test-id"
|
|
158
|
+
data-trackable-context-truncated-post="collapse"
|
|
159
|
+
href="#test-id__container"
|
|
160
|
+
>
|
|
161
|
+
Close
|
|
162
|
+
</a>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
`;
|
|
167
|
+
|
|
168
|
+
exports[`Expander Snapshot component rendered on server with different state 1`] = `
|
|
169
|
+
<div
|
|
170
|
+
className="cp-expander cp-expander--all-resolutions cp-expander--not-initialised"
|
|
171
|
+
data-component="expander"
|
|
172
|
+
data-state="expanded"
|
|
173
|
+
id="test-id__container"
|
|
174
|
+
>
|
|
175
|
+
<div
|
|
176
|
+
className="cp-expander-content"
|
|
177
|
+
id="test-id"
|
|
178
|
+
>
|
|
179
|
+
<div
|
|
180
|
+
className="cp-expander__expand"
|
|
181
|
+
>
|
|
182
|
+
<a
|
|
183
|
+
aria-controls="test-id"
|
|
184
|
+
aria-expanded={true}
|
|
185
|
+
aria-hidden={true}
|
|
186
|
+
className="cp-expander__link"
|
|
187
|
+
data-action="expand"
|
|
188
|
+
data-trackable="truncated-post"
|
|
189
|
+
data-trackable-context-truncated-id="test-id"
|
|
190
|
+
data-trackable-context-truncated-post="expand"
|
|
191
|
+
href="#test-id"
|
|
192
|
+
>
|
|
193
|
+
Expand
|
|
194
|
+
</a>
|
|
195
|
+
</div>
|
|
196
|
+
<div>
|
|
197
|
+
Children 1
|
|
198
|
+
</div>
|
|
199
|
+
<div>
|
|
200
|
+
Children 2
|
|
201
|
+
</div>
|
|
202
|
+
<div
|
|
203
|
+
className="cp-expander__collapse"
|
|
204
|
+
>
|
|
205
|
+
<a
|
|
206
|
+
aria-controls="test-id"
|
|
207
|
+
aria-expanded={true}
|
|
208
|
+
aria-hidden={false}
|
|
209
|
+
className="cp-expander__link"
|
|
210
|
+
data-action="collapse"
|
|
211
|
+
data-trackable="truncated-post"
|
|
212
|
+
data-trackable-context-truncated-id="test-id"
|
|
213
|
+
data-trackable-context-truncated-post="collapse"
|
|
214
|
+
href="#test-id__container"
|
|
215
|
+
>
|
|
216
|
+
Collapse
|
|
217
|
+
</a>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
`;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
import Expander, { ExpanderProps } from '../../index'
|
|
6
|
+
import { ExpanderClient } from '../../client'
|
|
7
|
+
import { render, screen } from '@testing-library/react'
|
|
8
|
+
|
|
9
|
+
//mock IntersectionObserver
|
|
10
|
+
class IntersectionObserver {
|
|
11
|
+
//mock constructor
|
|
12
|
+
constructor(callback) {
|
|
13
|
+
this.callback = callback
|
|
14
|
+
}
|
|
15
|
+
observe() {
|
|
16
|
+
this.active = true
|
|
17
|
+
}
|
|
18
|
+
disconnect() {
|
|
19
|
+
this.active = false
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
intersects() {
|
|
23
|
+
if (this.active) {
|
|
24
|
+
this.callback([{ isIntersecting: true }])
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//mock scrollIntoView
|
|
30
|
+
window.HTMLElement.prototype.scrollIntoView = jest.fn()
|
|
31
|
+
|
|
32
|
+
describe('Expander client test', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
window.IntersectionObserver = IntersectionObserver
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('find expanders markup and initialises it', () => {
|
|
38
|
+
const props: ExpanderProps = {
|
|
39
|
+
id: 'test-id',
|
|
40
|
+
}
|
|
41
|
+
render(
|
|
42
|
+
<Expander {...props}>
|
|
43
|
+
<div>Children 1</div>
|
|
44
|
+
</Expander>
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const expanders = ExpanderClient.init()
|
|
48
|
+
expect(expanders.length).toBe(1)
|
|
49
|
+
expect(
|
|
50
|
+
document.querySelectorAll("[data-component='expander']").length
|
|
51
|
+
).toBe(1)
|
|
52
|
+
expect(expanders[0].container.id).toBe('test-id__container')
|
|
53
|
+
expect(
|
|
54
|
+
expanders[0].container.classList.contains('cp-expander--initialised')
|
|
55
|
+
).toBe(true)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('does not initialise expanders twice', () => {
|
|
59
|
+
const props: ExpanderProps = {
|
|
60
|
+
id: 'test-id',
|
|
61
|
+
}
|
|
62
|
+
render(
|
|
63
|
+
<Expander {...props}>
|
|
64
|
+
<div>Children 1</div>
|
|
65
|
+
</Expander>
|
|
66
|
+
)
|
|
67
|
+
ExpanderClient.init()
|
|
68
|
+
const expanders = ExpanderClient.init()
|
|
69
|
+
|
|
70
|
+
expect(expanders.length).toBe(0)
|
|
71
|
+
expect(
|
|
72
|
+
document.querySelectorAll("[data-component='expander']").length
|
|
73
|
+
).toBe(1)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('expands and collapse', async () => {
|
|
77
|
+
const props: ExpanderProps = {
|
|
78
|
+
id: 'test-id',
|
|
79
|
+
}
|
|
80
|
+
render(
|
|
81
|
+
<Expander {...props}>
|
|
82
|
+
<div>Children 1</div>
|
|
83
|
+
</Expander>
|
|
84
|
+
)
|
|
85
|
+
const expanders = ExpanderClient.init()
|
|
86
|
+
const expanderButton = screen.getByText('Expand')
|
|
87
|
+
const collapserButton = screen.getByText('Collapse')
|
|
88
|
+
expect(expanderButton.getAttribute('aria-expanded')).toBe('false')
|
|
89
|
+
expect(expanderButton.getAttribute('aria-hidden')).toBe('false')
|
|
90
|
+
expect(collapserButton.getAttribute('aria-expanded')).toBe('false')
|
|
91
|
+
expect(collapserButton.getAttribute('aria-hidden')).toBe('true')
|
|
92
|
+
|
|
93
|
+
await expanderButton.click()
|
|
94
|
+
expect(expanderButton.getAttribute('aria-expanded')).toBe('true')
|
|
95
|
+
expect(expanders[0].container?.getAttribute('data-state')).toBe('expanded')
|
|
96
|
+
expect(expanderButton.getAttribute('aria-expanded')).toBe('true')
|
|
97
|
+
expect(expanderButton.getAttribute('aria-hidden')).toBe('true')
|
|
98
|
+
expect(collapserButton.getAttribute('aria-expanded')).toBe('true')
|
|
99
|
+
expect(collapserButton.getAttribute('aria-hidden')).toBe('false')
|
|
100
|
+
|
|
101
|
+
await collapserButton.click()
|
|
102
|
+
expect(expanders[0].container?.getAttribute('data-state')).toBe('collapsed')
|
|
103
|
+
expect(expanderButton.getAttribute('aria-expanded')).toBe('false')
|
|
104
|
+
expect(expanderButton.getAttribute('aria-hidden')).toBe('false')
|
|
105
|
+
expect(collapserButton.getAttribute('aria-expanded')).toBe('false')
|
|
106
|
+
expect(collapserButton.getAttribute('aria-hidden')).toBe('true')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('track entire read only once', () => {
|
|
110
|
+
const props: ExpanderProps = {
|
|
111
|
+
id: 'test-id',
|
|
112
|
+
}
|
|
113
|
+
render(
|
|
114
|
+
<Expander {...props}>
|
|
115
|
+
<div>Children 1</div>
|
|
116
|
+
</Expander>
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
const expanders = ExpanderClient.init()
|
|
120
|
+
const spy = jest.spyOn(document.body, 'dispatchEvent')
|
|
121
|
+
spy.mockImplementation((event) => {
|
|
122
|
+
expect(event.detail.action).toBe('entire_read')
|
|
123
|
+
})
|
|
124
|
+
expanders[0].trackingEntireRead.observer.intersects()
|
|
125
|
+
expect(spy).toHaveBeenCalledTimes(1)
|
|
126
|
+
expanders[0].trackingEntireRead.observer.intersects()
|
|
127
|
+
expect(spy).toHaveBeenCalledTimes(1)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
import Expander, { ExpanderProps } from '../index'
|
|
6
|
+
import { render, screen } from '@testing-library/react'
|
|
7
|
+
|
|
8
|
+
describe('Expander template', () => {
|
|
9
|
+
it('renders', () => {
|
|
10
|
+
const props: ExpanderProps = {
|
|
11
|
+
id: 'test-id',
|
|
12
|
+
}
|
|
13
|
+
const tree = render(
|
|
14
|
+
<Expander {...props}>
|
|
15
|
+
<div>Children 1</div>
|
|
16
|
+
<div>Children 2</div>
|
|
17
|
+
</Expander>
|
|
18
|
+
)
|
|
19
|
+
expect(
|
|
20
|
+
tree.container.querySelector('[data-component="expander"]')
|
|
21
|
+
).toBeTruthy()
|
|
22
|
+
expect(
|
|
23
|
+
tree.container.querySelector('[data-state="collapsed"]')
|
|
24
|
+
).toBeTruthy()
|
|
25
|
+
expect(
|
|
26
|
+
tree.container.querySelector('.cp-expander--not-initialised')
|
|
27
|
+
).toBeTruthy()
|
|
28
|
+
expect(screen.getByText('Expand')).toBeTruthy()
|
|
29
|
+
expect(screen.getByText('Collapse')).toBeTruthy()
|
|
30
|
+
expect(screen.getByText('Children 1')).toBeTruthy()
|
|
31
|
+
expect(screen.getByText('Children 2')).toBeTruthy()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('with different labels', () => {
|
|
35
|
+
const props: ExpanderProps = {
|
|
36
|
+
id: 'test-id',
|
|
37
|
+
collapseLabel: 'Close',
|
|
38
|
+
expandLabel: 'Open',
|
|
39
|
+
}
|
|
40
|
+
render(
|
|
41
|
+
<Expander {...props}>
|
|
42
|
+
<div>Children</div>
|
|
43
|
+
</Expander>
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
expect(screen.getByText('Open')).toBeTruthy()
|
|
47
|
+
expect(screen.getByText('Close')).toBeTruthy()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('with different state', () => {
|
|
51
|
+
const props: ExpanderProps = {
|
|
52
|
+
id: 'test-id',
|
|
53
|
+
state: 'expanded',
|
|
54
|
+
}
|
|
55
|
+
const tree = render(
|
|
56
|
+
<Expander {...props}>
|
|
57
|
+
<div>Children</div>
|
|
58
|
+
</Expander>
|
|
59
|
+
)
|
|
60
|
+
expect(tree.container.querySelector('[data-state="expanded"]')).toBeTruthy()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('add class for only mobile', () => {
|
|
64
|
+
const props: ExpanderProps = {
|
|
65
|
+
id: 'test-id',
|
|
66
|
+
onlyMobile: true,
|
|
67
|
+
}
|
|
68
|
+
const tree = render(
|
|
69
|
+
<Expander {...props}>
|
|
70
|
+
<div>Children</div>
|
|
71
|
+
</Expander>
|
|
72
|
+
)
|
|
73
|
+
expect(
|
|
74
|
+
tree.container.querySelector('.cp-expander--mobile-only')
|
|
75
|
+
).toBeTruthy()
|
|
76
|
+
})
|
|
77
|
+
})
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import renderer from 'react-test-renderer'
|
|
5
|
+
import Expander, { ExpanderProps } from '../index'
|
|
6
|
+
|
|
7
|
+
describe('Expander Snapshot', () => {
|
|
8
|
+
describe('component rendered on server', () => {
|
|
9
|
+
it('default render', () => {
|
|
10
|
+
const props: ExpanderProps = {
|
|
11
|
+
id: 'test-id',
|
|
12
|
+
}
|
|
13
|
+
const tree = renderer
|
|
14
|
+
.create(
|
|
15
|
+
<Expander {...props}>
|
|
16
|
+
<div>Children 1</div>
|
|
17
|
+
<div>Children 2</div>
|
|
18
|
+
</Expander>
|
|
19
|
+
)
|
|
20
|
+
.toJSON()
|
|
21
|
+
expect(tree).toMatchSnapshot()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('only on mobile', () => {
|
|
25
|
+
const props: ExpanderProps = {
|
|
26
|
+
id: 'test-id',
|
|
27
|
+
onlyMobile: true,
|
|
28
|
+
}
|
|
29
|
+
const tree = renderer
|
|
30
|
+
.create(
|
|
31
|
+
<Expander {...props}>
|
|
32
|
+
<div>Children 1</div>
|
|
33
|
+
<div>Children 2</div>
|
|
34
|
+
</Expander>
|
|
35
|
+
)
|
|
36
|
+
.toJSON()
|
|
37
|
+
expect(tree).toMatchSnapshot()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('with different labels', () => {
|
|
41
|
+
const props: ExpanderProps = {
|
|
42
|
+
id: 'test-id',
|
|
43
|
+
collapseLabel: 'Close',
|
|
44
|
+
expandLabel: 'Open',
|
|
45
|
+
}
|
|
46
|
+
const tree = renderer
|
|
47
|
+
.create(
|
|
48
|
+
<Expander {...props}>
|
|
49
|
+
<div>Children 1</div>
|
|
50
|
+
<div>Children 2</div>
|
|
51
|
+
</Expander>
|
|
52
|
+
)
|
|
53
|
+
.toJSON()
|
|
54
|
+
expect(tree).toMatchSnapshot()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('with different state', () => {
|
|
58
|
+
const props: ExpanderProps = {
|
|
59
|
+
id: 'test-id',
|
|
60
|
+
state: 'expanded',
|
|
61
|
+
}
|
|
62
|
+
const tree = renderer
|
|
63
|
+
.create(
|
|
64
|
+
<Expander {...props}>
|
|
65
|
+
<div>Children 1</div>
|
|
66
|
+
<div>Children 2</div>
|
|
67
|
+
</Expander>
|
|
68
|
+
)
|
|
69
|
+
.toJSON()
|
|
70
|
+
expect(tree).toMatchSnapshot()
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ExpanderClient } from '../../Expander/client'
|
|
2
|
+
|
|
3
|
+
export class LiveBlogPostClient {
|
|
4
|
+
static init() {
|
|
5
|
+
const expanders = ExpanderClient.init({
|
|
6
|
+
trackingData: { category: 'live-blog-post' },
|
|
7
|
+
})
|
|
8
|
+
expanders.forEach((expander) => {
|
|
9
|
+
expander.container?.addEventListener('expander:collapsed', () => {
|
|
10
|
+
expander?.container?.parentElement?.parentElement?.scrollIntoView()
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default LiveBlogPostClient
|
|
@@ -2,10 +2,13 @@ import React from 'react'
|
|
|
2
2
|
import ShareButtons from './ShareButtons'
|
|
3
3
|
import Timestamp from './Timestamp'
|
|
4
4
|
import RichText from '../RichText'
|
|
5
|
+
import Expander from '../Expander'
|
|
5
6
|
import classnames from 'classnames'
|
|
6
7
|
import Headshot from '../Headshot'
|
|
7
8
|
import Byline from '../Byline'
|
|
8
9
|
import { StructuredTreeFragment } from '@financial-times/cp-content-pipeline-client'
|
|
10
|
+
import parse from 'html-react-parser'
|
|
11
|
+
|
|
9
12
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
13
|
//TODO: CI-1975 remove "any" types
|
|
11
14
|
// this has been ported from x-dash, and a lot of what is expected into these arguments will take a lot of digging
|
|
@@ -14,6 +17,26 @@ type indicators = {
|
|
|
14
17
|
isOpinion?: boolean
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
const TruncatedPost = ({ id, children }: { id: string; children: any }) => {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
data-trackable="truncated-post"
|
|
24
|
+
data-trackable-context-post={id}
|
|
25
|
+
data-trackable-category="live-blog"
|
|
26
|
+
className="x-live-blog-post__body n-content-body article--body"
|
|
27
|
+
>
|
|
28
|
+
<Expander
|
|
29
|
+
expandLabel="Expand post"
|
|
30
|
+
collapseLabel="Collapse post"
|
|
31
|
+
onlyMobile={true}
|
|
32
|
+
id={`truncated-${id}`}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</Expander>
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
17
40
|
export type LiveBlogPostProps = {
|
|
18
41
|
id: string
|
|
19
42
|
postId: string // Remove once wordpress is no longer in use
|
|
@@ -39,23 +62,6 @@ export type LiveBlogPostProps = {
|
|
|
39
62
|
authors: Array<any>
|
|
40
63
|
}
|
|
41
64
|
|
|
42
|
-
const truncatedSelector = () => {
|
|
43
|
-
const prefix = '.x-live-blog-post__body >'
|
|
44
|
-
const selectors = [
|
|
45
|
-
'p',
|
|
46
|
-
'blockquote',
|
|
47
|
-
'ul',
|
|
48
|
-
'.o-table-container',
|
|
49
|
-
'.n-content-recommended--single-story',
|
|
50
|
-
"[data-layout-name='card']",
|
|
51
|
-
'.n-content-big-number',
|
|
52
|
-
'hr',
|
|
53
|
-
'.n-content-tweet',
|
|
54
|
-
"[data-layout-name='timeline']",
|
|
55
|
-
]
|
|
56
|
-
return selectors.map((item) => `${prefix} ${item}`).join(',')
|
|
57
|
-
}
|
|
58
|
-
|
|
59
65
|
const LiveBlogPost = ({
|
|
60
66
|
id,
|
|
61
67
|
postId, // Remove once wordpress is no longer in use
|
|
@@ -78,22 +84,18 @@ const LiveBlogPost = ({
|
|
|
78
84
|
const showBreakingNewsLabel = standout.breakingNews || isBreakingNews
|
|
79
85
|
|
|
80
86
|
let postBody
|
|
81
|
-
|
|
82
87
|
if (body && 'structured' in body) {
|
|
83
88
|
// Content comes from cp-content-pipeline-api
|
|
84
89
|
postBody = (
|
|
85
|
-
<
|
|
90
|
+
<TruncatedPost id={id}>
|
|
86
91
|
<RichText structuredContent={body.structured} />
|
|
87
|
-
</
|
|
92
|
+
</TruncatedPost>
|
|
88
93
|
)
|
|
89
94
|
} else {
|
|
95
|
+
const elements = bodyHTML || content ? parse(bodyHTML || content) : []
|
|
96
|
+
|
|
90
97
|
// Content comes from next-es or wordpress
|
|
91
|
-
postBody =
|
|
92
|
-
<div
|
|
93
|
-
className="x-live-blog-post__body n-content-body article--body"
|
|
94
|
-
dangerouslySetInnerHTML={{ __html: bodyHTML || content }}
|
|
95
|
-
/>
|
|
96
|
-
)
|
|
98
|
+
postBody = <TruncatedPost id={id}>{elements}</TruncatedPost>
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
const author = authors?.[0] ?? null
|
|
@@ -155,23 +157,7 @@ const LiveBlogPost = ({
|
|
|
155
157
|
<div className="x-live-blog-post__breaking-news">Breaking news</div>
|
|
156
158
|
)}
|
|
157
159
|
{title && <h2 className="x-live-blog-post__title">{title}</h2>}
|
|
158
|
-
{
|
|
159
|
-
<div
|
|
160
|
-
data-o-component="o-expander"
|
|
161
|
-
className="o-expander"
|
|
162
|
-
data-o-expander-shrink-to="1"
|
|
163
|
-
data-o-expander-item-selector={truncatedSelector()}
|
|
164
|
-
data-o-expander-collapsed-toggle-text={'Expand post'}
|
|
165
|
-
data-o-expander-expanded-toggle-text={'Collapse post'}
|
|
166
|
-
>
|
|
167
|
-
<div className="o-expander__content">{postBody}</div>
|
|
168
|
-
<a className="o-expander__toggle o-expander__text--custom">
|
|
169
|
-
<span className="o-expander__visually-hidden"> </span>
|
|
170
|
-
</a>
|
|
171
|
-
</div>
|
|
172
|
-
) : (
|
|
173
|
-
postBody
|
|
174
|
-
)}
|
|
160
|
+
{postBody}
|
|
175
161
|
<div className="x-live-blog-post__controls">
|
|
176
162
|
{showShareButtons && (
|
|
177
163
|
<ShareButtons
|
|
@@ -25,6 +25,7 @@ export default function Recommended({
|
|
|
25
25
|
className={classnames('n-content-recommended--single-story', {
|
|
26
26
|
'n-content-recommended--inset': !isInLiveBlog,
|
|
27
27
|
})}
|
|
28
|
+
data-component="recommended"
|
|
28
29
|
>
|
|
29
30
|
{!isInLiveBlog && (
|
|
30
31
|
<p className="n-content-recommended__title">{heading}</p>
|
|
@@ -8,7 +8,10 @@ export default function Video({
|
|
|
8
8
|
title,
|
|
9
9
|
}: VideoFragment & ContentTreeWorkarounds.Video) {
|
|
10
10
|
return (
|
|
11
|
-
<div
|
|
11
|
+
<div
|
|
12
|
+
className="n-content-video n-content-video--internal"
|
|
13
|
+
data-component="video"
|
|
14
|
+
>
|
|
12
15
|
<div
|
|
13
16
|
className="n-content-video__placeholder"
|
|
14
17
|
data-o-component="o-video"
|
|
@@ -13,7 +13,10 @@ export default function YoutubeVideo({
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
|
-
<div
|
|
16
|
+
<div
|
|
17
|
+
className="n-content-video n-content-video--youtube"
|
|
18
|
+
data-component="youtube-video"
|
|
19
|
+
>
|
|
17
20
|
<div className="n-content-video__placeholder">
|
|
18
21
|
<iframe
|
|
19
22
|
className="n-content-video__embedded"
|