@transferwise/components 46.115.1 → 46.116.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 (65) hide show
  1. package/build/criticalBanner/CriticalCommsBanner.js +1 -0
  2. package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
  3. package/build/criticalBanner/CriticalCommsBanner.mjs +1 -0
  4. package/build/criticalBanner/CriticalCommsBanner.mjs.map +1 -1
  5. package/build/main.css +428 -36
  6. package/build/mocks.js +7 -0
  7. package/build/mocks.js.map +1 -1
  8. package/build/mocks.mjs +7 -1
  9. package/build/mocks.mjs.map +1 -1
  10. package/build/sentimentSurface/SentimentSurface.js +43 -0
  11. package/build/sentimentSurface/SentimentSurface.js.map +1 -0
  12. package/build/sentimentSurface/SentimentSurface.mjs +39 -0
  13. package/build/sentimentSurface/SentimentSurface.mjs.map +1 -0
  14. package/build/sentimentSurface/classMap.js +17 -0
  15. package/build/sentimentSurface/classMap.js.map +1 -0
  16. package/build/sentimentSurface/classMap.mjs +14 -0
  17. package/build/sentimentSurface/classMap.mjs.map +1 -0
  18. package/build/statusIcon/StatusIcon.js +10 -1
  19. package/build/statusIcon/StatusIcon.js.map +1 -1
  20. package/build/statusIcon/StatusIcon.mjs +10 -1
  21. package/build/statusIcon/StatusIcon.mjs.map +1 -1
  22. package/build/styles/main.css +428 -36
  23. package/build/styles/sentimentSurface/SentimentSurface.css +424 -0
  24. package/build/styles/statusIcon/StatusIcon.css +4 -36
  25. package/build/types/criticalBanner/CriticalCommsBanner.d.ts +2 -1
  26. package/build/types/criticalBanner/CriticalCommsBanner.d.ts.map +1 -1
  27. package/build/types/mocks.d.ts +1 -0
  28. package/build/types/mocks.d.ts.map +1 -1
  29. package/build/types/sentimentSurface/SentimentSurface.d.ts +30 -0
  30. package/build/types/sentimentSurface/SentimentSurface.d.ts.map +1 -0
  31. package/build/types/sentimentSurface/SentimentSurface.types.d.ts +80 -0
  32. package/build/types/sentimentSurface/SentimentSurface.types.d.ts.map +1 -0
  33. package/build/types/sentimentSurface/classMap.d.ts +4 -0
  34. package/build/types/sentimentSurface/classMap.d.ts.map +1 -0
  35. package/build/types/sentimentSurface/index.d.ts +3 -0
  36. package/build/types/sentimentSurface/index.d.ts.map +1 -0
  37. package/build/types/statusIcon/StatusIcon.d.ts.map +1 -1
  38. package/build/types/test-utils/window-mock.d.ts +1 -0
  39. package/build/types/test-utils/window-mock.d.ts.map +1 -1
  40. package/package.json +2 -2
  41. package/src/criticalBanner/CriticalCommsBanner.tsx +3 -2
  42. package/src/expressiveMoneyInput/ExpressiveMoneyInput.spec.tsx +229 -0
  43. package/src/expressiveMoneyInput/amountInput/AmountInput.spec.tsx +282 -0
  44. package/src/expressiveMoneyInput/currencySelector/CurrencySelector.spec.tsx +160 -0
  45. package/src/inputs/SelectInput.spec.tsx +7 -1
  46. package/src/main.css +428 -36
  47. package/src/main.less +2 -0
  48. package/src/mocks.ts +7 -0
  49. package/src/moneyInput/MoneyInput.spec.tsx +9 -1
  50. package/src/provider/theme/ThemeProvider.story.tsx +78 -11
  51. package/src/sentimentSurface/SentimentSurface.css +424 -0
  52. package/src/sentimentSurface/SentimentSurface.docs.mdx +527 -0
  53. package/src/sentimentSurface/SentimentSurface.less +296 -0
  54. package/src/sentimentSurface/SentimentSurface.spec.tsx +140 -0
  55. package/src/sentimentSurface/SentimentSurface.story.tsx +340 -0
  56. package/src/sentimentSurface/SentimentSurface.tests.story.tsx +123 -0
  57. package/src/sentimentSurface/SentimentSurface.tsx +72 -0
  58. package/src/sentimentSurface/SentimentSurface.types.ts +104 -0
  59. package/src/sentimentSurface/classMap.ts +15 -0
  60. package/src/sentimentSurface/index.ts +8 -0
  61. package/src/statusIcon/StatusIcon.css +4 -36
  62. package/src/statusIcon/StatusIcon.less +3 -41
  63. package/src/statusIcon/StatusIcon.tsx +14 -1
  64. package/src/test-utils/jest.setup.ts +0 -5
  65. package/src/test-utils/window-mock.ts +5 -0
