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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/lib/client.d.ts +1 -0
  3. package/lib/client.js +3 -1
  4. package/lib/client.js.map +1 -1
  5. package/lib/components/Body/index.test.js +12 -11
  6. package/lib/components/Body/index.test.js.map +1 -1
  7. package/lib/components/CustomCodeComponent/client/index.d.ts +15 -0
  8. package/lib/components/CustomCodeComponent/client/index.js +95 -0
  9. package/lib/components/CustomCodeComponent/client/index.js.map +1 -0
  10. package/lib/components/CustomCodeComponent/index.d.ts +19 -0
  11. package/lib/components/CustomCodeComponent/index.js +17 -0
  12. package/lib/components/CustomCodeComponent/index.js.map +1 -0
  13. package/lib/components/Flourish/index.js +2 -5
  14. package/lib/components/Flourish/index.js.map +1 -1
  15. package/lib/components/Layout/index.d.ts +1 -1
  16. package/lib/components/Message/index.d.ts +9 -0
  17. package/lib/components/Message/index.js +18 -0
  18. package/lib/components/Message/index.js.map +1 -0
  19. package/lib/components/Message/test/snapshot.spec.d.ts +1 -0
  20. package/lib/components/Message/test/snapshot.spec.js +23 -0
  21. package/lib/components/Message/test/snapshot.spec.js.map +1 -0
  22. package/lib/components/PartnerContentHeader/index.js +2 -3
  23. package/lib/components/PartnerContentHeader/index.js.map +1 -1
  24. package/lib/components/RichText/BasicComponents.d.ts +1 -0
  25. package/lib/components/RichText/BasicComponents.js +3 -1
  26. package/lib/components/RichText/BasicComponents.js.map +1 -1
  27. package/lib/components/RichText/index.js +3 -0
  28. package/lib/components/RichText/index.js.map +1 -1
  29. package/lib/components/Workarounds.d.ts +5 -1
  30. package/lib/index.d.ts +2 -1
  31. package/lib/index.js +4 -1
  32. package/lib/index.js.map +1 -1
  33. package/lib/stories/Message.stories.d.ts +11 -0
  34. package/lib/stories/Message.stories.js +30 -0
  35. package/lib/stories/Message.stories.js.map +1 -0
  36. package/package.json +3 -2
  37. package/src/client.ts +1 -0
  38. package/src/components/Body/index.test.tsx +23 -24
  39. package/src/components/CustomCodeComponent/client/index.ts +121 -0
  40. package/src/components/CustomCodeComponent/index.tsx +54 -0
  41. package/src/components/Flourish/index.tsx +5 -26
  42. package/src/components/Flourish/test/__snapshots__/snapshot.spec.tsx.snap +12 -12
  43. package/src/components/Layout/index.tsx +1 -1
  44. package/src/components/Message/index.tsx +35 -0
  45. package/src/components/Message/test/__snapshots__/snapshot.spec.tsx.snap +45 -0
  46. package/src/components/Message/test/snapshot.spec.tsx +31 -0
  47. package/src/components/PartnerContentHeader/index.tsx +6 -8
  48. package/src/components/RichText/BasicComponents.tsx +4 -0
  49. package/src/components/RichText/index.tsx +4 -0
  50. package/src/components/Workarounds.ts +12 -0
  51. package/src/index.ts +2 -0
  52. package/src/stories/Message.stories.scss +5 -0
  53. package/src/stories/Message.stories.tsx +29 -0
  54. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.noticeInformCustomText = exports.noticeInformDefault = void 0;
