@transferwise/components 46.136.1 → 46.137.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 (153) hide show
  1. package/build/common/hooks/useContainerSize.js +30 -0
  2. package/build/common/hooks/useContainerSize.js.map +1 -0
  3. package/build/common/hooks/useContainerSize.mjs +28 -0
  4. package/build/common/hooks/useContainerSize.mjs.map +1 -0
  5. package/build/common/hooks/useResizeObserver.js +3 -3
  6. package/build/common/hooks/useResizeObserver.js.map +1 -1
  7. package/build/common/hooks/useResizeObserver.mjs +3 -3
  8. package/build/common/hooks/useResizeObserver.mjs.map +1 -1
  9. package/build/criticalBanner/CriticalCommsBanner.js +3 -0
  10. package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
  11. package/build/criticalBanner/CriticalCommsBanner.mjs +3 -0
  12. package/build/criticalBanner/CriticalCommsBanner.mjs.map +1 -1
  13. package/build/field/Field.js +3 -2
  14. package/build/field/Field.js.map +1 -1
  15. package/build/field/Field.mjs +3 -2
  16. package/build/field/Field.mjs.map +1 -1
  17. package/build/i18n/en.json +2 -0
  18. package/build/i18n/en.json.js +2 -0
  19. package/build/i18n/en.json.js.map +1 -1
  20. package/build/i18n/en.json.mjs +2 -0
  21. package/build/i18n/en.json.mjs.map +1 -1
  22. package/build/index.js +2 -0
  23. package/build/index.js.map +1 -1
  24. package/build/index.mjs +1 -0
  25. package/build/index.mjs.map +1 -1
  26. package/build/listItem/Prompt/ListItemPrompt.js +3 -2
  27. package/build/listItem/Prompt/ListItemPrompt.js.map +1 -1
  28. package/build/listItem/Prompt/ListItemPrompt.mjs +3 -2
  29. package/build/listItem/Prompt/ListItemPrompt.mjs.map +1 -1
  30. package/build/logo/Logo.js +77 -25
  31. package/build/logo/Logo.js.map +1 -1
  32. package/build/logo/Logo.mjs +79 -27
  33. package/build/logo/Logo.mjs.map +1 -1
  34. package/build/logo/logo-assets.js +68 -97
  35. package/build/logo/logo-assets.js.map +1 -1
  36. package/build/logo/logo-assets.mjs +62 -90
  37. package/build/logo/logo-assets.mjs.map +1 -1
  38. package/build/main.css +225 -58
  39. package/build/prompt/ActionPrompt/ActionPrompt.js +8 -40
  40. package/build/prompt/ActionPrompt/ActionPrompt.js.map +1 -1
  41. package/build/prompt/ActionPrompt/ActionPrompt.mjs +8 -40
  42. package/build/prompt/ActionPrompt/ActionPrompt.mjs.map +1 -1
  43. package/build/prompt/CriticalBanner/CriticalBanner.js +143 -0
  44. package/build/prompt/CriticalBanner/CriticalBanner.js.map +1 -0
  45. package/build/prompt/CriticalBanner/CriticalBanner.mjs +141 -0
  46. package/build/prompt/CriticalBanner/CriticalBanner.mjs.map +1 -0
  47. package/build/prompt/CriticalBanner/helpers.js +29 -0
  48. package/build/prompt/CriticalBanner/helpers.js.map +1 -0
  49. package/build/prompt/CriticalBanner/helpers.mjs +26 -0
  50. package/build/prompt/CriticalBanner/helpers.mjs.map +1 -0
  51. package/build/prompt/InfoPrompt/InfoPrompt.js +3 -2
  52. package/build/prompt/InfoPrompt/InfoPrompt.js.map +1 -1
  53. package/build/prompt/InfoPrompt/InfoPrompt.mjs +3 -2
  54. package/build/prompt/InfoPrompt/InfoPrompt.mjs.map +1 -1
  55. package/build/prompt/PrimitivePrompt/PrimitivePrompt.js +11 -4
  56. package/build/prompt/PrimitivePrompt/PrimitivePrompt.js.map +1 -1
  57. package/build/prompt/PrimitivePrompt/PrimitivePrompt.mjs +11 -4
  58. package/build/prompt/PrimitivePrompt/PrimitivePrompt.mjs.map +1 -1
  59. package/build/prompt/common/Expander/Expander.js +35 -0
  60. package/build/prompt/common/Expander/Expander.js.map +1 -0
  61. package/build/prompt/common/Expander/Expander.messages.js +17 -0
  62. package/build/prompt/common/Expander/Expander.messages.js.map +1 -0
  63. package/build/prompt/common/Expander/Expander.messages.mjs +13 -0
  64. package/build/prompt/common/Expander/Expander.messages.mjs.map +1 -0
  65. package/build/prompt/common/Expander/Expander.mjs +33 -0
  66. package/build/prompt/common/Expander/Expander.mjs.map +1 -0
  67. package/build/prompt/helpers/promptMedia.js +52 -0
  68. package/build/prompt/helpers/promptMedia.js.map +1 -0
  69. package/build/prompt/helpers/promptMedia.mjs +50 -0
  70. package/build/prompt/helpers/promptMedia.mjs.map +1 -0
  71. package/build/styles/logo/Logo.css +3 -23
  72. package/build/styles/main.css +225 -58
  73. package/build/styles/prompt/CriticalBanner/CriticalBanner.css +134 -0
  74. package/build/styles/prompt/CriticalBanner/CriticalBanner.vars.css +0 -0
  75. package/build/styles/prompt/InfoPrompt/InfoPrompt.css +24 -0
  76. package/build/styles/prompt/common/Expander/Expander.css +8 -0
  77. package/build/typeahead/Typeahead.js +3 -2
  78. package/build/typeahead/Typeahead.js.map +1 -1
  79. package/build/typeahead/Typeahead.mjs +3 -2
  80. package/build/typeahead/Typeahead.mjs.map +1 -1
  81. package/build/types/common/hooks/useContainerSize.d.ts +14 -0
  82. package/build/types/common/hooks/useContainerSize.d.ts.map +1 -0
  83. package/build/types/common/hooks/useResizeObserver.d.ts +1 -1
  84. package/build/types/common/hooks/useResizeObserver.d.ts.map +1 -1
  85. package/build/types/criticalBanner/CriticalCommsBanner.d.ts +3 -0
  86. package/build/types/criticalBanner/CriticalCommsBanner.d.ts.map +1 -1
  87. package/build/types/index.d.ts +2 -2
  88. package/build/types/index.d.ts.map +1 -1
  89. package/build/types/logo/Logo.d.ts +33 -1
  90. package/build/types/logo/Logo.d.ts.map +1 -1
  91. package/build/types/logo/logo-assets.d.ts +33 -9
  92. package/build/types/logo/logo-assets.d.ts.map +1 -1
  93. package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts +2 -11
  94. package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts.map +1 -1
  95. package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts +39 -0
  96. package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts.map +1 -0
  97. package/build/types/prompt/CriticalBanner/helpers.d.ts +18 -0
  98. package/build/types/prompt/CriticalBanner/helpers.d.ts.map +1 -0
  99. package/build/types/prompt/CriticalBanner/index.d.ts +3 -0
  100. package/build/types/prompt/CriticalBanner/index.d.ts.map +1 -0
  101. package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts.map +1 -1
  102. package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts +35 -3
  103. package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts.map +1 -1
  104. package/build/types/prompt/common/Expander/Expander.d.ts +20 -0
  105. package/build/types/prompt/common/Expander/Expander.d.ts.map +1 -0
  106. package/build/types/prompt/common/Expander/Expander.messages.d.ts +14 -0
  107. package/build/types/prompt/common/Expander/Expander.messages.d.ts.map +1 -0
  108. package/build/types/prompt/helpers/promptMedia.d.ts +22 -0
  109. package/build/types/prompt/helpers/promptMedia.d.ts.map +1 -0
  110. package/build/types/prompt/index.d.ts +2 -0
  111. package/build/types/prompt/index.d.ts.map +1 -1
  112. package/build/types/test-utils/index.d.ts +4 -0
  113. package/build/types/test-utils/index.d.ts.map +1 -1
  114. package/package.json +6 -6
  115. package/src/common/hooks/useContainerSize.test.tsx +125 -0
  116. package/src/common/hooks/useContainerSize.ts +32 -0
  117. package/src/common/hooks/useResizeObserver.ts +3 -2
  118. package/src/criticalBanner/CriticalCommsBanner.story.tsx +4 -0
  119. package/src/criticalBanner/CriticalCommsBanner.test.story.tsx +1 -1
  120. package/src/criticalBanner/CriticalCommsBanner.tsx +3 -0
  121. package/src/i18n/en.json +2 -0
  122. package/src/index.ts +2 -2
  123. package/src/logo/Logo.css +3 -23
  124. package/src/logo/Logo.less +3 -29
  125. package/src/logo/Logo.story.tsx +117 -89
  126. package/src/logo/Logo.test.story.tsx +15 -24
  127. package/src/logo/Logo.tsx +90 -28
  128. package/src/logo/logo-assets.tsx +36 -92
  129. package/src/main.css +225 -58
  130. package/src/main.less +3 -1
  131. package/src/prompt/ActionPrompt/ActionPrompt.tsx +9 -62
  132. package/src/prompt/CriticalBanner/CriticalBanner.accessibility.docs.mdx +113 -0
  133. package/src/prompt/CriticalBanner/CriticalBanner.css +134 -0
  134. package/src/prompt/CriticalBanner/CriticalBanner.less +155 -0
  135. package/src/prompt/CriticalBanner/CriticalBanner.story.tsx +635 -0
  136. package/src/prompt/CriticalBanner/CriticalBanner.test.story.tsx +422 -0
  137. package/src/prompt/CriticalBanner/CriticalBanner.tsx +179 -0
  138. package/src/prompt/CriticalBanner/CriticalBanner.vars.css +0 -0
  139. package/src/prompt/CriticalBanner/CriticalBanner.vars.less +6 -0
  140. package/src/prompt/CriticalBanner/helpers.ts +39 -0
  141. package/src/prompt/CriticalBanner/index.ts +2 -0
  142. package/src/prompt/InfoPrompt/InfoPrompt.css +24 -0
  143. package/src/prompt/InfoPrompt/InfoPrompt.less +23 -0
  144. package/src/prompt/InfoPrompt/InfoPrompt.tsx +5 -1
  145. package/src/prompt/PrimitivePrompt/PrimitivePrompt.tsx +56 -40
  146. package/src/prompt/common/Expander/Expander.css +8 -0
  147. package/src/prompt/common/Expander/Expander.less +9 -0
  148. package/src/prompt/common/Expander/Expander.messages.ts +14 -0
  149. package/src/prompt/common/Expander/Expander.test.tsx +167 -0
  150. package/src/prompt/common/Expander/Expander.tsx +83 -0
  151. package/src/prompt/helpers/promptMedia.tsx +79 -0
  152. package/src/prompt/index.ts +4 -0
  153. package/src/sentimentSurface/SentimentSurface.story.tsx +43 -17
