@financial-times/cp-content-pipeline-ui 7.1.0 → 7.1.2

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 CHANGED
@@ -574,6 +574,20 @@
574
574
  * @financial-times/cp-content-pipeline-client bumped from ^3.7.2 to ^3.7.3
575
575
  * @financial-times/cp-content-pipeline-schema bumped from ^2.10.1 to ^2.10.2
576
576
 
577
+ ## [7.1.2](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v7.1.1...cp-content-pipeline-ui-v7.1.2) (2024-09-24)
578
+
579
+
580
+ ### Bug Fixes
581
+
582
+ * tracking for ccc ([d21e731](https://github.com/Financial-Times/cp-content-pipeline/commit/d21e7310ca88cd8b9e21af2439c39ae4243eec0f))
583
+
584
+ ## [7.1.1](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v7.1.0...cp-content-pipeline-ui-v7.1.1) (2024-09-17)
585
+
586
+
587
+ ### Bug Fixes
588
+
589
+ * ci-2457 add ads to LiveBlogBody ([0fb6c0f](https://github.com/Financial-Times/cp-content-pipeline/commit/0fb6c0fe93d3c83d3f1af5543530d3f764cd9d15))
590
+
577
591
  ## [7.1.0](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-ui-v7.0.2...cp-content-pipeline-ui-v7.1.0) (2024-09-17)
578
592
 
579
593
 
@@ -1,3 +1,4 @@
1
+ import { CustomCodeComponentTracker } from './tracking';
1
2
  /**
2
3
  * CustomCodeComponentClient
3
4
  * @description Track the view of a rendered custom code component
@@ -8,8 +9,9 @@ declare class CustomCodeComponentClient {
8
9
  /**
9
10
  * Track the mount of a custom code component
10
11
  */
11
- private trackingMount;
12
+ tracking: CustomCodeComponentTracker;
12
13
  constructor(el: Element);
13
14
  static init(rootEl?: Element): (CustomCodeComponentClient | undefined)[];
15
+ static destroy(components: CustomCodeComponentClient[]): void;
14
16
  }
15
17
  export default CustomCodeComponentClient;
@@ -1,74 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
4
- * TrackMount
5
- * @description Track initial render of a custom code component
6
- * @param {HTMLElement} mountElement - The custom code component
7
- * @param {TrackingData} trackingData - The specific component data
8
- */
9
- class TrackMount {
10
- constructor(mountElement, trackingData) {
11
- this.mountElement = mountElement;
12
- this.trackingData = trackingData;
13
- this.handleMount = () => {
14
- const event = new CustomEvent('oTracking.event', {
15
- detail: {
16
- category: 'component',
17
- action: 'mount',
18
- ...this.trackingData,
19
- },
20
- });
21
- document.body.dispatchEvent(event);
22
- };
23
- this.init();
24
- }
25
- init() {
26
- this.mountElement.addEventListener('ccc-connected', () => {
27
- new TrackView(this.mountElement, this.trackingData);
28
- this.handleMount();
29
- });
30
- }
31
- }
32
- /**
33
- * TrackView
34
- * @description Track the view of a rendered custom code component
35
- * @param {HTMLElement} mountElement - The custom code component
36
- * @param {TrackingData} trackingData - The specific component data
37
- */
38
- class TrackView {
39
- constructor(viewElement, trackingData) {
40
- this.viewElement = viewElement;
41
- this.trackingData = trackingData;
42
- this.handleView = () => {
43
- const event = new CustomEvent('oTracking.event', {
44
- detail: {
45
- category: 'component',
46
- action: 'view',
47
- ...this.trackingData,
48
- },
49
- });
50
- document.body.dispatchEvent(event);
51
- };
52
- this.viewElement = viewElement;
53
- this.trackingData = trackingData;
54
- this.init();
55
- }
56
- init() {
57
- //Intersection observer that observes when viewElement is in view
58
- this.observer = new IntersectionObserver((entries) => {
59
- entries.forEach((entry) => {
60
- if (entry.isIntersecting) {
61
- this.handleView();
62
- this.observer?.disconnect();
63
- }
64
- });
65
- });
66
- this.observer.observe(this.viewElement);
67
- }
68
- destroy() {
69
- this.observer?.disconnect();
70
- }
71
- }
3
+ const tracking_1 = require("./tracking");
72
4
  /**
73
5
  * CustomCodeComponentClient
74
6
  * @description Track the view of a rendered custom code component
@@ -84,12 +16,17 @@ class CustomCodeComponentClient {
84
16
  type: 'custom-code-component',
85
17
  },
86
18
  };
87
- this.trackingMount = new TrackMount(el, trackingData);
19
+ this.tracking = new tracking_1.CustomCodeComponentTracker(el, trackingData);
88
20
  }
89
21
  static init(rootEl) {
90
22
  const root = rootEl instanceof Element ? rootEl : document;
91
23
  return Array.from(root.querySelectorAll('custom-code-component')).map((el) => new CustomCodeComponentClient(el));
92
24
  }
25
+ static destroy(components) {
26
+ components.forEach((component) => {
27
+ component.tracking.destroy();
28
+ });
29
+ }
93
30
  }
94
31
  exports.default = CustomCodeComponentClient;
95
32
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/CustomCodeComponent/client/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/CustomCodeComponent/client/index.ts"],"names":[],"mappings":";;AAAA,yCAAuD;AAEvD;;;;;GAKG;AACH,MAAM,yBAAyB;IAM7B,YAAY,EAAW;QACrB,MAAM,YAAY,GAAG;YACnB,SAAS,EAAE;gBACT,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;gBAC/B,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE;gBACnC,IAAI,EAAE,uBAAuB;aAC9B;SACF,CAAA;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,qCAA0B,CAAC,EAAa,EAAE,YAAY,CAAC,CAAA;IAC7E,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,MAAgB;QAC1B,MAAM,IAAI,GAAG,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,CAAC,CAAC,GAAG,CACnE,CAAC,EAAW,EAAE,EAAE,CAAC,IAAI,yBAAyB,CAAC,EAAE,CAAC,CACnD,CAAA;IACH,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,UAAuC;QACpD,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;QAC9B,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,kBAAe,yBAAyB,CAAA"}
@@ -0,0 +1,32 @@
1
+ type Component = {
2
+ id: string;
3
+ name: string;
4
+ type: string;
5
+ timeElapsedSeconds?: number;
6
+ };
7
+ type TrackingData = {
8
+ component: Component;
9
+ };
10
+ /**
11
+ * CustomCodeComponentTracker
12
+ * @description Track initial render of a custom code component
13
+ * @param {HTMLElement} mountElement - The custom code component
14
+ * @param {TrackingData} trackingData - The specific component data
15
+ */
16
+ declare class CustomCodeComponentTracker {
17
+ private component;
18
+ private trackingData;
19
+ private startTime;
20
+ private totalVisibleTime;
21
+ private timeElapsedSeconds;
22
+ private observer;
23
+ private viewing;
24
+ constructor(component: Element, trackingData: TrackingData);
25
+ private init;
26
+ private onCccConnected;
27
+ private onCccError;
28
+ private dispatchEvent;
29
+ private onChange;
30
+ destroy(): void;
31
+ }
32
+ export { CustomCodeComponentTracker };
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CustomCodeComponentTracker = void 0;
4
+ /**
5
+ * CustomCodeComponentTracker
6
+ * @description Track initial render of a custom code component
7
+ * @param {HTMLElement} mountElement - The custom code component
8
+ * @param {TrackingData} trackingData - The specific component data
9
+ */
10
+ class CustomCodeComponentTracker {
11
+ constructor(component, trackingData) {
12
+ this.component = component;
13
+ this.trackingData = trackingData;
14
+ this.startTime = 0;
15
+ this.totalVisibleTime = 0;
16
+ this.timeElapsedSeconds = null;
17
+ this.component = component;
18
+ this.trackingData = trackingData;
19
+ this.observer = null;
20
+ this.viewing = false;
21
+ this.init();
22
+ }
23
+ init() {
24
+ this.dispatchEvent('mount');
25
+ this.component.addEventListener('error', this.onCccError.bind(this));
26
+ this.component.addEventListener('ccc-connected', this.onCccConnected.bind(this));
27
+ }
28
+ onCccConnected() {
29
+ this.dispatchEvent('success');
30
+ this.observer = new IntersectionObserver(this.onChange.bind(this), {
31
+ rootMargin: `0px 0px -300px 0px`,
32
+ threshold: 0,
33
+ });
34
+ this.observer.observe(this.component);
35
+ }
36
+ onCccError() {
37
+ this.dispatchEvent('error');
38
+ }
39
+ dispatchEvent(action) {
40
+ const component = this.trackingData.component;
41
+ if (this.timeElapsedSeconds) {
42
+ component.timeElapsedSeconds = this.timeElapsedSeconds;
43
+ }
44
+ const event = new CustomEvent('oTracking.event', {
45
+ detail: {
46
+ category: 'component',
47
+ action,
48
+ ...component,
49
+ },
50
+ bubbles: true,
51
+ });
52
+ document.body.dispatchEvent(event);
53
+ }
54
+ onChange(changes) {
55
+ changes.forEach((change) => {
56
+ if (change.target !== this.component) {
57
+ return;
58
+ }
59
+ if (change.boundingClientRect.height > 0 &&
60
+ (change.isIntersecting || change.intersectionRatio >= 1)) {
61
+ this.dispatchEvent('view');
62
+ this.startTime = performance.now();
63
+ this.viewing = true;
64
+ }
65
+ if (this.viewing &&
66
+ (!change.isIntersecting || change.intersectionRatio === 0)) {
67
+ this.totalVisibleTime = performance.now() - this.startTime;
68
+ this.timeElapsedSeconds = parseFloat((this.totalVisibleTime / 1000).toFixed(2));
69
+ this.dispatchEvent('stop-view');
70
+ this.totalVisibleTime = 0;
71
+ this.timeElapsedSeconds = null;
72
+ }
73
+ });
74
+ }
75
+ destroy() {
76
+ if (this.observer && this.component) {
77
+ this.observer.unobserve(this.component);
78
+ this.observer.disconnect();
79
+ this.component.removeEventListener('ccc-connected', this.onCccConnected.bind(this));
80
+ this.component.removeEventListener('error', this.onCccError.bind(this));
81
+ }
82
+ }
83
+ }
84
+ exports.CustomCodeComponentTracker = CustomCodeComponentTracker;
85
+ //# sourceMappingURL=tracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracking.js","sourceRoot":"","sources":["../../../../src/components/CustomCodeComponent/client/tracking.ts"],"names":[],"mappings":"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"}
@@ -6,13 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
7
  const RichText_1 = require("../RichText");
8
8
  const LiveBlogWrapper_1 = require("../LiveBlogWrapper");
9
- const LiveBlogBody = ({ content, richTextComponents, xInteractionSerialiser, showShareButtons, postTrackerConfig, }) => {
9
+ const LiveBlogBody = ({ content, richTextComponents, xInteractionSerialiser, showShareButtons, postTrackerConfig, ads, }) => {
10
10
  if (content.__typename !== 'LiveBlogPackage')
11
11
  return null;
12
12
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
13
  const posts = content.liveBlogPosts || [];
14
14
  return (react_1.default.createElement(RichText_1.ComponentsContext.Provider, { value: richTextComponents },
15
- react_1.default.createElement(LiveBlogWrapper_1.LiveBlogWrapper, { articleUrl: `https://www.ft.com/content/${content.id}`, id: "live-blog-wrapper", posts: posts, serialiser: xInteractionSerialiser, showShareButtons: showShareButtons ?? true, postTrackerConfig: postTrackerConfig })));
15
+ react_1.default.createElement(LiveBlogWrapper_1.LiveBlogWrapper, { articleUrl: `https://www.ft.com/content/${content.id}`, id: "live-blog-wrapper", posts: posts, serialiser: xInteractionSerialiser, showShareButtons: showShareButtons ?? true, postTrackerConfig: postTrackerConfig, ads: ads })));
16
16
  };
17
17
  exports.default = LiveBlogBody;
18
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/LiveBlogBody/index.tsx"],"names":[],"mappings":";;;;;AAAA,kDAAyB;AAEzB,0CAA+C;AAC/C,wDAAoD;AASpD,MAAM,YAAY,GAAgC,CAAC,EACjD,OAAO,EACP,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,GAClB,EAAE,EAAE;IACH,IAAI,OAAO,CAAC,UAAU,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAA;IAEzD,8DAA8D;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,IAAI,EAAE,CAAA;IAEzC,OAAO,CACL,8BAAC,4BAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,kBAAkB;QACnD,8BAAC,iCAAe,IACd,UAAU,EAAE,8BAA8B,OAAO,CAAC,EAAE,EAAE,EACtD,EAAE,EAAC,mBAAmB,EACtB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,sBAAsB,EAClC,gBAAgB,EAAE,gBAAgB,IAAI,IAAI,EAC1C,iBAAiB,EAAE,iBAAiB,GACpC,CACyB,CAC9B,CAAA;AACH,CAAC,CAAA;AAED,kBAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/LiveBlogBody/index.tsx"],"names":[],"mappings":";;;;;AAAA,kDAAyB;AAEzB,0CAA+C;AAC/C,wDAAoD;AASpD,MAAM,YAAY,GAAgC,CAAC,EACjD,OAAO,EACP,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,GAAG,GACJ,EAAE,EAAE;IACH,IAAI,OAAO,CAAC,UAAU,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAA;IAEzD,8DAA8D;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,IAAI,EAAE,CAAA;IAEzC,OAAO,CACL,8BAAC,4BAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,kBAAkB;QACnD,8BAAC,iCAAe,IACd,UAAU,EAAE,8BAA8B,OAAO,CAAC,EAAE,EAAE,EACtD,EAAE,EAAC,mBAAmB,EACtB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,sBAAsB,EAClC,gBAAgB,EAAE,gBAAgB,IAAI,IAAI,EAC1C,iBAAiB,EAAE,iBAAiB,EACpC,GAAG,EAAE,GAAG,GACR,CACyB,CAC9B,CAAA;AACH,CAAC,CAAA;AAED,kBAAe,YAAY,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/cp-content-pipeline-ui",
3
- "version": "7.1.0",
3
+ "version": "7.1.2",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -1,91 +1,4 @@
1
- type Component = {
2
- id: string
3
- name: string
4
- type: string
5
- }
6
-
7
- type TrackingData = {
8
- component: Component
9
- }
10
-
11
- /**
12
- * TrackMount
13
- * @description Track initial render of a custom code component
14
- * @param {HTMLElement} mountElement - The custom code component
15
- * @param {TrackingData} trackingData - The specific component data
16
- */
17
- class TrackMount {
18
- constructor(
19
- private mountElement: Element,
20
- private trackingData: TrackingData
21
- ) {
22
- this.init()
23
- }
24
-
25
- private init() {
26
- this.mountElement.addEventListener('ccc-connected', () => {
27
- new TrackView(this.mountElement as Element, this.trackingData)
28
- this.handleMount()
29
- })
30
- }
31
-
32
- private handleMount = () => {
33
- const event = new CustomEvent('oTracking.event', {
34
- detail: {
35
- category: 'component',
36
- action: 'mount',
37
- ...this.trackingData,
38
- },
39
- })
40
- document.body.dispatchEvent(event)
41
- }
42
- }
43
-
44
- /**
45
- * TrackView
46
- * @description Track the view of a rendered custom code component
47
- * @param {HTMLElement} mountElement - The custom code component
48
- * @param {TrackingData} trackingData - The specific component data
49
- */
50
- class TrackView {
51
- private observer: IntersectionObserver | undefined
52
- constructor(
53
- private viewElement: Element,
54
- private trackingData: TrackingData
55
- ) {
56
- this.viewElement = viewElement as Element
57
- this.trackingData = trackingData
58
- this.init()
59
- }
60
-
61
- private init() {
62
- //Intersection observer that observes when viewElement is in view
63
- this.observer = new IntersectionObserver((entries) => {
64
- entries.forEach((entry) => {
65
- if (entry.isIntersecting) {
66
- this.handleView()
67
- this.observer?.disconnect()
68
- }
69
- })
70
- })
71
- this.observer.observe(this.viewElement as Element)
72
- }
73
-
74
- private handleView = () => {
75
- const event = new CustomEvent('oTracking.event', {
76
- detail: {
77
- category: 'component',
78
- action: 'view',
79
- ...this.trackingData,
80
- },
81
- })
82
- document.body.dispatchEvent(event)
83
- }
84
-
85
- destroy(): void {
86
- this.observer?.disconnect()
87
- }
88
- }
1
+ import { CustomCodeComponentTracker } from './tracking'
89
2
 
90
3
  /**
91
4
  * CustomCodeComponentClient
@@ -97,7 +10,7 @@ class CustomCodeComponentClient {
97
10
  /**
98
11
  * Track the mount of a custom code component
99
12
  */
100
- private trackingMount: TrackMount
13
+ tracking: CustomCodeComponentTracker
101
14
 
102
15
  constructor(el: Element) {
103
16
  const trackingData = {
@@ -107,7 +20,7 @@ class CustomCodeComponentClient {
107
20
  type: 'custom-code-component',
108
21
  },
109
22
  }
110
- this.trackingMount = new TrackMount(el as Element, trackingData)
23
+ this.tracking = new CustomCodeComponentTracker(el as Element, trackingData)
111
24
  }
112
25
 
113
26
  static init(rootEl?: Element): (CustomCodeComponentClient | undefined)[] {
@@ -116,6 +29,12 @@ class CustomCodeComponentClient {
116
29
  (el: Element) => new CustomCodeComponentClient(el)
117
30
  )
118
31
  }
32
+
33
+ static destroy(components: CustomCodeComponentClient[]): void {
34
+ components.forEach((component) => {
35
+ component.tracking.destroy()
36
+ })
37
+ }
119
38
  }
120
39
 
121
40
  export default CustomCodeComponentClient
@@ -0,0 +1,117 @@
1
+ type Component = {
2
+ id: string
3
+ name: string
4
+ type: string
5
+ timeElapsedSeconds?: number
6
+ }
7
+
8
+ type TrackingData = {
9
+ component: Component
10
+ }
11
+
12
+ /**
13
+ * CustomCodeComponentTracker
14
+ * @description Track initial render of a custom code component
15
+ * @param {HTMLElement} mountElement - The custom code component
16
+ * @param {TrackingData} trackingData - The specific component data
17
+ */
18
+ class CustomCodeComponentTracker {
19
+ private startTime: number
20
+ private totalVisibleTime: number
21
+ private timeElapsedSeconds: number | null
22
+ private observer: IntersectionObserver | null
23
+ private viewing: boolean
24
+
25
+ constructor(private component: Element, private trackingData: TrackingData) {
26
+ this.startTime = 0
27
+ this.totalVisibleTime = 0
28
+ this.timeElapsedSeconds = null
29
+ this.component = component
30
+ this.trackingData = trackingData
31
+ this.observer = null
32
+ this.viewing = false
33
+ this.init()
34
+ }
35
+
36
+ private init() {
37
+ this.dispatchEvent('mount')
38
+ this.component.addEventListener('error', this.onCccError.bind(this))
39
+ this.component.addEventListener(
40
+ 'ccc-connected',
41
+ this.onCccConnected.bind(this)
42
+ )
43
+ }
44
+
45
+ private onCccConnected(): void {
46
+ this.dispatchEvent('success')
47
+ this.observer = new IntersectionObserver(this.onChange.bind(this), {
48
+ rootMargin: `0px 0px -300px 0px`,
49
+ threshold: 0,
50
+ })
51
+ this.observer.observe(this.component)
52
+ }
53
+
54
+ private onCccError(): void {
55
+ this.dispatchEvent('error')
56
+ }
57
+
58
+ private dispatchEvent(action: string): void {
59
+ const component = this.trackingData.component
60
+
61
+ if (this.timeElapsedSeconds) {
62
+ component.timeElapsedSeconds = this.timeElapsedSeconds
63
+ }
64
+
65
+ const event = new CustomEvent('oTracking.event', {
66
+ detail: {
67
+ category: 'component',
68
+ action,
69
+ ...component,
70
+ },
71
+ bubbles: true,
72
+ })
73
+ document.body.dispatchEvent(event)
74
+ }
75
+
76
+ private onChange(changes: IntersectionObserverEntry[]): void {
77
+ changes.forEach((change) => {
78
+ if (change.target !== this.component) {
79
+ return
80
+ }
81
+ if (
82
+ change.boundingClientRect.height > 0 &&
83
+ (change.isIntersecting || change.intersectionRatio >= 1)
84
+ ) {
85
+ this.dispatchEvent('view')
86
+ this.startTime = performance.now()
87
+ this.viewing = true
88
+ }
89
+ if (
90
+ this.viewing &&
91
+ (!change.isIntersecting || change.intersectionRatio === 0)
92
+ ) {
93
+ this.totalVisibleTime = performance.now() - this.startTime
94
+ this.timeElapsedSeconds = parseFloat(
95
+ (this.totalVisibleTime / 1000).toFixed(2)
96
+ )
97
+ this.dispatchEvent('stop-view')
98
+ this.totalVisibleTime = 0
99
+ this.timeElapsedSeconds = null
100
+ }
101
+ })
102
+ }
103
+
104
+ destroy(): void {
105
+ if (this.observer && this.component) {
106
+ this.observer.unobserve(this.component)
107
+ this.observer.disconnect()
108
+ this.component.removeEventListener(
109
+ 'ccc-connected',
110
+ this.onCccConnected.bind(this)
111
+ )
112
+ this.component.removeEventListener('error', this.onCccError.bind(this))
113
+ }
114
+ }
115
+ }
116
+
117
+ export { CustomCodeComponentTracker }
@@ -16,6 +16,7 @@ const LiveBlogBody: React.FC<LiveBlogBodyProps> = ({
16
16
  xInteractionSerialiser,
17
17
  showShareButtons,
18
18
  postTrackerConfig,
19
+ ads,
19
20
  }) => {
20
21
  if (content.__typename !== 'LiveBlogPackage') return null
21
22
 
@@ -31,6 +32,7 @@ const LiveBlogBody: React.FC<LiveBlogBodyProps> = ({
31
32
  serialiser={xInteractionSerialiser}
32
33
  showShareButtons={showShareButtons ?? true}
33
34
  postTrackerConfig={postTrackerConfig}
35
+ ads={ads}
34
36
  />
35
37
  </ComponentsContext.Provider>
36
38
  )