@financial-times/cp-content-pipeline-ui 6.7.0 → 6.8.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 +38 -0
- package/lib/components/Clip/client/progressBar.js +2 -10
- package/lib/components/Clip/client/progressBar.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 +1 -0
- package/lib/components/Clip/template/index.js.map +1 -1
- package/lib/components/ImageSet/index.js +1 -1
- package/lib/components/ImageSet/index.js.map +1 -1
- package/lib/components/LiveBlogPost/index.js +21 -9
- 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/PartnerContentHeader/index.d.ts +5 -0
- package/lib/components/PartnerContentHeader/index.js +14 -0
- package/lib/components/PartnerContentHeader/index.js.map +1 -0
- 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/Topper/index.js +51 -24
- package/lib/components/Topper/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/stories/Clip.stories.d.ts +1 -2
- package/lib/stories/Clip.stories.js +5 -5
- package/lib/stories/Clip.stories.js.map +1 -1
- package/package.json +5 -2
- package/src/components/Clip/client/main.scss +2 -2
- package/src/components/Clip/client/progressBar.scss +8 -14
- package/src/components/Clip/client/progressBar.ts +2 -8
- package/src/components/Clip/components/Container.tsx +3 -10
- package/src/components/Clip/template/index.ts +1 -0
- package/src/components/Clip/test/__snapshots__/snapshot.spec.tsx.snap +8 -8
- package/src/components/ImageSet/index.tsx +0 -1
- package/src/components/LiveBlogPost/index.tsx +42 -29
- package/src/components/LiveBlogWrapper/index.tsx +0 -1
- package/src/components/PartnerContentHeader/index.tsx +15 -0
- package/src/components/Recommended/index.tsx +0 -1
- package/src/components/Table/index.tsx +0 -1
- package/src/components/Topper/index.tsx +97 -91
- package/src/components/Video/index.tsx +1 -4
- package/src/components/YoutubeVideo/index.tsx +1 -4
- package/src/stories/Clip.stories.tsx +2 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/components/Expander/client/index.d.ts +0 -49
- package/lib/components/Expander/client/index.js +0 -124
- package/lib/components/Expander/client/index.js.map +0 -1
- package/lib/components/Expander/index.d.ts +0 -15
- package/lib/components/Expander/index.js +0 -27
- package/lib/components/Expander/index.js.map +0 -1
- package/lib/components/Expander/test/client/index.spec.d.ts +0 -1
- package/lib/components/Expander/test/client/index.spec.js +0 -103
- package/lib/components/Expander/test/client/index.spec.js.map +0 -1
- package/lib/components/Expander/test/index.spec.d.ts +0 -1
- package/lib/components/Expander/test/index.spec.js +0 -57
- package/lib/components/Expander/test/index.spec.js.map +0 -1
- package/lib/components/Expander/test/snapshot.spec.d.ts +0 -1
- package/lib/components/Expander/test/snapshot.spec.js +0 -63
- package/lib/components/Expander/test/snapshot.spec.js.map +0 -1
- package/lib/components/LiveBlogPost/client/index.d.ts +0 -5
- package/lib/components/LiveBlogPost/client/index.js +0 -12
- package/lib/components/LiveBlogPost/client/index.js.map +0 -1
- package/lib/stories/Expander.stories.d.ts +0 -54
- package/lib/stories/Expander.stories.js +0 -142
- package/lib/stories/Expander.stories.js.map +0 -1
- package/src/components/Expander/client/index.ts +0 -197
- package/src/components/Expander/client/main.scss +0 -162
- package/src/components/Expander/index.tsx +0 -74
- package/src/components/Expander/test/__snapshots__/snapshot.spec.tsx.snap +0 -225
- package/src/components/Expander/test/client/index.spec.tsx +0 -129
- package/src/components/Expander/test/index.spec.tsx +0 -77
- package/src/components/Expander/test/snapshot.spec.tsx +0 -73
- package/src/components/LiveBlogPost/client/index.ts +0 -9
- package/src/stories/Expander.stories.scss +0 -3
- package/src/stories/Expander.stories.tsx +0 -159
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.OnlyMobileServer = exports.OnlyMobileWithClient = exports.WithClient = exports.OnlyServer = void 0;
|
|
30
|
-
const Expander_1 = require("../components/Expander");
|
|
31
|
-
const client_1 = require("../components/Expander/client");
|
|
32
|
-
const react_1 = __importStar(require("react"));
|
|
33
|
-
const main_1 = __importDefault(require("@financial-times/o-tracking/main"));
|
|
34
|
-
require("./Expander.stories.scss");
|
|
35
|
-
const client_2 = __importDefault(require("../components/Clip/client"));
|
|
36
|
-
require("./Clip.stories.scss");
|
|
37
|
-
const RichText_1 = __importDefault(require("../components/RichText"));
|
|
38
|
-
const structuredContent = {
|
|
39
|
-
type: 'body',
|
|
40
|
-
version: 1,
|
|
41
|
-
children: [
|
|
42
|
-
{
|
|
43
|
-
type: 'paragraph',
|
|
44
|
-
children: [
|
|
45
|
-
{
|
|
46
|
-
type: 'text',
|
|
47
|
-
value: 'Mike Johnson has survived an attempt to oust him as speaker of the House of Representatives by Marjorie Taylor Greene, a hardline Republican congresswoman from Georgia. ',
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
type: 'paragraph',
|
|
53
|
-
children: [
|
|
54
|
-
{
|
|
55
|
-
type: 'text',
|
|
56
|
-
value: 'In a vote on Wednesday night, the lower chamber of Congress rejected Greene’s bid with overwhelming support from Democrats as well as Republicans. ',
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
},
|
|
60
|
-
,
|
|
61
|
-
{
|
|
62
|
-
type: 'paragraph',
|
|
63
|
-
children: [
|
|
64
|
-
{
|
|
65
|
-
type: 'text',
|
|
66
|
-
value: 'The vote all but ensures that Johnson will remain in his post until after the November election, and will put a lid on a debate over his political future that has lasted for weeks among Republicans in Congress. ',
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
type: 'clip-set',
|
|
72
|
-
id: 'http://api.ft.com/content/23a00095-d9fc-4cac-ad7c-477e61e3c159',
|
|
73
|
-
autoplay: false,
|
|
74
|
-
loop: false,
|
|
75
|
-
muted: false,
|
|
76
|
-
dataLayout: 'in-line',
|
|
77
|
-
data: {
|
|
78
|
-
referenceIndex: 3,
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
};
|
|
83
|
-
const storyArgs = {
|
|
84
|
-
expandLabel: 'Open',
|
|
85
|
-
collapseLabel: 'Close',
|
|
86
|
-
onlyMobile: false,
|
|
87
|
-
id: '111232323-12123-2323',
|
|
88
|
-
};
|
|
89
|
-
exports.default = {
|
|
90
|
-
title: 'Expander',
|
|
91
|
-
component: Expander_1.ExpanderServer,
|
|
92
|
-
tags: ['autodocs'],
|
|
93
|
-
};
|
|
94
|
-
const LiveBLogWrapper = (args) => {
|
|
95
|
-
const { classNames } = args;
|
|
96
|
-
return (react_1.default.createElement("div", { className: classNames },
|
|
97
|
-
react_1.default.createElement("article", { id: "site-content", role: "main", className: "article article-grid article-grid--no-full-width-graphics js enhanced", "data-article-type": "no-full-width-graphics" },
|
|
98
|
-
react_1.default.createElement("div", { className: "article__content", "data-trackable": "article-body", "data-component": "article-body", style: { position: 'relative' } },
|
|
99
|
-
react_1.default.createElement("div", { className: "article__content-body n-content-body js-article__content-body", "data-attribute": "article-content-body" },
|
|
100
|
-
react_1.default.createElement(LiveBlogPostWrapper, { ...args, id: "111" }))),
|
|
101
|
-
react_1.default.createElement("div", { className: "article__right " }))));
|
|
102
|
-
};
|
|
103
|
-
const LiveBlogPostWrapper = (args) => {
|
|
104
|
-
(0, react_1.useEffect)(() => {
|
|
105
|
-
main_1.default.init({
|
|
106
|
-
context: { product: 'next' },
|
|
107
|
-
test: true,
|
|
108
|
-
});
|
|
109
|
-
const clips = client_2.default.init(null, {});
|
|
110
|
-
return () => {
|
|
111
|
-
clips.forEach((clip) => clip.unload());
|
|
112
|
-
};
|
|
113
|
-
}, []);
|
|
114
|
-
return (react_1.default.createElement("article", { id: args.id },
|
|
115
|
-
react_1.default.createElement("div", { className: "n-content-body" },
|
|
116
|
-
react_1.default.createElement("div", { "data-trackable": "truncated-post", "data-trackable-context-post": "1234", "data-component": "example-boundary" },
|
|
117
|
-
react_1.default.createElement(Expander_1.ExpanderServer, { ...args, id: `${args.id}_expander` },
|
|
118
|
-
react_1.default.createElement(RichText_1.default, { structuredContent: { tree: structuredContent } }))))));
|
|
119
|
-
};
|
|
120
|
-
const OnlyServer = (args) => {
|
|
121
|
-
return react_1.default.createElement(LiveBLogWrapper, { ...args });
|
|
122
|
-
};
|
|
123
|
-
exports.OnlyServer = OnlyServer;
|
|
124
|
-
exports.OnlyServer.args = { ...storyArgs };
|
|
125
|
-
const WithClient = (args) => {
|
|
126
|
-
(0, react_1.useEffect)(() => {
|
|
127
|
-
const clips = client_2.default.init(null, {});
|
|
128
|
-
const expanders = client_1.ExpanderClient.init();
|
|
129
|
-
return () => {
|
|
130
|
-
clips.forEach((clip) => clip.unload());
|
|
131
|
-
expanders.forEach((expander) => expander?.destroy());
|
|
132
|
-
};
|
|
133
|
-
}, []);
|
|
134
|
-
return react_1.default.createElement(LiveBLogWrapper, { ...args });
|
|
135
|
-
};
|
|
136
|
-
exports.WithClient = WithClient;
|
|
137
|
-
exports.WithClient.args = { ...storyArgs };
|
|
138
|
-
exports.OnlyMobileWithClient = exports.WithClient;
|
|
139
|
-
exports.OnlyMobileWithClient.args = { ...storyArgs, onlyMobile: true };
|
|
140
|
-
exports.OnlyMobileServer = exports.OnlyServer;
|
|
141
|
-
exports.OnlyMobileServer.args = { ...storyArgs, onlyMobile: true };
|
|
142
|
-
//# sourceMappingURL=Expander.stories.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Expander.stories.js","sourceRoot":"","sources":["../../src/stories/Expander.stories.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* trackEntireRead
|
|
3
|
-
* @description Track the entire read of a truncated post
|
|
4
|
-
* @param {HTMLElement} post - The post element
|
|
5
|
-
*/
|
|
6
|
-
class TrackEntireRead {
|
|
7
|
-
private observer: IntersectionObserver | null = null
|
|
8
|
-
private readElement: Element | null
|
|
9
|
-
// data can be any key value pair that needs to be tracked
|
|
10
|
-
private data: Record<string, string>
|
|
11
|
-
constructor(readElement: Element, data: Record<string, string>) {
|
|
12
|
-
this.readElement = readElement as Element
|
|
13
|
-
this.data = data
|
|
14
|
-
this.init()
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
private init() {
|
|
18
|
-
//Intersection observer that observes readElement and when in view tracks the entire read
|
|
19
|
-
this.observer = new IntersectionObserver((entries) => {
|
|
20
|
-
entries.forEach((entry) => {
|
|
21
|
-
if (entry.isIntersecting) {
|
|
22
|
-
this.handleEntireRead()
|
|
23
|
-
this.observer?.disconnect()
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
|
-
this.observer.observe(this.readElement as Element)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
private handleEntireRead = () => {
|
|
31
|
-
const trackingData = {
|
|
32
|
-
action: 'entire_read',
|
|
33
|
-
...this.data,
|
|
34
|
-
}
|
|
35
|
-
const event = new CustomEvent('oTracking.event', {
|
|
36
|
-
detail: trackingData,
|
|
37
|
-
bubbles: true,
|
|
38
|
-
})
|
|
39
|
-
document.body.dispatchEvent(event)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
destroy(): void {
|
|
43
|
-
this.observer?.disconnect()
|
|
44
|
-
this.observer = null
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export class ExpanderClient {
|
|
48
|
-
/**
|
|
49
|
-
* The container element for all the elements that should be showned or be hidden.
|
|
50
|
-
*/
|
|
51
|
-
private container: Element | null
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* An optional element to which the expander will dispatch the events to.
|
|
55
|
-
* If not provided, events will not be dispatched.
|
|
56
|
-
*/
|
|
57
|
-
private dispatchBoundary?: Element | Document | null
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Element that will be showned at the end of the content when the expander is expanded.
|
|
61
|
-
* We use this to track when the entire post is read.
|
|
62
|
-
*/
|
|
63
|
-
private endContent: Element | null
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Track the entire read of a truncated post
|
|
67
|
-
*/
|
|
68
|
-
private trackingEntireRead: TrackEntireRead
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* The button that will expand the content
|
|
72
|
-
*/
|
|
73
|
-
private expanderButton: HTMLElement | null
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* The button that will collapse the content
|
|
77
|
-
*/
|
|
78
|
-
private collapserButton: HTMLElement | null
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* The tracking data that will be sent when the entire post is read
|
|
82
|
-
*/
|
|
83
|
-
private trackingData: Record<string, string>
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
*
|
|
87
|
-
* @param el
|
|
88
|
-
* @param dispatchBoundary
|
|
89
|
-
*/
|
|
90
|
-
|
|
91
|
-
constructor(
|
|
92
|
-
el: Element,
|
|
93
|
-
dispatchBoundary?: Element | Document | null,
|
|
94
|
-
trackingData?: Record<string, string>
|
|
95
|
-
) {
|
|
96
|
-
this.container = el
|
|
97
|
-
this.trackingData = trackingData || {}
|
|
98
|
-
this.expanderButton = el.querySelector(
|
|
99
|
-
'.cp-expander__expand [data-action="expand"]'
|
|
100
|
-
) as HTMLElement
|
|
101
|
-
this.collapserButton = el.querySelector(
|
|
102
|
-
'.cp-expander__collapse [data-action="collapse"]'
|
|
103
|
-
) as HTMLElement
|
|
104
|
-
this.endContent = el.querySelector('.cp-expander__collapse')
|
|
105
|
-
|
|
106
|
-
this.expanderButton?.addEventListener('click', this.handleExpand)
|
|
107
|
-
this.collapserButton?.addEventListener('click', this.handleCollapse)
|
|
108
|
-
|
|
109
|
-
this.container.classList.replace(
|
|
110
|
-
'cp-expander--not-initialised',
|
|
111
|
-
'cp-expander--initialised'
|
|
112
|
-
)
|
|
113
|
-
this.dispatchBoundary = dispatchBoundary || this.container
|
|
114
|
-
;(this.trackingData['post_id'] =
|
|
115
|
-
this.container
|
|
116
|
-
.querySelector('[data-trackable-context-truncated-id]')
|
|
117
|
-
?.getAttribute('data-trackable-context-truncated-id') || ''),
|
|
118
|
-
(this.trackingEntireRead = new TrackEntireRead(
|
|
119
|
-
this.endContent as Element,
|
|
120
|
-
this.trackingData
|
|
121
|
-
))
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
expand() {
|
|
125
|
-
this.container?.setAttribute('data-state', 'expanded')
|
|
126
|
-
this.dispatchBoundary?.dispatchEvent(
|
|
127
|
-
new CustomEvent('expander:expanded', {
|
|
128
|
-
bubbles: true,
|
|
129
|
-
detail: {
|
|
130
|
-
component: this.container,
|
|
131
|
-
},
|
|
132
|
-
})
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
collapse() {
|
|
137
|
-
this.container?.setAttribute('data-state', 'collapsed')
|
|
138
|
-
this.container?.scrollIntoView()
|
|
139
|
-
this.dispatchBoundary?.dispatchEvent(
|
|
140
|
-
new CustomEvent('expander:collapsed', {
|
|
141
|
-
bubbles: true,
|
|
142
|
-
detail: {
|
|
143
|
-
component: this.container,
|
|
144
|
-
},
|
|
145
|
-
})
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
private handleExpand = (e: Event) => {
|
|
150
|
-
e.preventDefault()
|
|
151
|
-
this.expand()
|
|
152
|
-
this.expanderButton?.setAttribute('aria-expanded', 'true')
|
|
153
|
-
this.expanderButton?.setAttribute('aria-hidden', 'true')
|
|
154
|
-
this.collapserButton?.setAttribute('aria-expanded', 'true')
|
|
155
|
-
this.collapserButton?.setAttribute('aria-hidden', 'false')
|
|
156
|
-
}
|
|
157
|
-
private handleCollapse = (e: Event) => {
|
|
158
|
-
e.preventDefault()
|
|
159
|
-
this.collapse()
|
|
160
|
-
this.expanderButton?.setAttribute('aria-expanded', 'false')
|
|
161
|
-
this.expanderButton?.setAttribute('aria-hidden', 'false')
|
|
162
|
-
this.collapserButton?.setAttribute('aria-expanded', 'false')
|
|
163
|
-
this.collapserButton?.setAttribute('aria-hidden', 'true')
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
destroy(): void {
|
|
167
|
-
this.container?.setAttribute('data-state', 'collapsed')
|
|
168
|
-
this.container
|
|
169
|
-
?.querySelector('.cp-expander__expand')
|
|
170
|
-
?.removeEventListener('click', this.expand)
|
|
171
|
-
this.container
|
|
172
|
-
?.querySelector('.cp-expander__collapse')
|
|
173
|
-
?.removeEventListener('click', this.collapse)
|
|
174
|
-
this.container?.classList.remove('cp-expander--initialised')
|
|
175
|
-
this.trackingEntireRead.destroy()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
static init(data?: {
|
|
179
|
-
rootElement?: HTMLElement | null
|
|
180
|
-
dispatchBoundary?: Element | Document | null
|
|
181
|
-
trackingData?: Record<string, string>
|
|
182
|
-
}): ExpanderClient[] {
|
|
183
|
-
const { rootElement, dispatchBoundary, trackingData } = data || {}
|
|
184
|
-
const root = rootElement || document.body
|
|
185
|
-
|
|
186
|
-
return (Array.from(
|
|
187
|
-
root.querySelectorAll(
|
|
188
|
-
':not(.cp-expander--initialised)[data-component="expander"]'
|
|
189
|
-
)
|
|
190
|
-
)?.map((el: Element) => {
|
|
191
|
-
if (!el.classList.contains('expander--initialised')) {
|
|
192
|
-
return new ExpanderClient(el, dispatchBoundary, trackingData)
|
|
193
|
-
}
|
|
194
|
-
}) || []) as ExpanderClient[]
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
export default ExpanderClient
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
@import '@financial-times/o-icons/main';
|
|
2
|
-
@import '@financial-times/o-colors/main';
|
|
3
|
-
@import '@financial-times/o-grid/main';
|
|
4
|
-
@import '@financial-times/o-spacing/main';
|
|
5
|
-
|
|
6
|
-
$numberIntroductoryElements: 1;
|
|
7
|
-
$dataComponentVisibleElements: (
|
|
8
|
-
'clip-set',
|
|
9
|
-
'recommended',
|
|
10
|
-
'flourish',
|
|
11
|
-
'image-set',
|
|
12
|
-
'video',
|
|
13
|
-
'youtube-video',
|
|
14
|
-
'table'
|
|
15
|
-
);
|
|
16
|
-
$alwaysVisibleComponentSelectors: ();
|
|
17
|
-
|
|
18
|
-
@each $component-name in $dataComponentVisibleElements {
|
|
19
|
-
$alwaysVisibleComponentSelectors: append(
|
|
20
|
-
$alwaysVisibleComponentSelectors,
|
|
21
|
-
'[data-component="#{$component-name}"]'
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
@mixin AlwaysVisibleElements {
|
|
25
|
-
@each $component in $alwaysVisibleComponentSelectors {
|
|
26
|
-
#{$component} {
|
|
27
|
-
display: block;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
@mixin IntroductoryElements {
|
|
32
|
-
& > :nth-child(-n + #{$numberIntroductoryElements + 1}):not(.cp-expander__expand) {
|
|
33
|
-
display: block;
|
|
34
|
-
order:1
|
|
35
|
-
}
|
|
36
|
-
& > :nth-child(n + #{$numberIntroductoryElements + 1}) {
|
|
37
|
-
order:3
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
@mixin expandeAndCollapse {
|
|
41
|
-
&[data-state='expanded'] {
|
|
42
|
-
.cp-expander-content {
|
|
43
|
-
// Show all the hidden children...
|
|
44
|
-
& > * {
|
|
45
|
-
display: block;
|
|
46
|
-
}
|
|
47
|
-
> .cp-expander__expand {
|
|
48
|
-
display: none;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
&[data-state='collapsed'] {
|
|
56
|
-
.cp-expander-content {
|
|
57
|
-
// Hide everything that comes after the expander...
|
|
58
|
-
// ... except the always visible children
|
|
59
|
-
& > * {
|
|
60
|
-
display: none;
|
|
61
|
-
}
|
|
62
|
-
&:target > * {
|
|
63
|
-
display: block;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
> .cp-expander__expand {
|
|
67
|
-
display: block;
|
|
68
|
-
order: 2;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
> .cp-expander__collapse {
|
|
72
|
-
display: none;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@include AlwaysVisibleElements;
|
|
76
|
-
|
|
77
|
-
@include IntroductoryElements;
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
@mixin InnerStyles {
|
|
85
|
-
|
|
86
|
-
&.cp-expander--not-initialised {
|
|
87
|
-
|
|
88
|
-
.cp-expander__expand,
|
|
89
|
-
.cp-expander__collapse {
|
|
90
|
-
display: none;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.cp-expander-content {
|
|
94
|
-
// Target is used for the Core experience.
|
|
95
|
-
// It permits us to hide elements server-side via CSS preventing Cumulative Shift but it is also a fully functional solution without Javascript
|
|
96
|
-
&:target{
|
|
97
|
-
.cp-expander__collapse{
|
|
98
|
-
display: block;
|
|
99
|
-
}
|
|
100
|
-
.cp-expander__expand{
|
|
101
|
-
display: none;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
.cp-expander__expand,
|
|
107
|
-
.cp-expander__collapse {
|
|
108
|
-
display: block;
|
|
109
|
-
padding-bottom: oSpacingByName('s6');
|
|
110
|
-
> a {
|
|
111
|
-
$icon-color: oColorsByName('ft-grey');
|
|
112
|
-
--_o-typography-body-color: $icon-color;
|
|
113
|
-
font-feature-settings: 'clig' off, 'liga' off;
|
|
114
|
-
|
|
115
|
-
@include oTypographyBody();
|
|
116
|
-
font-weight: 400;
|
|
117
|
-
text-decoration: none;
|
|
118
|
-
font-size: 20px;
|
|
119
|
-
&:hover {
|
|
120
|
-
|
|
121
|
-
cursor: pointer;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
&:after {
|
|
125
|
-
content: '';
|
|
126
|
-
@include oIconsContent('arrow-down', $icon-color, $size: 20);
|
|
127
|
-
padding: 0 4px;
|
|
128
|
-
vertical-align: middle;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.cp-expander__collapse a:after {
|
|
134
|
-
transform: rotate(180deg);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.cp-expander-content {
|
|
138
|
-
display: flex;
|
|
139
|
-
flex-direction: column;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@include expandeAndCollapse;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.cp-expander{
|
|
148
|
-
&.cp-expander--mobile-only {
|
|
149
|
-
.cp-expander__expand,
|
|
150
|
-
.cp-expander__collapse {
|
|
151
|
-
display: none;
|
|
152
|
-
}
|
|
153
|
-
@include oGridRespondTo($until: S) {
|
|
154
|
-
@include InnerStyles;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
&.cp-expander--all-resolutions {
|
|
159
|
-
@include InnerStyles;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import classnames from 'classnames'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
export interface ExpanderProps extends React.PropsWithChildren {
|
|
5
|
-
/** The initial state of the expander */
|
|
6
|
-
state?: 'expanded' | 'collapsed'
|
|
7
|
-
/** The label for the Expand CTA */
|
|
8
|
-
expandLabel?: string
|
|
9
|
-
/** The label for the collapse CTA */
|
|
10
|
-
collapseLabel?: string
|
|
11
|
-
/** Show the expander only on mobile resolutions */
|
|
12
|
-
onlyMobile?: boolean
|
|
13
|
-
/** Id of the component */
|
|
14
|
-
id: string
|
|
15
|
-
}
|
|
16
|
-
// React functional component with children
|
|
17
|
-
export const ExpanderServer: React.FC<ExpanderProps> = ({
|
|
18
|
-
state = 'collapsed', // default value for "state
|
|
19
|
-
children,
|
|
20
|
-
id,
|
|
21
|
-
expandLabel = 'Expand',
|
|
22
|
-
collapseLabel = 'Collapse',
|
|
23
|
-
onlyMobile = false,
|
|
24
|
-
}) => {
|
|
25
|
-
return (
|
|
26
|
-
<div
|
|
27
|
-
className={classnames({
|
|
28
|
-
'cp-expander': true,
|
|
29
|
-
'cp-expander--mobile-only': onlyMobile,
|
|
30
|
-
'cp-expander--all-resolutions': !onlyMobile,
|
|
31
|
-
'cp-expander--not-initialised': true,
|
|
32
|
-
})}
|
|
33
|
-
data-component="expander"
|
|
34
|
-
data-state={state}
|
|
35
|
-
id={`${id}__container`}
|
|
36
|
-
>
|
|
37
|
-
<div id={id} className="cp-expander-content" aria-describedby={id}>
|
|
38
|
-
<div className="cp-expander__expand">
|
|
39
|
-
<a
|
|
40
|
-
data-trackable="truncated-post"
|
|
41
|
-
data-trackable-context-truncated-post="expand"
|
|
42
|
-
data-trackable-context-truncated-id={id}
|
|
43
|
-
className="cp-expander__link"
|
|
44
|
-
href={`#${id}`}
|
|
45
|
-
aria-expanded={state === 'expanded' ? true : false}
|
|
46
|
-
aria-controls={id}
|
|
47
|
-
aria-hidden={state === 'expanded' ? true : false}
|
|
48
|
-
data-action="expand"
|
|
49
|
-
>
|
|
50
|
-
{expandLabel}
|
|
51
|
-
</a>
|
|
52
|
-
</div>
|
|
53
|
-
{children}
|
|
54
|
-
<div className="cp-expander__collapse">
|
|
55
|
-
<a
|
|
56
|
-
data-trackable="truncated-post"
|
|
57
|
-
data-trackable-context-truncated-post="collapse"
|
|
58
|
-
data-trackable-context-truncated-id={id}
|
|
59
|
-
href={`#${id}__container`}
|
|
60
|
-
className="cp-expander__link"
|
|
61
|
-
aria-expanded={state === 'expanded' ? true : false}
|
|
62
|
-
aria-controls={id}
|
|
63
|
-
aria-hidden={state === 'expanded' ? false : true}
|
|
64
|
-
data-action="collapse"
|
|
65
|
-
>
|
|
66
|
-
{collapseLabel}
|
|
67
|
-
</a>
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export default ExpanderServer
|