@financial-times/cp-content-pipeline-ui 6.7.0 → 6.7.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/components/Byline/index.js +1 -1
  3. package/lib/components/Byline/index.js.map +1 -1
  4. package/lib/components/Clip/components/Container.js +2 -2
  5. package/lib/components/Clip/components/Container.js.map +1 -1
  6. package/lib/components/Clip/template/index.js +1 -0
  7. package/lib/components/Clip/template/index.js.map +1 -1
  8. package/lib/components/ImageSet/index.js +1 -1
  9. package/lib/components/ImageSet/index.js.map +1 -1
  10. package/lib/components/LiveBlogPost/index.js +21 -9
  11. package/lib/components/LiveBlogPost/index.js.map +1 -1
  12. package/lib/components/LiveBlogWrapper/index.js +1 -1
  13. package/lib/components/LiveBlogWrapper/index.js.map +1 -1
  14. package/lib/components/Recommended/index.js +1 -1
  15. package/lib/components/Recommended/index.js.map +1 -1
  16. package/lib/components/RichText/index.d.ts +1 -1
  17. package/lib/components/Table/index.js +1 -1
  18. package/lib/components/Table/index.js.map +1 -1
  19. package/lib/components/Video/index.js +1 -1
  20. package/lib/components/Video/index.js.map +1 -1
  21. package/lib/components/YoutubeVideo/index.js +1 -1
  22. package/lib/components/YoutubeVideo/index.js.map +1 -1
  23. package/lib/stories/Clip.stories.d.ts +1 -2
  24. package/lib/stories/Clip.stories.js +5 -5
  25. package/lib/stories/Clip.stories.js.map +1 -1
  26. package/package.json +5 -2
  27. package/src/components/Byline/index.tsx +8 -4
  28. package/src/components/Clip/components/Container.tsx +3 -10
  29. package/src/components/Clip/template/index.ts +1 -0
  30. package/src/components/Clip/test/__snapshots__/snapshot.spec.tsx.snap +8 -8
  31. package/src/components/ImageSet/index.tsx +0 -1
  32. package/src/components/LiveBlogPost/index.tsx +42 -29
  33. package/src/components/LiveBlogWrapper/index.tsx +0 -1
  34. package/src/components/Recommended/index.tsx +0 -1
  35. package/src/components/Table/index.tsx +0 -1
  36. package/src/components/Video/index.tsx +1 -4
  37. package/src/components/YoutubeVideo/index.tsx +1 -4
  38. package/src/stories/Clip.stories.tsx +2 -3
  39. package/tsconfig.tsbuildinfo +1 -1
  40. package/lib/components/Expander/client/index.d.ts +0 -49
  41. package/lib/components/Expander/client/index.js +0 -124
  42. package/lib/components/Expander/client/index.js.map +0 -1
  43. package/lib/components/Expander/index.d.ts +0 -15
  44. package/lib/components/Expander/index.js +0 -27
  45. package/lib/components/Expander/index.js.map +0 -1
  46. package/lib/components/Expander/test/client/index.spec.d.ts +0 -1
  47. package/lib/components/Expander/test/client/index.spec.js +0 -103
  48. package/lib/components/Expander/test/client/index.spec.js.map +0 -1
  49. package/lib/components/Expander/test/index.spec.d.ts +0 -1
  50. package/lib/components/Expander/test/index.spec.js +0 -57
  51. package/lib/components/Expander/test/index.spec.js.map +0 -1
  52. package/lib/components/Expander/test/snapshot.spec.d.ts +0 -1
  53. package/lib/components/Expander/test/snapshot.spec.js +0 -63
  54. package/lib/components/Expander/test/snapshot.spec.js.map +0 -1
  55. package/lib/components/LiveBlogPost/client/index.d.ts +0 -5
  56. package/lib/components/LiveBlogPost/client/index.js +0 -12
  57. package/lib/components/LiveBlogPost/client/index.js.map +0 -1
  58. package/lib/stories/Expander.stories.d.ts +0 -54
  59. package/lib/stories/Expander.stories.js +0 -142
  60. package/lib/stories/Expander.stories.js.map +0 -1
  61. package/src/components/Expander/client/index.ts +0 -197
  62. package/src/components/Expander/client/main.scss +0 -162
  63. package/src/components/Expander/index.tsx +0 -74
  64. package/src/components/Expander/test/__snapshots__/snapshot.spec.tsx.snap +0 -225
  65. package/src/components/Expander/test/client/index.spec.tsx +0 -129
  66. package/src/components/Expander/test/index.spec.tsx +0 -77
  67. package/src/components/Expander/test/snapshot.spec.tsx +0 -73
  68. package/src/components/LiveBlogPost/client/index.ts +0 -9
  69. package/src/stories/Expander.stories.scss +0 -3
  70. 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsE;AACtE,0DAA8D;AAC9D,+CAAwC;AACxC,4EAAwD;AACxD,mCAAgC;AAChC,uEAAkD;AAClD,+BAA4B;AAC5B,sEAA6C;AAI7C,MAAM,iBAAiB,GAAqB;IAC1C,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,KAAK,EACH,2KAA2K;iBAC9K;aACF;SACuB;QAC1B;YACE,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,KAAK,EACH,qJAAqJ;iBACxJ;aACF;SACuB;QAC1B,AAD2B;QAE3B;YACE,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,KAAK,EACH,sNAAsN;iBACzN;aACF;SACuB;QAC1B;YACE,IAAI,EAAE,UAAU;YAChB,EAAE,EAAE,gEAAgE;YACpE,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,KAAK;YACZ,UAAU,EAAE,SAAS;YACrB,IAAI,EAAE;gBACJ,cAAc,EAAE,CAAC;aAClB;SACS;KACmB;CAClC,CAAA;AACD,MAAM,SAAS,GAAkB;IAC/B,WAAW,EAAE,MAAM;IACnB,aAAa,EAAE,OAAO;IACtB,UAAU,EAAE,KAAK;IACjB,EAAE,EAAE,sBAAsB;CAC3B,CAAA;AAED,kBAAe;IACb,KAAK,EAAE,UAAU;IACjB,SAAS,EAAE,yBAAc;IACzB,IAAI,EAAE,CAAC,UAAU,CAAC;CACnB,CAAA;AAED,MAAM,eAAe,GAAsD,CACzE,IAAI,EACJ,EAAE;IACF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;IAE3B,OAAO,CACL,uCAAK,SAAS,EAAE,UAAU;QACxB,2CACE,EAAE,EAAC,cAAc,EACjB,IAAI,EAAC,MAAM,EACX,SAAS,EAAC,wEAAwE,uBAChE,wBAAwB;YAE1C,uCACE,SAAS,EAAC,kBAAkB,oBACb,cAAc,oBACd,cAAc,EAC7B,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE;gBAE/B,uCACE,SAAS,EAAC,+DAA+D,oBAC1D,sBAAsB;oBAErC,8BAAC,mBAAmB,OAAK,IAAI,EAAE,EAAE,EAAC,KAAK,GAAuB,CAC1D,CACF;YACN,uCAAK,SAAS,EAAC,iBAAiB,GAAO,CAC/B,CACN,CACP,CAAA;AACH,CAAC,CAAA;AAED,MAAM,mBAAmB,GAAG,CAAC,IAAmB,EAAE,EAAE;IAClD,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,cAAS,CAAC,IAAI,CAAC;YACb,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;YAC5B,IAAI,EAAE,IAAI;SACX,CAAC,CAAA;QAEF,MAAM,KAAK,GAAG,gBAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAEvC,OAAO,GAAG,EAAE;YACV,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QACxC,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IACN,OAAO,CACL,2CAAS,EAAE,EAAE,IAAI,CAAC,EAAE;QAClB,uCAAK,SAAS,EAAC,gBAAgB;YAC7B,yDACiB,gBAAgB,iCACH,MAAM,oBACnB,kBAAkB;gBAEjC,8BAAC,yBAAc,OAAK,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,WAAW;oBACjD,8BAAC,kBAAQ,IAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,GAAI,CAC7C,CACb,CACF,CACE,CACX,CAAA;AACH,CAAC,CAAA;AAEM,MAAM,UAAU,GAAG,CAAC,IAAmB,EAAE,EAAE;IAChD,OAAO,8BAAC,eAAe,OAAK,IAAI,GAAI,CAAA;AACtC,CAAC,CAAA;AAFY,QAAA,UAAU,cAEtB;AAED,kBAAU,CAAC,IAAI,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;AAE3B,MAAM,UAAU,GAAG,CAAC,IAAmB,EAAE,EAAE;IAChD,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,KAAK,GAAG,gBAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QACvC,MAAM,SAAS,GAAG,uBAAc,CAAC,IAAI,EAAE,CAAA;QACvC,OAAO,GAAG,EAAE;YACV,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;YACtC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QACtD,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IACN,OAAO,8BAAC,eAAe,OAAK,IAAI,GAAI,CAAA;AACtC,CAAC,CAAA;AAVY,QAAA,UAAU,cAUtB;AAED,kBAAU,CAAC,IAAI,GAAG,EAAE,GAAG,SAAS,EAAE,CAAA;AAErB,QAAA,oBAAoB,GAAG,kBAAU,CAAA;AAC9C,4BAAoB,CAAC,IAAI,GAAG,EAAE,GAAG,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;AAEjD,QAAA,gBAAgB,GAAG,kBAAU,CAAA;AAC1C,wBAAgB,CAAC,IAAI,GAAG,EAAE,GAAG,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA"}
@@ -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