@@ -0,0 +1,527 @@
1
+ import { Meta, Source, ArgTypes } from '@storybook/addon-docs/blocks';
2
+ import * as SentimentSurfaceStories from './SentimentSurface.story';
3
+
4
+ <Meta title="Content/SentimentSurface/Developer Guide" />
5
+
6
+ # SentimentSurface Developer Guide
7
+
8
+ `SentimentSurface` is a polymorphic container component that applies contextual background colours and text styling based on sentiment types. It's designed to visually communicate the nature or importance of content through colour and establish a semantic colour context for nested interactive components.
9
+
10
+ ## Basic Usage
11
+
12
+ Import and use the component with a required `sentiment` prop:
13
+
14
+ <Source dark code={`
15
+ import { SentimentSurface } from '@transferwise/components';
16
+
17
+ <SentimentSurface sentiment="negative">Your payment has failed</SentimentSurface>
18
+ `} />
19
+
20
+ ### Props
21
+
22
+ <ArgTypes of={SentimentSurfaceStories} />
23
+
24
+ ## Sentiment Types
25
+
26
+ The component supports five sentiment types (`negative`, `warning`, `neutral`, `proposition` and `success`), each communicating different types of information:
27
+
28
+ ```tsx
29
+ <SentimentSurface sentiment="negative">
30
+ Your payment has failed. Please try again.
31
+ </SentimentSurface>
32
+
33
+ <SentimentSurface sentiment="warning">
34
+ Action required: Please verify your email address.
35
+ </SentimentSurface>
36
+
37
+ <SentimentSurface sentiment="neutral">
38
+ Your account is up to date.
39
+ </SentimentSurface>
40
+
41
+ <SentimentSurface sentiment="proposition">
42
+ Try our new feature and save time on transfers.
43
+ </SentimentSurface>
44
+
45
+ <SentimentSurface sentiment="success">
46
+ Your payment was successful!
47
+ </SentimentSurface>
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Emphasis Levels
53
+
54
+ Each sentiment type supports two emphasis levels to provide different levels of visual prominence (`base`, `elevated`):
55
+
56
+ ```tsx
57
+ <SentimentSurface sentiment="success" emphasis="base">
58
+ Base emphasis - subtle background
59
+ </SentimentSurface>
60
+
61
+ <SentimentSurface sentiment="success" emphasis="elevated">
62
+ Elevated emphasis - strong background
63
+ </SentimentSurface>
64
+ ```
65
+
66
+ **When to use:**
67
+
68
+ - **Base**: For inline notifications, subtle callouts, or when sentiment needs to be communicated without drawing too much attention
69
+ - **Elevated**: For prominent banners, critical alerts, or when the sentiment should be immediately noticeable
70
+
71
+ ---
72
+
73
+ ## Polymorphic Rendering
74
+
75
+ The component is fully polymorphic, meaning it can render as any HTML element using the `as` prop while maintaining full type safety.
76
+
77
+ ### Basic Examples
78
+
79
+ ```tsx
80
+ // Render as div (default)
81
+ <SentimentSurface sentiment="neutral">
82
+ Default div element
83
+ </SentimentSurface>
84
+
85
+ // Render as section
86
+ <SentimentSurface sentiment="negative" as="section">
87
+ Semantic section element
88
+ </SentimentSurface>
89
+
90
+ // Render as article
91
+ <SentimentSurface sentiment="success" as="article">
92
+ Article element for standalone content
93
+ </SentimentSurface>
94
+ ```
95
+
96
+ ### With HTML Attributes
97
+
98
+ The component accepts all valid HTML attributes for the rendered element:
99
+
100
+ ```tsx
101
+ // Section with ARIA attributes
102
+ <SentimentSurface
103
+ sentiment="negative"
104
+ as="section"
105
+ role="alert"
106
+ aria-live="polite"
107
+ aria-atomic="true"
108
+ >
109
+ Critical error message
110
+ </SentimentSurface>
111
+
112
+ // Article with data attributes
113
+ <SentimentSurface
114
+ sentiment="proposition"
115
+ as="article"
116
+ data-tracking-id="promo-banner"
117
+ data-position="top"
118
+ >
119
+ Promotional content
120
+ </SentimentSurface>
121
+ ```
122
+
123
+ ### Type Safety
124
+
125
+ TypeScript provides full type checking for HTML attributes based on the `as` prop:
126
+
127
+ ```tsx
128
+ // ✅ Valid - section supports these attributes
129
+ <SentimentSurface as="section" role="region" aria-labelledby="heading">
130
+ Content
131
+ </SentimentSurface>
132
+
133
+ // ❌ TypeScript error - 'href' is not valid for 'div'
134
+ <SentimentSurface as="div" href="/link">
135
+ Content
136
+ </SentimentSurface>
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Nesting Sentiment Surfaces
142
+
143
+ Sentiment surfaces can be nested to create layered contexts. Each nested surface establishes its own colour context through CSS custom properties.
144
+
145
+ ### Basic Nesting
146
+
147
+ ```tsx
148
+ <SentimentSurface sentiment="negative" emphasis="base">
149
+ <Title size="large">Payment Failed</Title>
150
+ <Body>There was an issue processing your payment.</Body>
151
+
152
+ <SentimentSurface sentiment="neutral" emphasis="elevated">
153
+ <Title size="small">What happened?</Title>
154
+ <Body>Your card was declined by your bank.</Body>
155
+ </SentimentSurface>
156
+ </SentimentSurface>
157
+ ```
158
+
159
+ ### Multi-Level Nesting
160
+
161
+ ```tsx
162
+ <SentimentSurface sentiment="success" emphasis="base">
163
+ Outer: Payment successful
164
+ <SentimentSurface sentiment="neutral" emphasis="elevated">
165
+ Inner: Transaction details
166
+ <SentimentSurface sentiment="warning" emphasis="base">
167
+ Deepest: Additional fees may apply
168
+ </SentimentSurface>
169
+ </SentimentSurface>
170
+ </SentimentSurface>
171
+ ```
172
+
173
+ ### Nesting with Different Elements
174
+
175
+ ```tsx
176
+ <SentimentSurface sentiment="negative" as="section">
177
+ <Title size="large">Error Section</Title>
178
+
179
+ <SentimentSurface sentiment="neutral" as="article">
180
+ <Title size="small">Details</Title>
181
+ <Body>More information about the error.</Body>
182
+ </SentimentSurface>
183
+
184
+ <SentimentSurface sentiment="proposition" as="aside">
185
+ <Body>Need help? Contact support.</Body>
186
+ </SentimentSurface>
187
+ </SentimentSurface>
188
+ ```
189
+
190
+ ---
191
+
192
+ ## CSS Custom Properties (Tokens)
193
+
194
+ The component sets CSS custom properties (CSS variables) that child components can use to adapt their styling to the sentiment context. This enables a powerful theming system where nested components automatically adjust their appearance.
195
+
196
+ ### Available Tokens
197
+
198
+ Each `SentimentSurface` sets tokens for content, interactive elements, and background surfaces. See the [Tokens story](?path=/story/content-sentimentsurface--tokens) for a visual demonstration of all tokens across sentiments and emphasis levels:
199
+
200
+ #### Content Tokens
201
+
202
+ ```css
203
+ --color-sentiment-content-primary
204
+ --color-sentiment-content-primary-hover
205
+ --color-sentiment-content-primary-active
206
+ ```
207
+
208
+ #### Interactive Primary Tokens
209
+
210
+ ```css
211
+ --color-sentiment-interactive-primary
212
+ --color-sentiment-interactive-primary-hover
213
+ --color-sentiment-interactive-primary-active
214
+ ```
215
+
216
+ #### Interactive Secondary Tokens
217
+
218
+ ```css
219
+ --color-sentiment-interactive-secondary
220
+ --color-sentiment-interactive-secondary-hover
221
+ --color-sentiment-interactive-secondary-active
222
+ ```
223
+
224
+ #### Interactive Secondary Neutral Tokens
225
+
226
+ ```css
227
+ --color-sentiment-interactive-secondary-neutral
228
+ --color-sentiment-interactive-secondary-neutral-hover
229
+ --color-sentiment-interactive-secondary-neutral-active
230
+ ```
231
+
232
+ #### Interactive Control Tokens
233
+
234
+ ```css
235
+ --color-sentiment-interactive-control
236
+ --color-sentiment-interactive-control-hover
237
+ --color-sentiment-interactive-control-active
238
+ ```
239
+
240
+ #### Background Surface Tokens
241
+
242
+ ```css
243
+ --color-sentiment-background-surface
244
+ --color-sentiment-background-surface-hover
245
+ --color-sentiment-background-surface-active
246
+ ```
247
+
248
+ ### Using Tokens in Component Styles
249
+
250
+ Components can reference these tokens with fallbacks to maintain functionality outside of a `SentimentSurface`:
251
+
252
+ ```css
253
+ .wds-Button {
254
+ /* Primary button uses interactive primary tokens */
255
+ --Button-background: var(--color-sentiment-interactive-primary, var(--color-interactive-accent));
256
+ --Button-background-hover: var(
257
+ --color-sentiment-interactive-primary-hover,
258
+ var(--color-interactive-accent-hover)
259
+ );
260
+ --Button-background-active: var(
261
+ --color-sentiment-interactive-primary-active,
262
+ var(--color-interactive-accent-active)
263
+ );
264
+
265
+ /* Button text color uses control tokens */
266
+ --Button-color: var(--color-sentiment-interactive-control, var(--color-interactive-control));
267
+ --Button-color-hover: var(
268
+ --color-sentiment-interactive-control-hover,
269
+ var(--color-interactive-control-hover)
270
+ );
271
+ --Button-color-active: var(
272
+ --color-sentiment-interactive-control-active,
273
+ var(--color-interactive-control-active)
274
+ );
275
+ }
276
+
277
+ .wds-Button--secondary {
278
+ /* Secondary button uses secondary tokens */
279
+ --Button-background: var(
280
+ --color-sentiment-interactive-secondary,
281
+ var(--color-interactive-neutral)
282
+ );
283
+ --Button-background-hover: var(
284
+ --color-sentiment-interactive-secondary-hover,
285
+ var(--color-interactive-neutral-hover)
286
+ );
287
+ --Button-color: var(--color-sentiment-interactive-primary, var(--color-interactive-primary));
288
+ }
289
+ ```
290
+
291
+ ### Example: Button in Sentiment Context
292
+
293
+ ```tsx
294
+ import { Button, Body } from '@transferwise/components';
295
+
296
+ // Button automatically adapts to the sentiment context
297
+ <SentimentSurface sentiment="success">
298
+ <Body>Your payment was successful!</Body>
299
+ <Button v2 priority="primary">View Receipt</Button>
300
+ <Button v2 priority="secondary">Send Another</Button>
301
+ </SentimentSurface>
302
+
303
+ // Same buttons in different sentiment context
304
+ <SentimentSurface sentiment="negative">
305
+ <Body>Payment failed</Body>
306
+ <Button v2 priority="primary">Try Again</Button>
307
+ <Button v2 priority="secondary">Cancel</Button>
308
+ </SentimentSurface>
309
+ ```
310
+
311
+ The buttons will automatically use appropriate colours based on the sentiment context.
312
+
313
+ ### Creating Custom Components with Sentiment Tokens
314
+
315
+ You can create your own components that respect sentiment context:
316
+
317
+ ```tsx
318
+ // CustomCard.css
319
+ .custom-card {
320
+ background-color: var(
321
+ --color-sentiment-background-surface,
322
+ var(--color-background-surface)
323
+ );
324
+ color: var(
325
+ --color-sentiment-content-primary,
326
+ var(--color-content-primary)
327
+ );
328
+ border: 1px solid var(
329
+ --color-sentiment-interactive-secondary,
330
+ var(--color-border-neutral)
331
+ );
332
+ }
333
+
334
+ .custom-card:hover {
335
+ background-color: var(
336
+ --color-sentiment-background-surface-hover,
337
+ var(--color-background-surface-hover)
338
+ );
339
+ }
340
+
341
+ .custom-card-link {
342
+ color: var(
343
+ --color-sentiment-interactive-primary,
344
+ var(--color-interactive-primary)
345
+ );
346
+ }
347
+
348
+ .custom-card-link:hover {
349
+ color: var(
350
+ --color-sentiment-interactive-primary-hover,
351
+ var(--color-interactive-primary-hover)
352
+ );
353
+ }
354
+ ```
355
+
356
+ ```tsx
357
+ // CustomCard.tsx
358
+ function CustomCard({ children }) {
359
+ return (
360
+ <div className="custom-card">
361
+ {children}
362
+ <a href="#" className="custom-card-link">
363
+ Learn more
364
+ </a>
365
+ </div>
366
+ );
367
+ }
368
+
369
+ // Usage
370
+ <SentimentSurface sentiment="warning">
371
+ <CustomCard>This card adapts to the warning sentiment</CustomCard>
372
+ </SentimentSurface>;
373
+ ```
374
+
375
+ ---
376
+
377
+ ## Accessibility Considerations
378
+
379
+ ### Semantic HTML
380
+
381
+ Use appropriate HTML elements via the `as` prop to ensure proper document structure:
382
+
383
+ ```tsx
384
+ // ✅ Good - semantic HTML for alerts
385
+ <SentimentSurface
386
+ sentiment="negative"
387
+ as="section"
388
+ role="alert"
389
+ aria-live="assertive"
390
+ >
391
+ Critical error: Payment failed
392
+ </SentimentSurface>
393
+
394
+ // ✅ Good - article for standalone content
395
+ <SentimentSurface sentiment="proposition" as="article">
396
+ <Title size="large">New Feature Available</Title>
397
+ <Body>Try our new instant transfer feature...</Body>
398
+ </SentimentSurface>
399
+ ```
400
+
401
+ ### ARIA Attributes
402
+
403
+ Add appropriate ARIA attributes for screen readers:
404
+
405
+ ```tsx
406
+ // For errors or critical warnings
407
+ <SentimentSurface
408
+ sentiment="negative"
409
+ role="alert"
410
+ aria-live="assertive"
411
+ aria-atomic="true"
412
+ >
413
+ Error: Your session has expired
414
+ </SentimentSurface>
415
+
416
+ // For important but not critical information
417
+ <SentimentSurface
418
+ sentiment="warning"
419
+ role="status"
420
+ aria-live="polite"
421
+ >
422
+ Please verify your email address
423
+ </SentimentSurface>
424
+
425
+ // For regions with headings
426
+ <SentimentSurface
427
+ sentiment="success"
428
+ as="section"
429
+ role="region"
430
+ aria-labelledby="success-heading"
431
+ >
432
+ <Title id="success-heading" size="large">Payment Successful</Title>
433
+ <Body>Your payment has been processed.</Body>
434
+ </SentimentSurface>
435
+ ```
436
+
437
+ ### Color Contrast
438
+
439
+ The component is designed with WCAG AA contrast ratios in mind:
440
+
441
+ - **Base emphasis**: Provides sufficient contrast for body text
442
+ - **Elevated emphasis**: Provides higher contrast, often with inverted colours
443
+
444
+ Always test your content for contrast compliance, especially when:
445
+
446
+ - Adding custom text colours via `style` or `className`
447
+ - Using small text sizes
448
+ - Displaying important information
449
+
450
+ ### Don't Rely on Color Alone
451
+
452
+ Sentiment should not be conveyed through colour alone. Always include:
453
+
454
+ ```tsx
455
+ // ✅ Good - includes text and icons
456
+ <SentimentSurface sentiment="negative">
457
+ <ErrorIcon aria-hidden="true" />
458
+ <strong>Error:</strong> Payment failed
459
+ </SentimentSurface>
460
+
461
+ // ❌ Bad - relies only on colour
462
+ <SentimentSurface sentiment="negative">
463
+ Payment failed
464
+ </SentimentSurface>
465
+ ```
466
+
467
+ ### Focus Management
468
+
469
+ When using for alerts, consider focus management:
470
+
471
+ ```tsx
472
+ function ErrorBanner({ error }) {
473
+ const errorRef = useRef<HTMLElement>(null);
474
+
475
+ useEffect(() => {
476
+ if (error && errorRef.current) {
477
+ errorRef.current.focus();
478
+ }
479
+ }, [error]);
480
+
481
+ if (!error) return null;
482
+
483
+ return (
484
+ <SentimentSurface
485
+ ref={errorRef}
486
+ sentiment="negative"
487
+ as="section"
488
+ role="alert"
489
+ tabIndex={-1}
490
+ aria-live="assertive"
491
+ >
492
+ {error.message}
493
+ </SentimentSurface>
494
+ );
495
+ }
496
+ ```
497
+
498
+ ---
499
+
500
+ ## Best Practices
501
+
502
+ ### Do's
503
+
504
+ ✅ Use semantic HTML elements via the `as` prop
505
+ ✅ Include ARIA attributes for screen readers
506
+ ✅ Combine colour with icons and text for clarity
507
+ ✅ Use appropriate sentiment types for the content
508
+ ✅ Leverage CSS tokens for consistent theming
509
+ ✅ Test contrast ratios for accessibility
510
+ ✅ Provide focus management for critical alerts
511
+
512
+ ### Don'ts
513
+
514
+ ❌ Don't rely solely on colour to convey meaning
515
+ ❌ Don't nest too many levels (3+ levels can be confusing)
516
+ ❌ Don't override sentiment tokens without good reason
517
+ ❌ Don't use `sentiment="negative"` for informational content
518
+ ❌ Don't forget to test with screen readers
519
+
520
+ ---
521
+
522
+ ## Further Reading
523
+
524
+ - [Component Source Code](./SentimentSurface.tsx)
525
+ - [Storybook Examples](?path=/docs/content-sentimentsurface--docs)
526
+ - [WCAG Color Contrast Guidelines](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html)
527
+ - [ARIA Live Regions](https://www.w3.org/WAI/WCAG21/Understanding/status-messages.html)