7
+ const Message_1 = __importDefault(require("../components/Message"));
8
+ const react_1 = __importDefault(require("react"));
9
+ require("./Message.stories.scss");
10
+ exports.default = {
11
+ title: 'Message',
12
+ component: Message_1.default,
13
+ content: {},
14
+ };
15
+ const noticeInformArgs = {
16
+ id: '',
17
+ type: 'notice',
18
+ state: 'inform',
19
+ };
20
+ const noticeInformDefault = () => react_1.default.createElement(Message_1.default, { ...noticeInformArgs });
21
+ exports.noticeInformDefault = noticeInformDefault;
22
+ const noticeInformCustomTextArgs = {
23
+ id: '',
24
+ type: 'notice',
25
+ state: 'inform',
26
+ text: 'This is a custom message',
27
+ };
28
+ const noticeInformCustomText = () => (react_1.default.createElement(Message_1.default, { ...noticeInformCustomTextArgs }));
29
+ exports.noticeInformCustomText = noticeInformCustomText;
30
+ //# sourceMappingURL=Message.stories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Message.stories.js","sourceRoot":"","sources":["../../src/stories/Message.stories.tsx"],"names":[],"mappings":";;;;;;AAAA,oEAA2C;AAE3C,kDAAyB;AACzB,kCAA+B;AAE/B,kBAAe;IACb,KAAK,EAAE,SAAS;IAChB,SAAS,EAAE,iBAAO;IAClB,OAAO,EAAE,EAAE;CACZ,CAAA;AAED,MAAM,gBAAgB,GAAiB;IACrC,EAAE,EAAE,EAAE;IACN,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;CAChB,CAAA;AAEM,MAAM,mBAAmB,GAAG,GAAG,EAAE,CAAC,8BAAC,iBAAO,OAAK,gBAAgB,GAAI,CAAA;AAA7D,QAAA,mBAAmB,uBAA0C;AAE1E,MAAM,0BAA0B,GAAiB;IAC/C,EAAE,EAAE,EAAE;IACN,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,IAAI,EAAE,0BAA0B;CACjC,CAAA;AAEM,MAAM,sBAAsB,GAAG,GAAG,EAAE,CAAC,CAC1C,8BAAC,iBAAO,OAAK,0BAA0B,GAAI,CAC5C,CAAA;AAFY,QAAA,sBAAsB,0BAElC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/cp-content-pipeline-ui",
3
- "version": "7.0.2",
3
+ "version": "7.1.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -16,11 +16,12 @@
16
16
  "@babel/preset-env": "^7.22.5",
17
17
  "@babel/preset-react": "^7.22.5",
18
18
  "@dotcom-tool-kit/npm": "^3.3.2",
19
- "@financial-times/content-tree": "github:financial-times/content-tree#abdc26b",
19
+ "@financial-times/content-tree": "github:financial-times/content-tree#056af70",
20
20
  "@financial-times/n-scrollytelling-image": "^1.1.0",
21
21
  "@financial-times/o-colors": "^6.6.2",
22
22
  "@financial-times/o-grid": "^6.1.5",
23
23
  "@financial-times/o-icons": "^7.7.0",
24
+ "@financial-times/o-message": "^5.4.4",
24
25
  "@financial-times/o-share": "^10.0.1",
25
26
  "@financial-times/o-spacing": "^3.2.3",
26
27
  "@financial-times/o-tracking": "^4.5.0",
package/src/client.ts CHANGED
@@ -2,3 +2,4 @@ export { default as Clip } from './components/Clip/client/index'
2
2
  export { default as BackToTopButton } from './components/BackToTopButton/client'
3
3
  export { default as FlourishSSREmbed } from './components/Flourish/client/index'
4
4
  export { TopperTracker } from './components/Topper/client/index'
5
+ export { default as CustomCodeComponentClient } from './components/CustomCodeComponent/client/index'
@@ -36,12 +36,17 @@ const baseContent: ArticleQuery['content'] = {
36
36
  },
37
37
  }
38
38
 
39
- const extraContentForType: Partial<
40
- Record<
41
- ArticleQuery['content']['__typename'],
42
- Partial<ArticleQuery['content']>
43
- >
44
- > = {
39
+ // these are the only content types we currently care about rendering bodies for
40
+ const typesToTest = [
41
+ 'Article',
42
+ 'Video',
43
+ 'Audio',
44
+ 'LiveBlogPackage',
45
+ 'ContentPackage',
46
+ ] satisfies ArticleQuery['content']['__typename'][]
47
+
48
+ const extraContentForType = {
49
+ Article: {},
45
50
  Audio: {
46
51
  __typename: 'Audio',
47
52
  media: [
@@ -83,7 +88,10 @@ const extraContentForType: Partial<
83
88
  Video: {
84
89
  __typename: 'Video',
85
90
  },
86
- }
91
+ } satisfies Record<
92
+ (typeof typesToTest)[number],
93
+ Partial<ArticleQuery['content']>
94
+ >
87
95
 
88
96
  const extraPropsForType: Partial<
89
97
  Record<ArticleQuery['content']['__typename'], Record<string, unknown>>
@@ -95,24 +103,15 @@ const extraPropsForType: Partial<
95
103
  },
96
104
  }
97
105
 
