@transferwise/components 46.117.0 → 46.118.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 (50) hide show
  1. package/build/index.js +4 -0
  2. package/build/index.js.map +1 -1
  3. package/build/index.mjs +2 -0
  4. package/build/index.mjs.map +1 -1
  5. package/build/main.css +85 -25
  6. package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
  7. package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
  8. package/build/styles/button/Button.css +5 -5
  9. package/build/styles/button/Button.vars.css +5 -5
  10. package/build/styles/main.css +85 -25
  11. package/build/styles/sentimentSurface/SentimentSurface.css +80 -20
  12. package/build/types/button/_stories/helpers.d.ts +11 -0
  13. package/build/types/button/_stories/helpers.d.ts.map +1 -0
  14. package/build/types/index.d.ts +4 -0
  15. package/build/types/index.d.ts.map +1 -1
  16. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts +3 -1
  17. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -1
  18. package/build/types/test-utils/story-config.d.ts +1 -1
  19. package/build/types/test-utils/story-config.d.ts.map +1 -1
  20. package/package.json +1 -1
  21. package/src/alert/Alert.story.tsx +1 -1
  22. package/src/alert/Alert.tests.story.tsx +1 -1
  23. package/src/button/Button.css +5 -5
  24. package/src/button/Button.vars.css +5 -5
  25. package/src/button/Button.vars.less +28 -7
  26. package/src/button/{Button.accessibility.docs.mdx → _stories/Button.accessibility.docs.mdx} +1 -1
  27. package/src/button/_stories/Button.brightGreen.tests.story.tsx +31 -0
  28. package/src/button/_stories/Button.dark.tests.story.tsx +25 -0
  29. package/src/button/_stories/Button.default.tests.story.tsx +25 -0
  30. package/src/button/_stories/Button.forestGreen.tests.story.tsx +28 -0
  31. package/src/button/{Button.story.tsx → _stories/Button.story.tsx} +6 -6
  32. package/src/button/{Button.tests.story.tsx → _stories/Button.tests.story.tsx} +5 -82
  33. package/src/button/_stories/helpers.tsx +118 -0
  34. package/src/criticalBanner/CriticalCommsBanner.story.tsx +1 -1
  35. package/src/iconButton/IconButton.story.tsx +2 -2
  36. package/src/index.ts +4 -0
  37. package/src/inlineAlert/InlineAlert.story.tsx +1 -1
  38. package/src/link/Link.story.tsx +2 -2
  39. package/src/main.css +85 -25
  40. package/src/nudge/Nudge.story.tsx +1 -1
  41. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +41 -2
  42. package/src/prompt/InlinePrompt/InlinePrompt.tsx +3 -1
  43. package/src/provider/theme/ThemeProvider.story.tsx +1 -1
  44. package/src/sentimentSurface/SentimentSurface.css +80 -20
  45. package/src/sentimentSurface/SentimentSurface.less +40 -10
  46. package/src/sentimentSurface/SentimentSurface.story.tsx +163 -102
  47. package/src/sentimentSurface/SentimentSurface.tests.story.tsx +6 -2
  48. package/src/test-utils/story-config.ts +5 -0
  49. package/src/{neptune-css/NeptuneCSS.story.tsx → tokens/tokens.story.tsx} +2 -2
  50. package/src/withId/withId.story.tsx +1 -0
@@ -6,7 +6,10 @@
6
6
 