package/src/main.css CHANGED
@@ -31067,35 +31067,9 @@ button.np-link {
31067
31067
 
31068
31068
  .np-logo {
31069
31069
  display: inline-block;
31070
- }
31071
-
31072
- .np-theme-personal--forest-green .np-logo-svg path,
31073
- .np-theme-personal--bright-green .np-logo-svg path {
31074
- fill: var(--color-interactive-primary);
31075
- }
31076
-
31077
- .np-theme-personal--dark .np-logo-svg path {
31078
- fill: var(--color-white);
31079
- }
31080
-
31081
- .np-logo-svg--size-sm {
31082
- display: block;
31083
- }
31084
-
31085
- @media (min-width: 576px) {
31086
- .np-logo-svg--size-sm {
31087
- display: none;
31088
- }
31089
- }
31090
-
31091
- .np-logo-svg--size-md {
31092
- display: none;
31093
- }
31094
-
31095
- @media (min-width: 576px) {
31096
- .np-logo-svg--size-md {
31097
- display: block;
31098
- }
31070
+ color: var(--color-interactive-primary);
31071
+ width: var(--wds-logo-width);
31072
+ height: var(--wds-logo-height);
31099
31073
  }
31100
31074
 
31101
31075
  .tw-modal--scrollable {
@@ -32233,6 +32207,228 @@ html:not([dir="rtl"]) .np-navigation-option {
32233
32207
  padding: 0;
32234
32208
  }
32235
32209
 
32210
+ @media (max-width: 320px) {
32211
+ .wds-info-prompt .wds-prompt__media-wrapper {
32212
+ padding-top: 4px;
32213
+ padding-top: var(--size-4);
32214
+ }
32215
+ }
32216
+
32217
+ @media (max-width: 320px) {
32218
+ .wds-info-prompt .wds-prompt__media-wrapper:has(.wds-info-prompt__media > .tw-icon) {
32219
+ padding-top: 8px;
32220
+ padding-top: var(--size-8);
32221
+ }
32222
+ }
32223
+
32224
+ @media (max-width: 320px) {
32225
+ .wds-info-prompt .wds-prompt__media-wrapper:has(+ .wds-info-prompt__content .wds-info-prompt__title:first-child) {
32226
+ padding-top: 8px;
32227
+ padding-top: var(--size-8);
32228
+ }
32229
+ }
32230
+
32231
+ @media (max-width: 320px) {
32232
+ .wds-info-prompt .wds-prompt__media-wrapper:has(+ .wds-info-prompt__content .wds-info-prompt__title:first-child):has(.wds-info-prompt__media > .tw-icon) {
32233
+ padding-top: 12px;
32234
+ padding-top: var(--size-12);
32235
+ }
32236
+ }
32237
+
32238
+ .wds-action-prompt {
32239
+ --Prompt-padding: var(--size-16);
32240
+ --Prompt-actions-gap: var(--size-8);
32241
+ --Prompt-gap: var(--size-10) var(--size-16);
32242
+ --Prompt-border-radius: var(--radius-large);
32243
+ }
32244
+
32245
+ .wds-action-prompt--media-image {
32246
+ width: 48px;
32247
+ width: var(--size-48);
32248
+ height: 48px;
32249
+ height: var(--size-48);
32250
+ -o-object-fit: contain;
32251
+ object-fit: contain;
32252
+ }
32253
+
32254
+ @media (max-width: 767px) {
32255
+ .wds-action-prompt--with-two-actions .wds-prompt__actions-wrapper .wds-Button {
32256
+ flex: 1 1 calc(50% - (var(--Prompt-actions-gap) / 2));
32257
+ min-width: -moz-fit-content;
32258
+ min-width: fit-content;
32259
+ }
32260
+ }
32261
+
32262
+ .wds-action-prompt__content {
32263
+ max-width: calc(48px * 10);
32264
+ max-width: calc(var(--size-48) * 10);
32265
+ }
32266
+
32267
+ .wds-critical-banner {
32268
+ --Prompt-padding: var(--size-16);
32269
+ --Prompt-actions-gap: var(--size-8);
32270
+ --Prompt-gap: var(--size-10) var(--size-16);
32271
+ --Prompt-border-radius: 0;
32272
+ container-type: inline-size;
32273
+ --critical-banner-easing: cubic-bezier(0.9, 0, 0.7, 1);
32274
+ --critical-banner-duration: 150ms;
32275
+ /* Override PrimitivePrompt's --screen-sm-max actions behaviour:
32276
+ actions only go full-width below mobile-max token (container query) */
32277
+ }
32278
+
32279
+ .wds-critical-banner--media-image {
32280
+ width: 48px;
32281
+ width: var(--size-48);
32282
+ height: 48px;
32283
+ height: var(--size-48);
32284
+ -o-object-fit: contain;
32285
+ object-fit: contain;
32286
+ }
32287
+
32288
+ .wds-critical-banner__title {
32289
+ display: -webkit-box;
32290
+ -webkit-line-clamp: 8;
32291
+ line-clamp: 8;
32292
+ -webkit-box-orient: vertical;
32293
+ max-height: 192px;
32294
+ overflow: hidden;
32295
+ transition: max-height var(--critical-banner-duration) var(--critical-banner-easing);
32296
+ }
32297
+
32298
+ .wds-critical-banner--collapsed .wds-critical-banner__title {
32299
+ -webkit-line-clamp: 2;
32300
+ line-clamp: 2;
32301
+ max-height: 48px;
32302
+ }
32303
+
32304
+ .wds-critical-banner__description {
32305
+ max-height: 30vh;
32306
+ opacity: 1;
32307
+ overflow: hidden;
32308
+ transition: max-height var(--critical-banner-duration) var(--critical-banner-easing), opacity var(--critical-banner-duration) var(--critical-banner-easing);
32309
+ }
32310
+
32311
+ .wds-critical-banner--collapsed .wds-critical-banner__description--with-title {
32312
+ max-height: 0;
32313
+ opacity: 0;
32314
+ }
32315
+
32316
+ .wds-critical-banner--collapsed .wds-critical-banner__description:not(.wds-critical-banner__description--with-title) {
32317
+ display: -webkit-box;
32318
+ -webkit-line-clamp: 2;
32319
+ line-clamp: 2;
32320
+ -webkit-box-orient: vertical;
32321
+ overflow: hidden;
32322
+ }
32323
+
32324
+ .wds-critical-banner .wds-prompt__content-wrapper {
32325
+ grid-template-columns: auto 1fr auto;
32326
+ align-items: flex-start;
32327
+ transition: row-gap var(--critical-banner-duration) var(--critical-banner-easing);
32328
+ }
32329
+
32330
+ .wds-critical-banner--collapsed .wds-prompt__content-wrapper {
32331
+ row-gap: 0;
32332
+ }
32333
+
32334
+ .wds-critical-banner__text-wrapper {
32335
+ position: relative;
32336
+ display: flex;
32337
+ flex-direction: column;
32338
+ justify-content: center;
32339
+ align-items: flex-start;
32340
+ text-align: start;
32341
+ min-width: 0;
32342
+ max-width: 480px;
32343
+ height: 100%;
32344
+ padding-top: 3px;
32345
+ }
32346
+
32347
+ @media (max-width: 320px) {
32348
+ .wds-critical-banner__text-wrapper {
32349
+ padding-top: 0;
32350
+ }
32351
+ }
32352
+
32353
+ @container (max-width: 320px) {
32354
+ .wds-critical-banner__text-wrapper {
32355
+ padding-top: 0;
32356
+ }
32357
+ }
32358
+
32359
+ .wds-critical-banner--collapsed .wds-critical-banner__title,
32360
+ .wds-critical-banner--collapsed .wds-critical-banner__description {
32361
+ transform: translateY(0);
32362
+ }
32363
+
32364
+ .wds-critical-banner__toggle {
32365
+ flex-shrink: 0;
32366
+ transition: transform var(--critical-banner-duration) var(--critical-banner-easing);
32367
+ }
32368
+
32369
+ .wds-critical-banner__toggle--collapsed {
32370
+ transform: rotate(180deg);
32371
+ }
32372
+
32373
+ @container (min-width: 768px) {
32374
+ .wds-critical-banner__toggle {
32375
+ display: none;
32376
+ }
32377
+ }
32378
+
32379
+ .wds-critical-banner .wds-prompt__actions-wrapper {
32380
+ grid-column-start: 2;
32381
+ grid-column-end: 3;
32382
+ max-height: 200px;
32383
+ opacity: 1;
32384
+ overflow: visible;
32385
+ }
32386
+
32387
+ @container (max-width: 600px) {
32388
+ .wds-critical-banner .wds-prompt__actions-wrapper {
32389
+ grid-column: span 3;
32390
+ width: 100%;
32391
+ }
32392
+ .wds-critical-banner .wds-prompt__actions-wrapper .wds-Button {
32393
+ flex: 1 1 100%;
32394
+ width: 100%;
32395
+ }
32396
+ }
32397
+
32398
+ .wds-critical-banner--collapsed .wds-prompt__actions-wrapper {
32399
+ max-height: 0;
32400
+ opacity: 0;
32401
+ overflow: hidden;
32402
+ pointer-events: none;
32403
+ }
32404
+
32405
+ @container (max-width: 600px) {
32406
+ .wds-critical-banner--with-two-actions .wds-prompt__actions-wrapper .wds-Button {
32407
+ flex: 1 1 calc(50% - (var(--Prompt-actions-gap) / 2));
32408
+ min-width: -moz-fit-content;
32409
+ min-width: fit-content;
32410
+ }
32411
+ }
32412
+
32413
+ @media (prefers-reduced-motion: reduce) {
32414
+ .wds-critical-banner__description,
32415
+ .wds-critical-banner__title,
32416
+ .wds-critical-banner .wds-prompt__content-wrapper,
32417
+ .wds-critical-banner__toggle {
32418
+ transition: none !important;
32419
+ }
32420
+ }
32421
+
32422
+ .wds-expander-toggle {
32423
+ align-self: flex-start;
32424
+ flex-shrink: 0;
32425
+ transition: transform 0.2s ease-in-out;
32426
+ }
32427
+
32428
+ .wds-expander-toggle--collapsed {
32429
+ transform: rotate(180deg);
32430
+ }
32431
+
32236
32432
  .wds-radio-group .np-radio:last-child label {
32237
32433
  margin-bottom: 0;
32238
32434
  }
@@ -34658,32 +34854,3 @@ html:not([dir="rtl"]) .np-navigation-option {
34658
34854
  .np-list-item__action {
34659
34855
  flex-shrink: 0;
34660
34856
  }
34661
-
34662
- .wds-action-prompt {
34663
- --Prompt-padding: var(--size-16);
34664
- --Prompt-actions-gap: var(--size-8);
34665
- --Prompt-gap: var(--size-10) var(--size-16);
34666
- --Prompt-border-radius: var(--radius-large);
34667
- }
34668
-
34669
- .wds-action-prompt--media-image {
34670
- width: 48px;
34671
- width: var(--size-48);
34672
- height: 48px;
34673
- height: var(--size-48);
34674
- -o-object-fit: contain;
34675
- object-fit: contain;
34676
- }
34677
-
34678
- @media (max-width: 767px) {
34679
- .wds-action-prompt--with-two-actions .wds-prompt__actions-wrapper .wds-Button {
34680
- flex: 1 1 calc(50% - (var(--Prompt-actions-gap) / 2));
34681
- min-width: -moz-fit-content;
34682
- min-width: fit-content;
34683
- }
34684
- }
34685
-
34686
- .wds-action-prompt__content {
34687
- max-width: calc(48px * 10);
34688
- max-width: calc(var(--size-48) * 10);
34689
- }
package/src/main.less CHANGED
@@ -67,6 +67,9 @@
67
67
  @import "./prompt/PrimitivePrompt/PrimitivePrompt.less";
68
68
  @import "./prompt/InlinePrompt/InlinePrompt.less";
69
69
  @import "./prompt/InfoPrompt/InfoPrompt.less";
70
+ @import "./prompt/ActionPrompt/ActionPrompt.less";
71
+ @import "./prompt/CriticalBanner/CriticalBanner.less";
72
+ @import "./prompt/common/Expander/Expander.less";
70
73
  @import "./radioGroup/RadioGroup.less";
71
74
  @import "./section/Section.less";
72
75
  @import "./slidingPanel/SlidingPanel.less";
@@ -91,7 +94,6 @@
91
94
  @import "./progress/Progress.less";
92
95
  @import "./progressBar/ProgressBar.less";
93
96
  @import "./legacylistItem/LegacyListItem.less";
94
- @import "./prompt/ActionPrompt/ActionPrompt.less";
95
97
 
96
98
  // List all less files in src in alphabetical order: find -s src -type f -name '*.less' ! -name 'main.less'
97
99
  // Make sure you are not referencing main.less itself in this file!
@@ -1,31 +1,19 @@
1
1
  import { AriaAttributes, ReactNode, useId } from 'react';
2
2
  import { clsx } from 'clsx';
3
3
 
4
- import StatusIcon from '../../statusIcon';
5
4
  import Body from '../../body';
6
5
  import Button from '../../button';
7
6
  import { Breakpoint, Typography } from '../../common';
8
- import AvatarView, { AvatarViewProps } from '../../avatarView';
9
- import Image from '../../image';
10
7
  import { ButtonProps } from '../../button/Button.types';
11
8
  import { PrimitivePrompt, PrimitivePromptProps } from '../PrimitivePrompt';
12
- import { BadgeAssetsProps } from '../../badge';
13
- import { GiftBox } from '@transferwise/icons';
14
9
  import { useScreenSize } from '../../common/hooks/useScreenSize';
10
+ import { renderPromptMedia, PromptMedia } from '../helpers/promptMedia';
15
11
 
16
12
  export type ActionPromptProps = {
17
13
  title: ReactNode;
18
14
  description?: ReactNode;
19
15
  /** @default {} */
20
- media?: {
21
- imgSrc?: string;
22
- avatar?: Pick<AvatarViewProps, 'imgSrc' | 'profileName' | 'profileType'> & {
23
- asset?: AvatarViewProps['children'];
24
- badge?: Pick<BadgeAssetsProps, 'flagCode'>;
25
- };
26
- 'aria-label'?: string;
27
- 'aria-hidden'?: boolean;
28
- };
16
+ media?: PromptMedia;
29
17
  action: Pick<ButtonProps, 'onClick' | 'href' | 'target'> & {
30
18
  label: ButtonProps['children'];
31
19
  };
@@ -74,54 +62,13 @@ export const ActionPrompt = ({
74
62
  .filter(Boolean)
75
63
  .join(' ');
76
64
 
77
- const renderMedia = () => {
78
- if (media?.imgSrc) {
79
- return (
80
- <Image
81
- id={mediaId}
82
- src={media.imgSrc}
83
- className="wds-action-prompt--media-image"
84
- alt={media['aria-label'] ?? ''}
85
- />
86
- );
87
- }
88
- if (media?.avatar) {
89
- const badge = media.avatar.badge
90
- ? media.avatar.badge
91
- : sentiment === 'proposition'
92
- ? {}
93
- : { status: sentiment };
94
- return (
95
- <AvatarView
96
- {...media.avatar}
97
- badge={badge}
98
- aria-label={media['aria-label']}
99
- aria-hidden={media['aria-hidden']}
100
- id={mediaId}
101
- size={48}
102
- >
103
- {media.avatar.asset}
104
- </AvatarView>
105
- );
106
- }
107
- return sentiment === 'proposition' ? (
108
- <AvatarView
109
- id={mediaId}
110
- size={48}
111
- aria-label={media['aria-label']}
112
- aria-hidden={media['aria-hidden']}
113
- >
114
- <GiftBox />
115
- </AvatarView>
116
- ) : (
117
- <StatusIcon
118
- id={mediaId}
119
- size={48}
120
- sentiment={sentiment}
121
- iconLabel={media['aria-hidden'] ? null : media['aria-label']}
122
- />
123
- );
124
- };
65
+ const renderMedia = () =>
66
+ renderPromptMedia({
67
+ media,
68
+ sentiment,
69
+ mediaId,
70
+ imgClassName: 'wds-action-prompt--media-image',
71
+ });
125
72
 
126
73
  return (
127
74
  <PrimitivePrompt
@@ -0,0 +1,113 @@
1
+ import { Meta, Source, Canvas } from '@storybook/addon-docs/blocks';
2
+ import * as CriticalBannerStories from './CriticalBanner.story';
3
+
4
+ <Meta title="Prompts/CriticalBanner/Accessibility" tags={['new']} />
5
+
6
+ # Accessibility
7
+
8
+ Under the hood, `CriticalBanner` is marked as `role="region"` for a section of content that users might want to navigate to directly.
9
+
10
+ By default, it's labelled by the `title` and described by the `description`.
11
+
12
+ ## Announcement Behavior
13
+
14
+ `CriticalBanner` is designed for critical messages that require immediate attention. It always uses **`aria-live="assertive"`** to immediately interrupt and announce changes to screen readers.
15
+
16
+ Unlike `InfoPrompt` which offers configurable politeness levels, `CriticalBanner` is always assertive because it communicates critical, time-sensitive information that users must be aware of immediately.
17
+
18
+ ### What Gets Announced
19
+
20
+ The component intelligently announces only **visible content**, respecting the collapsed/expanded state:
21
+
22
+ - **Collapsed with title**: Announces title only (description is hidden)
23
+ - **Collapsed without title**: Announces description only (visible up to 2 lines)
24
+ - **Expanded**: Announces title, description, and action button labels (all visible)
25
+
26
+ <Source
27
+ dark
28
+ code={`
29
+ // Collapsed with title - announces: "Your account requires verification"
30
+ <CriticalBanner
31
+ title="Your account requires verification"
32
+ description="Please verify your identity to continue"
33
+ action={{ label: "Verify now", onClick: handleVerify }}
34
+ expanded={false}
35
+ onToggle={handleToggle}
36
+ />
37
+
38
+ // Expanded - announces: "Your account requires verification | Please verify your identity to continue | Verify now | Learn more"
39
+
40
+ <CriticalBanner
41
+ title="Your account requires verification"
42
+ description="Please verify your identity to continue"
43
+ action={{ label: 'Verify now', onClick: handleVerify }}
44
+ actionSecondary={{ label: 'Learn more', onClick: handleLearnMore }}
45
+ expanded={true}
46
+ onToggle={handleToggle}
47
+ />
48
+
49
+ // Collapsed without title - announces: "Your verification is pending..."
50
+
51
+ <CriticalBanner
52
+ description="Your verification is pending. We'll notify you once complete."
53
+ expanded={false}
54
+ onToggle={handleToggle}
55
+ />
56
+ `}
57
+ />
58
+
59
+ ### When Announcements Trigger
60
+
61
+ Screen readers announce the banner content whenever:
62
+
63
+ - The banner first appears in the DOM
64
+ - The user toggles between collapsed and expanded states
65
+ - The content (title, description, or action labels) changes
66
+
67
+ ## Media
68
+
69
+ Custom media icons should include their own accessibility attributes. Use the `title` prop on icons to provide accessible names for screen readers:
70
+
71
+ <Source
72
+ dark
73
+ code={`
74
+ import { Bank, AlertCircle } from '@transferwise/icons';
75
+
76
+ <CriticalBanner
77
+ title="Bank connection required"
78
+ description="Connect your bank account to continue"
79
+ media={{ avatar: { asset: <Bank title="Bank account" /> } }}
80
+ action={{ label: 'Connect now', onClick: handleConnect }}
81
+ expanded={false}
82
+ onToggle={handleToggle}
83
+ />
84
+
85
+ <CriticalBanner
86
+ title="Verification required"
87
+ description="We need to verify your identity"
88
+ media={{ avatar: { asset: <AlertCircle title="Alert" /> } }}
89
+ action={{ label: "Start verification", onClick: handleVerify }}
90
+ expanded={false}
91
+ onToggle={handleToggle}
92
+ />
93
+ `}
94
+ />
95
+
96
+ Alternatively, you can use `media['aria-label']` to provide a label for custom images:
97
+
98
+ <Source
99
+ dark
100
+ code={`
101
+ <CriticalBanner
102
+ title="Card blocked"
103
+ description="Your card has been blocked for security reasons"
104
+ media={{
105
+ imgSrc: '/wise-card.svg',
106
+ 'aria-label': 'Wise debit card'
107
+ }}
108
+ action={{ label: "Unblock card", onClick: handleUnblock }}
109
+ expanded={false}
110
+ onToggle={handleToggle}
111
+ />
112
+ `}
113
+ />
@@ -0,0 +1,134 @@
1
+ .wds-critical-banner {
2
+ --Prompt-padding: var(--size-16);
3
+ --Prompt-actions-gap: var(--size-8);
4
+ --Prompt-gap: var(--size-10) var(--size-16);
5
+ --Prompt-border-radius: 0;
6
+ container-type: inline-size;
7
+ --critical-banner-easing: cubic-bezier(0.9, 0, 0.7, 1);
8
+ --critical-banner-duration: 150ms;
9
+ /* Override PrimitivePrompt's --screen-sm-max actions behaviour:
10
+ actions only go full-width below mobile-max token (container query) */
11
+ }
12
+ .wds-critical-banner--media-image {
13
+ width: 48px;
14
+ width: var(--size-48);
15
+ height: 48px;
16
+ height: var(--size-48);
17
+ -o-object-fit: contain;
18
+ object-fit: contain;
19
+ }
20
+ .wds-critical-banner__title {
21
+ display: -webkit-box;
22
+ -webkit-line-clamp: 8;
23
+ line-clamp: 8;
24
+ -webkit-box-orient: vertical;
25
+ max-height: 192px;
26
+ overflow: hidden;
27
+ transition: max-height var(--critical-banner-duration) var(--critical-banner-easing);
28
+ }
29
+ .wds-critical-banner--collapsed .wds-critical-banner__title {
30
+ -webkit-line-clamp: 2;
31
+ line-clamp: 2;
32
+ max-height: 48px;
33
+ }
34
+ .wds-critical-banner__description {
35
+ max-height: 30vh;
36
+ opacity: 1;
37
+ overflow: hidden;
38
+ transition: max-height var(--critical-banner-duration) var(--critical-banner-easing), opacity var(--critical-banner-duration) var(--critical-banner-easing);
39
+ }
40
+ .wds-critical-banner--collapsed .wds-critical-banner__description--with-title {
41
+ max-height: 0;
42
+ opacity: 0;
43
+ }
44
+ .wds-critical-banner--collapsed .wds-critical-banner__description:not(.wds-critical-banner__description--with-title) {
45
+ display: -webkit-box;
46
+ -webkit-line-clamp: 2;
47
+ line-clamp: 2;
48
+ -webkit-box-orient: vertical;
49
+ overflow: hidden;
50
+ }
51
+ .wds-critical-banner .wds-prompt__content-wrapper {
52
+ grid-template-columns: auto 1fr auto;
53
+ align-items: flex-start;
54
+ transition: row-gap var(--critical-banner-duration) var(--critical-banner-easing);
55
+ }
56
+ .wds-critical-banner--collapsed .wds-prompt__content-wrapper {
57
+ row-gap: 0;
58
+ }
59
+ .wds-critical-banner__text-wrapper {
60
+ position: relative;
61
+ display: flex;
62
+ flex-direction: column;
63
+ justify-content: center;
64
+ align-items: flex-start;
65
+ text-align: start;
66
+ min-width: 0;
67
+ max-width: 480px;
68
+ height: 100%;
69
+ padding-top: 3px;
70
+ }
71
+ @media (max-width: 320px) {
72
+ .wds-critical-banner__text-wrapper {
73
+ padding-top: 0;
74
+ }
75
+ }
76
+ @container (max-width: 320px) {
77
+ .wds-critical-banner__text-wrapper {
78
+ padding-top: 0;
79
+ }
80
+ }
81
+ .wds-critical-banner--collapsed .wds-critical-banner__title,
82
+ .wds-critical-banner--collapsed .wds-critical-banner__description {
83
+ transform: translateY(0);
84
+ }
85
+ .wds-critical-banner__toggle {
86
+ flex-shrink: 0;
87
+ transition: transform var(--critical-banner-duration) var(--critical-banner-easing);
88
+ }
89
+ .wds-critical-banner__toggle--collapsed {
90
+ transform: rotate(180deg);
91
+ }
92
+ @container (min-width: 768px) {
93
+ .wds-critical-banner__toggle {
94
+ display: none;
95
+ }
96
+ }
97
+ .wds-critical-banner .wds-prompt__actions-wrapper {
98
+ grid-column-start: 2;
99
+ grid-column-end: 3;
100
+ max-height: 200px;
101
+ opacity: 1;
102
+ overflow: visible;
103
+ }
104
+ @container (max-width: 600px) {
105
+ .wds-critical-banner .wds-prompt__actions-wrapper {
106
+ grid-column: span 3;
107
+ width: 100%;
108
+ }
109
+ .wds-critical-banner .wds-prompt__actions-wrapper .wds-Button {
110
+ flex: 1 1 100%;
111
+ width: 100%;
112
+ }
113
+ }
114
+ .wds-critical-banner--collapsed .wds-prompt__actions-wrapper {
115
+ max-height: 0;
116
+ opacity: 0;
117
+ overflow: hidden;
118
+ pointer-events: none;
119
+ }
120
+ @container (max-width: 600px) {
121
+ .wds-critical-banner--with-two-actions .wds-prompt__actions-wrapper .wds-Button {
122
+ flex: 1 1 calc(50% - (var(--Prompt-actions-gap) / 2));
123
+ min-width: -moz-fit-content;
124
+ min-width: fit-content;
125
+ }
126
+ }
127
+ @media (prefers-reduced-motion: reduce) {
128
+ .wds-critical-banner__description,
129
+ .wds-critical-banner__title,
130
+ .wds-critical-banner .wds-prompt__content-wrapper,
131
+ .wds-critical-banner__toggle {
132
+ transition: none !important;
133
+ }
134
+ }