98
- // these are the only content types we currently care about rendering bodies for
99
- const typesToTest: ArticleQuery['content']['__typename'][] = [
100
- 'Article',
101
- 'Video',
102
- 'Audio',
103
- 'LiveBlogPackage',
104
- 'ContentPackage',
105
- ]
106
-
107
- const legacyOverridesToTest: [
108
- ArticleQuery['content']['__typename'],
109
- keyof BodyComponentMapRecord
110
- ][] = [
106
+ const legacyOverridesToTest = [
111
107
  ['Article', 'article-body'],
112
108
  ['LiveBlogPackage', 'live-blog-body'],
113
109
  ['ContentPackage', 'content-package-body'],
114
110
  ['Audio', 'podcast-body'],
115
- ]
111
+ ] satisfies [
112
+ ArticleQuery['content']['__typename'],
113
+ keyof BodyComponentMapRecord
114
+ ][]
116
115
 
117
116
  describe('Body', () => {
118
117
  let mockDate: jest.SpyInstance
@@ -128,7 +127,7 @@ describe('Body', () => {
128
127
  test.each(typesToTest)('renders default renderer for %s', (type) => {
129
128
  const { asFragment } = render(
130
129
  <Body
131
- content={{ ...baseContent, ...(extraContentForType[type] ?? {}) }}
130
+ content={{ ...baseContent, ...extraContentForType[type] }}
132
131
  {...(extraPropsForType[type] ?? {})}
133
132
  />
134
133
  )
@@ -143,7 +142,7 @@ describe('Body', () => {
143
142
  (type, overrideName) => {
144
143
  const { asFragment } = render(
145
144
  <Body
146
- content={{ ...baseContent, ...(extraContentForType[type] ?? {}) }}
145
+ content={{ ...baseContent, ...extraContentForType[type] }}
147
146
  {...(extraPropsForType[type] ?? {})}
148
147
  bodyComponents={{
149
148
  [overrideName]: ({
@@ -164,7 +163,7 @@ describe('Body', () => {
164
163
  test.each(typesToTest)('renders override renderer for %s', (type) => {
165
164
  const { asFragment } = render(
166
165
  <Body
167
- content={{ ...baseContent, ...(extraContentForType[type] ?? {}) }}
166
+ content={{ ...baseContent, ...extraContentForType[type] }}
168
167
  {...(extraPropsForType[type] ?? {})}
169
168
  bodyComponents={{
170
169
  [type]: ({ content }: { content: ArticleQuery['content'] }) => (
@@ -0,0 +1,121 @@
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
+ }
89
+
90
+ /**
91
+ * CustomCodeComponentClient
92
+ * @description Track the view of a rendered custom code component
93
+ * @param {HTMLElement} el - The custom code component
94
+ * @param {TrackingData} trackingData - The tracking data
95
+ */
96
+ class CustomCodeComponentClient {
97
+ /**
98
+ * Track the mount of a custom code component
99
+ */
100
+ private trackingMount: TrackMount
101
+
102
+ constructor(el: Element) {
103
+ const trackingData = {
104
+ component: {
105
+ id: el.getAttribute('id') ?? '',
106
+ name: el.getAttribute('path') ?? '',
107
+ type: 'custom-code-component',
108
+ },
109
+ }
110
+ this.trackingMount = new TrackMount(el as Element, trackingData)
111
+ }
112
+
113
+ static init(rootEl?: Element): (CustomCodeComponentClient | undefined)[] {
114
+ const root = rootEl instanceof Element ? rootEl : document
115
+ return Array.from(root.querySelectorAll('custom-code-component')).map(
116
+ (el: Element) => new CustomCodeComponentClient(el)
117
+ )
118
+ }
119
+ }
120
+
121
+ export default CustomCodeComponentClient
@@ -0,0 +1,54 @@
1
+ import React from 'react'
2
+ import Message from '../Message'
3
+ import { Layout } from '../Layout'
4
+ import RichText from '../RichText'
5
+ import { ContentProps } from '../types'
6
+ import * as ComponentWorkarounds from '../Workarounds'
7
+
8
+ interface CustomCodeComponentProps
9
+ extends ContentProps<ComponentWorkarounds.CustomCodeComponent> {}
10
+
11
+ declare module 'react' {
12
+ // eslint-disable-next-line @typescript-eslint/no-namespace
13
+ namespace JSX {
14
+ interface IntrinsicElements {
15
+ 'custom-code-component': {
16
+ path: string
17
+ version: string
18
+ id: string
19
+ children: React.ReactNode
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ const CustomCodeComponent: React.FC<
26
+ React.PropsWithChildren<CustomCodeComponentProps>
27
+ > = ({
28
+ content: {
29
+ path,
30
+ versionRange,
31
+ id,
32
+ layoutWidth = 'in-line',
33
+ attributes = {},
34
+ body,
35
+ },
36
+ }: CustomCodeComponentProps) => {
37
+ return (
38
+ <Layout
39
+ content={{ type: 'layout', layoutName: 'auto', layoutWidth: layoutWidth }}
40
+ >
41
+ <custom-code-component
42
+ path={path}
43
+ version={versionRange}
44
+ {...attributes}
45
+ id={id}
46
+ >
47
+ <Message id={id} type="notice" state="inform" />
48
+ {body?.structured && <RichText structuredContent={body.structured} />}
49
+ </custom-code-component>
50
+ </Layout>
51
+ )
52
+ }
53
+
54
+ export default CustomCodeComponent
@@ -2,36 +2,15 @@ import React from 'react'
2
2
  import classnames from 'classnames'
3
3
  import { ContentProps } from '../types'
4
4
  import { ContentTreeWorkarounds } from '@financial-times/cp-content-pipeline-schema'
5
-
6
- interface disclaimerProps {
7
- id: string
8
- }
9
-
10
- const DisclaimerNotice = ({ id }: disclaimerProps) => (
11
- <div
12
- id={id}
13
- className="flourish-disclaimer o-message o-message--alert o-message--neutral"
14
- data-o-component="o-message"
15
- >
16
- <div className="o-message__container">
17
- <div className="o-message__content">
18
- <p className="o-message__content-main">
19
- You are seeing a snapshot of an interactive graphic. This is most
20
- likely due to being offline or JavaScript being disabled in your
21
- browser.
22
- </p>
23
- </div>
24
- </div>
25
- </div>
26
- )
5
+ import Message from '../Message'
27
6
 
28
7
  interface FlourishProps extends ContentProps<ContentTreeWorkarounds.Flourish> {
29
- iFrame?: boolean
30
- inArticleBody?: boolean
8
+ iFrame?: boolean
9
+ inArticleBody?: boolean
31
10
  }
32
11
 
33
12
  const Flourish: React.FC<FlourishProps> = ({
34
- content: { id, flourishType, description, layoutWidth, fallbackImage },
13
+ content: { id, flourishType, description, layoutWidth, fallbackImage },
35
14
  iFrame = false,
36
15
  inArticleBody = true,
37
16
  }) => {
@@ -92,7 +71,7 @@ const Flourish: React.FC<FlourishProps> = ({
92
71
  data-flourish-id={id}
93
72
  data-flourish-type={flourishType}
94
73
  >
95
- <DisclaimerNotice id={id} />
74
+ <Message id={id} type="notice" state="inform" />
96
75
  <img
97
76
  src={fallbackImage?.url || ''}
98
77
  alt={description}
@@ -20,7 +20,7 @@ exports[`Flourish component renders ignoring layout different from full-grid 1`]
20
20
  data-flourish-type="bar"
21
21
  >
22
22
  <div
23
- class="flourish-disclaimer o-message o-message--alert o-message--neutral"
23
+ class="cp-message o-message o-message--inform o-message--notice"
24
24
  data-o-component="o-message"
25
25
  id="123"
26
26
  >
@@ -33,7 +33,7 @@ exports[`Flourish component renders ignoring layout different from full-grid 1`]
33
33
  <p
34
34
  class="o-message__content-main"
35
35
  >
36
- You are seeing a snapshot of an interactive graphic. This is most likely due to being offline or JavaScript being disabled in your browser.
36
+ Some content could not load. Check your internet connection or browser settings.
37
37
  </p>
38
38
  </div>
39
39
  </div>
@@ -72,7 +72,7 @@ exports[`Flourish component renders with a full-grid layout and fallback image 1
72
72
  data-flourish-type="bar"
73
73
  >
74
74
  <div
75
- class="flourish-disclaimer o-message o-message--alert o-message--neutral"
75
+ class="cp-message o-message o-message--inform o-message--notice"
76
76
  data-o-component="o-message"
77
77
  id="123"
78
78
  >
@@ -85,7 +85,7 @@ exports[`Flourish component renders with a full-grid layout and fallback image 1
85
85
  <p
86
86
  class="o-message__content-main"
87
87
  >
88
- You are seeing a snapshot of an interactive graphic. This is most likely due to being offline or JavaScript being disabled in your browser.
88
+ Some content could not load. Check your internet connection or browser settings.
89
89
  </p>
90
90
  </div>
91
91
  </div>
@@ -129,7 +129,7 @@ exports[`Flourish component renders with an iframe rather than using the embed s
129
129
  data-flourish-type="bar"
130
130
  >
131
131
  <div
132
- class="flourish-disclaimer o-message o-message--alert o-message--neutral"
132
+ class="cp-message o-message o-message--inform o-message--notice"
133
133
  data-o-component="o-message"
134
134
  id="123"
135
135
  >
@@ -142,7 +142,7 @@ exports[`Flourish component renders with an iframe rather than using the embed s
142
142
  <p
143
143
  class="o-message__content-main"
144
144
  >
145
- You are seeing a snapshot of an interactive graphic. This is most likely due to being offline or JavaScript being disabled in your browser.
145
+ Some content could not load. Check your internet connection or browser settings.
146
146
  </p>
147
147
  </div>
148
148
  </div>
@@ -181,7 +181,7 @@ exports[`Flourish component renders without n-content-layout class for charts no
181
181
  data-flourish-type="bar"
182
182
  >
183
183
  <div
184
- class="flourish-disclaimer o-message o-message--alert o-message--neutral"
184
+ class="cp-message o-message o-message--inform o-message--notice"
185
185
  data-o-component="o-message"
186
186
  id="123"
187
187
  >
@@ -194,7 +194,7 @@ exports[`Flourish component renders without n-content-layout class for charts no
194
194
  <p
195
195
  class="o-message__content-main"
196
196
  >
197
- You are seeing a snapshot of an interactive graphic. This is most likely due to being offline or JavaScript being disabled in your browser.
197
+ Some content could not load. Check your internet connection or browser settings.
198
198
  </p>
199
199
  </div>
200
200
  </div>
@@ -234,7 +234,7 @@ exports[`does not set aspect ratios when in article body 1`] = `
234
234
  data-flourish-type="bar"
235
235
  >
236
236
  <div
237
- class="flourish-disclaimer o-message o-message--alert o-message--neutral"
237
+ class="cp-message o-message o-message--inform o-message--notice"
238
238
  data-o-component="o-message"
239
239
  id="123"
240
240
  >
@@ -247,7 +247,7 @@ exports[`does not set aspect ratios when in article body 1`] = `
247
247
  <p
248
248
  class="o-message__content-main"
249
249
  >
250
- You are seeing a snapshot of an interactive graphic. This is most likely due to being offline or JavaScript being disabled in your browser.
250
+ Some content could not load. Check your internet connection or browser settings.
251
251
  </p>
252
252
  </div>
253
253
  </div>
@@ -291,7 +291,7 @@ exports[`sets the hideTitle param in the iframe url to true when not in article
291
291
  data-flourish-type="bar"
292
292
  >
293
293
  <div
294
- class="flourish-disclaimer o-message o-message--alert o-message--neutral"
294
+ class="cp-message o-message o-message--inform o-message--notice"
295
295
  data-o-component="o-message"
296
296
  id="123"
297
297
  >
@@ -304,7 +304,7 @@ exports[`sets the hideTitle param in the iframe url to true when not in article
304
304
  <p
305
305
  class="o-message__content-main"
306
306
  >
307
- You are seeing a snapshot of an interactive graphic. This is most likely due to being offline or JavaScript being disabled in your browser.
307
+ Some content could not load. Check your internet connection or browser settings.
308
308
  </p>
309
309
  </div>
310
310
  </div>
@@ -2,7 +2,7 @@ import { ContentTree } from '@financial-times/content-tree'
2
2
  import React from 'react'
3
3
  import { ContentProps } from '../types'
4
4
 
5
- interface LayoutProps extends ContentProps<ContentTree.transit.Layout> {}
5
+ interface LayoutProps extends ContentProps<Omit<ContentTree.transit.Layout, 'children'>> {}
6
6
 
7
7
  /*
8
8
  * @description Layout component is used to define the layout for content. It can be used with ContentTree Layout Nodes or as a static layout.
@@ -0,0 +1,35 @@
1
+ import React from 'react'
2
+ import classnames from 'classnames'
3
+
4
+ export type MessageProps = {
5
+ id: string
6
+ type?: string
7
+ state?: string
8
+ text?: string
9
+ }
10
+
11
+ const Message: React.FC<MessageProps> = ({
12
+ id,
13
+ type,
14
+ state,
15
+ text = 'Some content could not load. Check your internet connection or browser settings.',
16
+ }) => {
17
+ return (
18
+ <div
19
+ id={id}
20
+ className={classnames('cp-message', 'o-message', {
21
+ [`o-message--${state}`]: state,
22
+ [`o-message--${type}`]: type,
23
+ })}
24
+ data-o-component="o-message"
25
+ >
26
+ <div className="o-message__container">
27
+ <div className="o-message__content">
28
+ <p className="o-message__content-main">{text}</p>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ )
33
+ }
34
+
35
+ export default Message
@@ -0,0 +1,45 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Message component renders default 1`] = `
4
+ <div
5
+ className="cp-message o-message o-message--neutral o-message--alert"
6
+ data-o-component="o-message"
7
+ id="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
8
+ >
9
+ <div
10
+ className="o-message__container"
11
+ >
12
+ <div
13
+ className="o-message__content"
14
+ >
15
+ <p
16
+ className="o-message__content-main"
17
+ >
18
+ Some content could not load. Check your internet connection or browser settings.
19
+ </p>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ `;
24
+
25
+ exports[`Message component renders with custom text 1`] = `
26
+ <div
27
+ className="cp-message o-message o-message--neutral o-message--alert"
28
+ data-o-component="o-message"
29
+ id="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
30
+ >
31
+ <div
32
+ className="o-message__container"
33
+ >
34
+ <div
35
+ className="o-message__content"
36
+ >
37
+ <p
38
+ className="o-message__content-main"
39
+ >
40
+ This is a custom message
41
+ </p>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ `;
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import renderer from 'react-test-renderer'
3
+ import Message from '../index'
4
+
5
+ describe('Message component', () => {
6
+ it('renders default', () => {
7
+ const tree = renderer
8
+ .create(
9
+ <Message
10
+ id={'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}
11
+ type="alert"
12
+ state="neutral"
13
+ />
14
+ )
15
+ .toJSON()
16
+ expect(tree).toMatchSnapshot()
17
+ })
18
+ it('renders with custom text', () => {
19
+ const tree = renderer
20
+ .create(
21
+ <Message
22
+ id={'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}
23
+ type="alert"
24
+ state="neutral"
25
+ text="This is a custom message"
26
+ />
27
+ )
28
+ .toJSON()
29
+ expect(tree).toMatchSnapshot()
30
+ })
31
+ })
@@ -3,18 +3,16 @@ import { TooltipToggle } from '@financial-times/o3-tooltip'
3
3
 
4
4
  const PartnerContentHeader = ({ name = 'Partner' }: { name: string }) => {
5
5
  return (
6
- <div className="partner-content-header">
6
+ <div className="partner-content-header" data-o3-brand="core">
7
7
  <div className="partner-content-header__content">
8
8
  <div className="partner-content-header__client">{name}</div>
9
9
  <div className="partner-content-header__title">
10
10
  <p>Partner Content</p>
11
- <div data-o3-brand="core">
12
- <TooltipToggle
13
- placement="bottom"
14
- content={`This content was paid for by ${name} and produced in partnership with the Financial Times Commercial department`}
15
- infoLabel="More information on Partner Content"
16
- />
17
- </div>
11
+ <TooltipToggle
12
+ placement="bottom"
13
+ content={`This content was paid for by ${name} and produced in partnership with the Financial Times Commercial department`}
14
+ infoLabel="More information on Partner Content"
15
+ />
18
16
  </div>
19
17
  </div>
20
18
  </div>
@@ -50,6 +50,10 @@ export const Strikethrough: React.FC<
50
50
  React.PropsWithChildren<ContentProps<ContentTree.Strikethrough>>
51
51
  > = (props) => <s>{props.children}</s>
52
52
 
53
+ export const CccFallbackText: React.FC<
54
+ React.PropsWithChildren<ContentProps<ContentTreeWorkarounds.CccFallbackText>>
55
+ > = (props) => <div>{props.children}</div>
56
+
53
57
  export const TableRow: React.FC<
54
58
  React.PropsWithChildren<ContentProps<ContentTreeWorkarounds.TableRow>>
55
59
  > = (props) => <tr>{props.children}</tr>