7
7
  &-negative {
8
8
  .np-theme-personal &,
9
- .np-theme-personal--bright-green & {
9
+ .np-theme-business &,
10
+ .np-theme-platform &,
11
+ .np-theme-personal--bright-green &,
12
+ .np-theme-business--bright-green & {
10
13
  &-base {
11
14
  .sentiment-surface-tokens(
12
15
  #CB272F, #B8232B, #A72027,
@@ -30,7 +33,10 @@
30
33
  }
31
34
 
32
35
  .np-theme-personal--dark &,
33
- .np-theme-personal--forest-green & {
36
+ .np-theme-business--dark &,
37
+ .np-theme-personal--forest-green &,
38
+ .np-theme-business--forest-green &,
39
+ .np-theme-platform--forest-green & {
34
40
  &-base {
35
41
  .sentiment-surface-tokens(
36
42
  #FFA8AD, #FFBDC0, #FFD1D3,
@@ -56,7 +62,10 @@
56
62
 
57
63
  &-warning {
58
64
  .np-theme-personal &,
59
- .np-theme-personal--bright-green & {
65
+ .np-theme-business &,
66
+ .np-theme-platform &,
67
+ .np-theme-personal--bright-green &,
68
+ .np-theme-business--bright-green & {
60
69
  &-base {
61
70
  .sentiment-surface-tokens(
62
71
  #4A3B1C, #302612, #2C2311, // content-primary (default, hover, active)
@@ -80,7 +89,10 @@
80
89
  }
81
90
 
82
91
  .np-theme-personal--dark &,
83
- .np-theme-personal--forest-green & {
92
+ .np-theme-business--dark &,
93
+ .np-theme-personal--forest-green &,
94
+ .np-theme-business--forest-green &,
95
+ .np-theme-platform--forest-green & {
84
96
  &-base {
85
97
  .sentiment-surface-tokens(
86
98
  #FADC65, #F9D648, #F8CD20, // content-primary
@@ -105,7 +117,10 @@
105
117
  }
106
118
  &-success {
107
119
  .np-theme-personal &,
108
- .np-theme-personal--bright-green & {
120
+ .np-theme-business &,
121
+ .np-theme-platform &,
122
+ .np-theme-personal--bright-green &,
123
+ .np-theme-business--bright-green & {
109
124
  &-base {
110
125
  .sentiment-surface-tokens(
111
126
  #054D28, #043A1E, #022614, // content-primary (default, hover, active)
@@ -129,7 +144,10 @@
129
144
  }
130
145
 
131
146
  .np-theme-personal--dark &,
132
- .np-theme-personal--forest-green & {
147
+ .np-theme-business--dark &,
148
+ .np-theme-personal--forest-green &,
149
+ .np-theme-business--forest-green &,
150
+ .np-theme-platform--forest-green & {
133
151
  &-base {
134
152
  .sentiment-surface-tokens(
135
153
  #BAE5A0, #C8EAB3, #D6F0C7, // content-primary
@@ -154,7 +172,10 @@
154
172
  }
155
173
  &-neutral {
156
174
  .np-theme-personal &,
157
- .np-theme-personal--bright-green & {
175
+ .np-theme-business &,
176
+ .np-theme-platform &,
177
+ .np-theme-personal--bright-green &,
178
+ .np-theme-business--bright-green & {
158
179
  &-base {
159
180
  .sentiment-surface-tokens(
160
181
  #454745, #353635, #232423, // content-primary (default, hover, active)
@@ -178,7 +199,10 @@
178
199
  }
179
200
 
180
201
  .np-theme-personal--dark &,
181
- .np-theme-personal--forest-green & {
202
+ .np-theme-business--dark &,
203
+ .np-theme-personal--forest-green &,
204
+ .np-theme-business--forest-green &,
205
+ .np-theme-platform--forest-green & {
182
206
  &-base {
183
207
  .sentiment-surface-tokens(
184
208
  #F1F1ED, #E7E7E1, #DFDED5, // content-primary
@@ -203,7 +227,10 @@
203
227
  }
204
228
  &-proposition {
205
229
  .np-theme-personal &,
206
- .np-theme-personal--bright-green & {
230
+ .np-theme-business &,
231
+ .np-theme-platform &,
232
+ .np-theme-personal--bright-green &,
233
+ .np-theme-business--bright-green & {
207
234
  &-base {
208
235
  .sentiment-surface-tokens(
209
236
  #0E0F0C, #0A2826, #074140, // content-primary (default, hover, active)
@@ -227,7 +254,10 @@
227
254
  }
228
255
 
229
256
  .np-theme-personal--dark &,
230
- .np-theme-personal--forest-green & {
257
+ .np-theme-business--dark &,
258
+ .np-theme-personal--forest-green &,
259
+ .np-theme-business--forest-green &,
260
+ .np-theme-platform--forest-green & {
231
261
  &-base {
232
262
  .sentiment-surface-tokens(
233
263
  #FFFFFF, #EAF9F9, #D5F4F4, // content-primary
@@ -1,11 +1,12 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
- import { Defrost } from '@transferwise/icons';
2
+ import { Bank, Defrost } from '@transferwise/icons';
3
3
  import Body from '../body';
4
4
  import Button from '../button';
5
5
  import Header from '../header';
6
6
  import Link from '../link';
7
7
  import IconButton from '../iconButton';
8
8
  import StatusIcon from '../statusIcon';
9
+ import AvatarView from '../avatarView';
9
10
  import SentimentSurface from './SentimentSurface';
10
11
  import type { Sentiment, Emphasis } from './SentimentSurface.types';
11
12
 
@@ -30,7 +31,7 @@ const withComponentGrid = (Story: () => JSX.Element) => (
30
31
  */
31
32
  const meta: Meta<typeof SentimentSurface> = {
32
33
  component: SentimentSurface,
33
- title: 'Content/SentimentSurface',
34
+ title: 'Foundations/SentimentSurface',
34
35
  argTypes: {
35
36
  sentiment: {
36
37
  control: 'select',
@@ -228,12 +229,12 @@ export const EmphasisLevels: Story = {
228
229
 
229
230
  /**
230
231
  * By default, `SentimentSurface` exposes the tokens as CSS custom properties and also applies
231
- * the base styles for `background-color` and `color`.
232
- * However, you can choose to only expose the CSS custom properties by setting the `hasBaseStyles`
233
- * prop to `false`. This is useful when you want to create custom components that adapt to the
234
- * sentiment context without applying default styles.
232
+ * the base styles for `background-color` and `color`. However, you can choose to expose said
233
+ * properties without rendering them, by setting the `hasBaseStyles` prop to `false`.
234
+ * This is useful when you want to create custom components that adapt to the sentiment context
235
+ * without applying default styles.
235
236
  */
236
- export const BaseStyles: Story = {
237
+ export const RenderingBaseStyles: Story = {
237
238
  render: (args) => (
238
239
  <>
239
240
  <SentimentSurface
@@ -243,8 +244,8 @@ export const BaseStyles: Story = {
243
244
  <div className="p-a-2">This example exposes and applies the tokens.</div>
244
245
  </SentimentSurface>
245
246
  <SentimentSurface
246
- hasBaseStyles={false}
247
247
  sentiment="success"
248
+ hasBaseStyles={false}
248
249
  style={{ border: `1px dashed var(--color-sentiment-content-primary)` }}
249
250
  >
250
251
  <div className="p-a-2">This example only exposes the tokens without applying them.</div>
@@ -260,85 +261,25 @@ export const BaseStyles: Story = {
260
261
  </SentimentSurface>
261
262
  </>
262
263
  ),
263
- parameters: {
264
- controls: { disable: true },
265
- },
266
- decorators: [withComponentGrid],
267
- };
268
-
269
- /**
270
- * The component exposes token groups for all 5 sentiment types (`negative`, `warning`, `neutral`, `proposition` and `success`) each of them with two emphasis levels (`base` and `elevated`).
271
- */
272
- export const ExposedTokens: Story = {
273
- render: () => (
274
- <section style={{ display: 'flex', flexDirection: 'column', gap: '32px', maxWidth: '100%' }}>
275
- {sentiments.map((sentiment) =>
276
- emphasisLevels.map((emphasis) => (
277
- <SentimentSurface
278
- key={`${sentiment}-${emphasis}`}
279
- sentiment={sentiment}
280
- emphasis={emphasis}
281
- style={{
282
- padding: '24px',
283
- borderRadius: '16px',
284
- }}
285
- >
286
- <h4
287
- className="d-block m-b-2 text-capitalize np-text-title-body"
288
- style={{
289
- color: 'inherit',
290
- }}
291
- >
292
- {sentiment} - {emphasis}
293
- </h4>
294
- <div
295
- style={{
296
- display: 'grid',
297
- gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
298
- gap: '24px',
299
- }}
300
- >
301
- {tokenCategories.map((category) => (
302
- <div key={category.name}>
303
- <h5
304
- style={{
305
- color: 'inherit',
306
- fontSize: '12px',
307
- fontWeight: 600,
308
- marginBottom: '8px',
309
- textTransform: 'uppercase',
310
- letterSpacing: '0.5px',
311
- opacity: 0.8,
312
- }}
313
- >
314
- {category.name}
315
- </h5>
316
- {category.tokens.map((token) => (
317
- <TokenSwatch key={token} token={token} />
318
- ))}
319
- </div>
320
- ))}
321
- </div>
322
- </SentimentSurface>
323
- )),
324
- )}
325
- </section>
326
- ),
327
264
  parameters: {
328
265
  controls: { disable: true },
329
266
  docs: {
330
- canvas: {
331
- sourceState: 'hidden',
267
+ source: {
268
+ // Storybook strips out props that are set to false, so we need to hack it back in :/
269
+ transform: async (source: string) => {
270
+ if (source.includes('hasBaseStyles')) {
271
+ return source;
272
+ }
273
+
274
+ return source.replace(
275
+ /(<\/SentimentSurface>\s+<SentimentSurface(\s+)sentiment="success")/g,
276
+ '$1$2hasBaseStyles={false}',
277
+ );
278
+ },
332
279
  },
333
280
  },
334
281
  },
335
- decorators: [
336
- (Story: () => JSX.Element) => (
337
- <div style={{ padding: '2rem', maxWidth: '1200px' }}>
338
- <Story />
339
- </div>
340
- ),
341
- ],
282
+ decorators: [withComponentGrid],
342
283
  };
343
284
 
344
285
  /**
@@ -348,6 +289,12 @@ export const NestingSurfaces: Story = {
348
289
  parameters: {
349
290
  controls: { disable: true },
350
291
  },
292
+ /**
293
+ * As agreed with the design team, this story is temporarily hidden from the public view until we
294
+ * have proper discussion and documentation around when and how to use nested SentimentSurfaces.
295
+ * This is to prevent misuse and confusion among consumers.
296
+ */
297
+ tags: ['!dev', '!autodocs'],
351
298
  render: (args) => {
352
299
  return (
353
300
  <SentimentSurface sentiment="success" emphasis="base" className="p-a-1">
@@ -364,7 +311,9 @@ export const NestingSurfaces: Story = {
364
311
  };
365
312
 
366
313
  /**
367
- * Some DS components (namely `Button`, `StatusIcon`, and `IconButton`) automatically adapt to the sentiment context when used within a `SentimentSurface`.
314
+ * Some DS components (namely `Button`, `Link`, `StatusIcon`, `IconButton`) automatically adapt to the sentiment context when used within a `SentimentSurface`. <br/>
315
+ *
316
+ * > ⚠️ You should not mix sentiments within the same surface. For example, avoid using a `StatusIcon` with `sentiment="negative"` inside a `SentimentSurface` with `sentiment="success"`.
368
317
  */
369
318
  export const SentimentAwareComponents: Story = {
370
319
  name: 'Sentiment-aware Components',
@@ -377,34 +326,71 @@ export const SentimentAwareComponents: Story = {
377
326
  },
378
327
  },
379
328
  render: function Render(args) {
380
- const inner = (
381
- <div className="p-a-2 m-b-2 sentimentAwareComponent">
382
- <Body>
383
- This text and its <Link href="#">inline links</Link> should use sentiment-matched colour.
384
- </Body>
385
- <IconButton size={32}>
386
- <Defrost />
387
- </IconButton>
388
- <StatusIcon size={32} sentiment="positive" />
389
- <Button v2 priority="primary" size="sm">
390
- Primary
391
- </Button>
392
- <Button v2 priority="secondary" size="sm">
393
- Secondary
394
- </Button>
395
- </div>
329
+ const BODY = [
330
+ <Body key="body">
331
+ This text and its <Link href="#">inline links</Link> should use sentiment-matched colour.
332
+ </Body>,
333
+ <Button key="button1" v2 priority="primary" size="sm">
334
+ Primary
335
+ </Button>,
336
+ <Button key="button2" v2 priority="secondary" size="sm">
337
+ Secondary
338
+ </Button>,
339
+ <IconButton key="iconButton" size={32}>
340
+ <Defrost />
341
+ </IconButton>,
342
+ <AvatarView key="avatar" size={32}>
343
+ <Bank />
344
+ </AvatarView>,
345
+ <AvatarView key="avatar-initials" size={32} profileName="John Doe" />,
346
+ ];
347
+ const STATUS_SUCCESS = <StatusIcon size={32} sentiment="success" />;
348
+ const STATUS_NEGATIVE = <StatusIcon size={32} sentiment="negative" />;
349
+ const AVATAR_SUCCESS = (
350
+ <AvatarView
351
+ size={32}
352
+ imgSrc="../avatar-rectangle-fox.webp"
353
+ badge={{ status: 'success' }}
354
+ interactive
355
+ />
356
+ );
357
+ const AVATAR_NEGATIVE = (
358
+ <AvatarView
359
+ size={32}
360
+ imgSrc="../avatar-rectangle-fox.webp"
361
+ badge={{ status: 'negative' }}
362
+ interactive
363
+ />
396
364
  );
397
365
 
398
366
  return (
399
367
  <>
400
- <Header level="group" title="No sentiment surface" />
401
- {inner}
368
+ <Header level="group" title="Plain container" />
369
+ <div className="p-a-2 m-b-2 sentimentAwareComponent">
370
+ {BODY}
371
+ {AVATAR_SUCCESS}
372
+ {AVATAR_NEGATIVE}
373
+ {STATUS_SUCCESS}
374
+ {STATUS_NEGATIVE}
375
+ </div>
402
376
 
403
377
  <Header level="group" title="Success sentiment surface" />
404
- <SentimentSurface sentiment="success">{inner}</SentimentSurface>
378
+ <SentimentSurface sentiment="success">
379
+ <div className="p-a-2 m-b-2 sentimentAwareComponent">
380
+ {BODY}
381
+ {AVATAR_SUCCESS}
382
+ {STATUS_SUCCESS}
383
+ </div>
384
+ </SentimentSurface>
405
385
 
406
386
  <Header level="group" title="Negative sentiment surface" />
407
- <SentimentSurface sentiment="negative">{inner}</SentimentSurface>
387
+ <SentimentSurface sentiment="negative">
388
+ <div className="p-a-2 m-b-2 sentimentAwareComponent">
389
+ {BODY}
390
+ {AVATAR_NEGATIVE}
391
+ {STATUS_NEGATIVE}
392
+ </div>
393
+ </SentimentSurface>
408
394
  </>
409
395
  );
410
396
  },
@@ -516,3 +502,78 @@ function View() {
516
502
  },
517
503
  },
518
504
  };
505
+
506
+ /**
507
+ * The component exposes token groups for all 5 sentiment types (`negative`, `warning`, `neutral`, `proposition` and `success`) each of them with two emphasis levels (`base` and `elevated`).
508
+ */
509
+ export const ExposedTokens: Story = {
510
+ render: () => (
511
+ <section style={{ display: 'flex', flexDirection: 'column', gap: '32px', maxWidth: '100%' }}>
512
+ {sentiments.map((sentiment) =>
513
+ emphasisLevels.map((emphasis) => (
514
+ <SentimentSurface
515
+ key={`${sentiment}-${emphasis}`}
516
+ sentiment={sentiment}
517
+ emphasis={emphasis}
518
+ style={{
519
+ padding: '24px',
520
+ borderRadius: '16px',
521
+ }}
522
+ >
523
+ <h4
524
+ className="d-block m-b-2 text-capitalize np-text-title-body"
525
+ style={{
526
+ color: 'inherit',
527
+ }}
528
+ >
529
+ {sentiment} - {emphasis}
530
+ </h4>
531
+ <div
532
+ style={{
533
+ display: 'grid',
534
+ gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
535
+ gap: '24px',
536
+ }}
537
+ >
538
+ {tokenCategories.map((category) => (
539
+ <div key={category.name}>
540
+ <h5
541
+ style={{
542
+ color: 'inherit',
543
+ fontSize: '12px',
544
+ fontWeight: 600,
545
+ marginBottom: '8px',
546
+ textTransform: 'uppercase',
547
+ letterSpacing: '0.5px',
548
+ opacity: 0.8,
549
+ }}
550
+ >
551
+ {category.name}
552
+ </h5>
553
+ {category.tokens.map((token) => (
554
+ <TokenSwatch key={token} token={token} />
555
+ ))}
556
+ </div>
557
+ ))}
558
+ </div>
559
+ </SentimentSurface>
560
+ )),
561
+ )}
562
+ </section>
563
+ ),
564
+ parameters: {
565
+ controls: { disable: true },
566
+ docs: {
567
+ canvas: {
568
+ sourceState: 'hidden',
569
+ },
570
+ },
571
+ },
572
+ decorators: [
573
+ (Story: () => JSX.Element) => (
574
+ <div style={{ padding: '2rem', maxWidth: '1200px' }}>
575
+ <Story />
576
+ </div>
577
+ ),
578
+ ],
579
+ };
@@ -1,7 +1,7 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { ThemeProvider, type Theming } from '@wise/components-theming';
3
- import SentimentSurface from './SentimentSurface';
4
3
  import Button from '../button';
4
+ import SentimentSurface from './SentimentSurface';
5
5
  import type { Sentiment, Emphasis } from './SentimentSurface.types';
6
6
 
7
7
  const sentiments: Sentiment[] = ['negative', 'success', 'proposition', 'warning', 'neutral'];
@@ -21,13 +21,14 @@ const screenModes: Theming['screenMode'][] = ['light', 'dark'];
21
21
 
22
22
  export default {
23
23
  component: SentimentSurface,
24
- title: 'Content/SentimentSurface/Tests',
24
+ title: 'Foundations/SentimentSurface/Tests',
25
25
  tags: ['!autodocs'],
26
26
  } satisfies Meta<typeof SentimentSurface>;
27
27
 
28
28
  type Story = StoryObj<typeof SentimentSurface>;
29
29
 
30
30
  export const NestedSentiments: Story = {
31
+ tags: ['!dev'],
31
32
  render: () => (
32
33
  <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
33
34
  <SentimentSurface sentiment="negative" emphasis="base">
@@ -86,6 +87,9 @@ const ButtonsGrid = () => (
86
87
  <Button v2 priority="secondary-neutral" style={{ marginLeft: '8px' }}>
87
88
  Secondary Neutral
88
89
  </Button>
90
+ <Button v2 priority="tertiary" style={{ marginLeft: '8px' }}>
91
+ Tertiary
92
+ </Button>
89
93
  </SentimentSurface>
90
94
  )),
91
95
  )}
@@ -36,6 +36,11 @@ export interface StoryConfig {
36
36
  | 'dark'
37
37
  | 'bright-green'
38
38
  | 'forest-green'
39
+ | 'business'
40
+ | 'business--forest-green'
41
+ | 'business--bright-green'
42
+ | 'platform'
43
+ | 'platform--forest-green'
39
44
  | 'rtl'
40
45
  | 'mobile'
41
46
  | '400%'
@@ -7,8 +7,8 @@ import IconButton from '../iconButton';
7
7
  import Body from '../body';
8
8
 
9
9
  const meta: Meta = {
10
- title: 'NeptuneCSS',
11
- component: () => <div>NeptuneCSS Example</div>,
10
+ title: 'Foundations/tokens',
11
+ tags: ['!autodocs'],
12
12
  };
13
13
 
14
14
  export default meta;
@@ -26,6 +26,7 @@ DescribedButton.displayName = 'DescribedButton';
26
26
 
27
27
  export default {
28
28
  component: DescribedButton,
29
+ title: 'HoCs/withId',
29
30
  tags: ['docs-only'],
30
31
  } satisfies Meta<typeof withId>;
31
32