@transferwise/components 46.148.1 → 46.149.1

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 (84) hide show
  1. package/build/flowNavigation/FlowNavigation.js +56 -42
  2. package/build/flowNavigation/FlowNavigation.js.map +1 -1
  3. package/build/flowNavigation/FlowNavigation.mjs +56 -42
  4. package/build/flowNavigation/FlowNavigation.mjs.map +1 -1
  5. package/build/main.css +52 -28
  6. package/build/overlayHeader/OverlayHeader.js +3 -0
  7. package/build/overlayHeader/OverlayHeader.js.map +1 -1
  8. package/build/overlayHeader/OverlayHeader.mjs +3 -0
  9. package/build/overlayHeader/OverlayHeader.mjs.map +1 -1
  10. package/build/prompt/CriticalBanner/CriticalBanner.js +1 -1
  11. package/build/prompt/CriticalBanner/CriticalBanner.js.map +1 -1
  12. package/build/prompt/CriticalBanner/CriticalBanner.mjs +1 -1
  13. package/build/prompt/CriticalBanner/CriticalBanner.mjs.map +1 -1
  14. package/build/styles/avatarView/AvatarView.css +1 -0
  15. package/build/styles/css/neptune.css +11 -11
  16. package/build/styles/flowNavigation/FlowNavigation.css +16 -2
  17. package/build/styles/less/legacy-variables.less +1 -1
  18. package/build/styles/less/neptune-tokens.less +2 -2
  19. package/build/styles/main.css +52 -28
  20. package/build/styles/prompt/CriticalBanner/CriticalBanner.css +19 -12
  21. package/build/styles/props/custom-media.css +1 -1
  22. package/build/styles/props/neptune-tokens.css +1 -1
  23. package/build/styles/sentimentSurface/SentimentSurface.css +1 -1
  24. package/build/styles/styles/less/neptune.css +11 -11
  25. package/build/types/flowNavigation/FlowNavigation.d.ts +15 -3
  26. package/build/types/flowNavigation/FlowNavigation.d.ts.map +1 -1
  27. package/build/types/overlayHeader/OverlayHeader.d.ts +6 -0
  28. package/build/types/overlayHeader/OverlayHeader.d.ts.map +1 -1
  29. package/package.json +15 -15
  30. package/src/avatarView/AvatarView.css +1 -0
  31. package/src/avatarView/AvatarView.less +3 -1
  32. package/src/body/Body.story.tsx +1 -5
  33. package/src/calendar/Calendar.story.tsx +1 -4
  34. package/src/checkbox/Checkbox.story.tsx +1 -4
  35. package/src/chevron/Chevron.story.tsx +1 -1
  36. package/src/container/Container.story.tsx +1 -4
  37. package/src/dateInput/DateInput.story.tsx +1 -4
  38. package/src/dateLookup/DateLookup.story.tsx +1 -4
  39. package/src/decision/Decision.story.tsx +1 -4
  40. package/src/definitionList/DefinitionList.story.tsx +1 -4
  41. package/src/dimmer/Dimmer.story.tsx +1 -5
  42. package/src/display/Display.story.tsx +1 -4
  43. package/src/emphasis/Emphasis.story.tsx +1 -5
  44. package/src/expressiveMoneyInput/ExpressiveMoneyInput.story.tsx +1 -4
  45. package/src/field/Field.story.tsx +1 -4
  46. package/src/flowNavigation/FlowNavigation.css +16 -2
  47. package/src/flowNavigation/FlowNavigation.less +20 -4
  48. package/src/flowNavigation/FlowNavigation.story.tsx +249 -0
  49. package/src/flowNavigation/FlowNavigation.tsx +91 -58
  50. package/src/header/Header.story.tsx +1 -4
  51. package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.tsx +1 -4
  52. package/src/inputs/InputGroup.story.tsx +1 -4
  53. package/src/inputs/SearchInput.story.tsx +1 -4
  54. package/src/inputs/TextArea.story.tsx +1 -4
  55. package/src/instructionsList/InstructionsList.story.tsx +1 -4
  56. package/src/label/Label.story.tsx +1 -4
  57. package/src/link/Link.story.tsx +1 -4
  58. package/src/loader/Loader.story.tsx +1 -1
  59. package/src/main.css +52 -28
  60. package/src/markdown/Markdown.story.tsx +1 -5
  61. package/src/money/Money.story.tsx +0 -1
  62. package/src/moneyInput/MoneyInput.story.tsx +1 -4
  63. package/src/overlayHeader/OverlayHeader.story.tsx +4 -0
  64. package/src/overlayHeader/OverlayHeader.tsx +6 -0
  65. package/src/phoneNumberInput/PhoneNumberInput.story.tsx +1 -4
  66. package/src/promoCard/PromoCard.story.tsx +1 -4
  67. package/src/promoCard/PromoCardGroup.story.tsx +1 -4
  68. package/src/prompt/CriticalBanner/CriticalBanner.css +19 -12
  69. package/src/prompt/CriticalBanner/CriticalBanner.less +33 -25
  70. package/src/prompt/CriticalBanner/CriticalBanner.story.tsx +22 -11
  71. package/src/prompt/CriticalBanner/CriticalBanner.test.story.tsx +71 -0
  72. package/src/prompt/CriticalBanner/CriticalBanner.tsx +1 -1
  73. package/src/radio/Radio.story.tsx +1 -4
  74. package/src/radioGroup/RadioGroup.story.tsx +1 -4
  75. package/src/segmentedControl/SegmentedControl.story.tsx +1 -4
  76. package/src/sentimentSurface/SentimentSurface.css +1 -1
  77. package/src/statusIcon/StatusIcon.story.tsx +1 -1
  78. package/src/styles/less/neptune.css +11 -11
  79. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.story.tsx +1 -4
  80. package/src/title/Title.story.tsx +1 -5
  81. package/src/typeahead/Typeahead.story.tsx +1 -4
  82. package/src/upload/Upload.story.tsx +1 -4
  83. package/src/uploadInput/UploadInput.story.tsx +1 -4
  84. package/src/flowNavigation/FlowNavigation.test.js +0 -190
package/src/main.css CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Do not edit directly, this file was auto-generated.
3
- * Generated on Wed, 27 May 2026 15:50:09 GMT
3
+ * Generated on Tue, 09 Jun 2026 08:11:03 GMT
4
4
  */
5
5
 
6
6
  :root {
@@ -144,7 +144,7 @@
144
144
 
145
145
  /**
146
146
  * Do not edit directly, this file was auto-generated.
147
- * Generated on Wed, 27 May 2026 15:50:10 GMT
147
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
148
148
  */
149
149
 
150
150
  .np-theme-personal {
@@ -328,7 +328,7 @@
328
328
 
329
329
  /**
330
330
  * Do not edit directly, this file was auto-generated.
331
- * Generated on Wed, 27 May 2026 15:50:10 GMT
331
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
332
332
  */
333
333
 
334
334
  .np-theme-personal--forest-green {
@@ -512,7 +512,7 @@
512
512
 
513
513
  /**
514
514
  * Do not edit directly, this file was auto-generated.
515
- * Generated on Wed, 27 May 2026 15:50:10 GMT
515
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
516
516
  */
517
517
 
518
518
  .np-theme-personal--bright-green {
@@ -696,7 +696,7 @@
696
696
 
697
697
  /**
698
698
  * Do not edit directly, this file was auto-generated.
699
- * Generated on Wed, 27 May 2026 15:50:10 GMT
699
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
700
700
  */
701
701
 
702
702
  .np-theme-personal--dark {
@@ -880,7 +880,7 @@
880
880
 
881
881
  /**
882
882
  * Do not edit directly, this file was auto-generated.
883
- * Generated on Wed, 27 May 2026 15:50:10 GMT
883
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
884
884
  */
885
885
 
886
886
  .np-theme-platform {
@@ -1064,7 +1064,7 @@
1064
1064
 
1065
1065
  /**
1066
1066
  * Do not edit directly, this file was auto-generated.
1067
- * Generated on Wed, 27 May 2026 15:50:10 GMT
1067
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
1068
1068
  */
1069
1069
 
1070
1070
  .np-theme-platform--forest-green {
@@ -1248,7 +1248,7 @@
1248
1248
 
1249
1249
  /**
1250
1250
  * Do not edit directly, this file was auto-generated.
1251
- * Generated on Wed, 27 May 2026 15:50:10 GMT
1251
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
1252
1252
  */
1253
1253
 
1254
1254
  .np-theme-business {
@@ -1433,7 +1433,7 @@
1433
1433
 
1434
1434
  /**
1435
1435
  * Do not edit directly, this file was auto-generated.
1436
- * Generated on Wed, 27 May 2026 15:50:10 GMT
1436
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
1437
1437
  */
1438
1438
 
1439
1439
  .np-theme-business--dark {
@@ -1618,7 +1618,7 @@
1618
1618
 
1619
1619
  /**
1620
1620
  * Do not edit directly, this file was auto-generated.
1621
- * Generated on Wed, 27 May 2026 15:50:10 GMT
1621
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
1622
1622
  */
1623
1623
 
1624
1624
  .np-theme-business--forest-green {
@@ -1803,7 +1803,7 @@
1803
1803
 
1804
1804
  /**
1805
1805
  * Do not edit directly, this file was auto-generated.
1806
- * Generated on Wed, 27 May 2026 15:50:11 GMT
1806
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
1807
1807
  */
1808
1808
 
1809
1809
  .np-theme-business--bright-green {
@@ -1990,7 +1990,7 @@
1990
1990
 
1991
1991
  /**
1992
1992
  * Do not edit directly, this file was auto-generated.
1993
- * Generated on Wed, 27 May 2026 15:50:11 GMT
1993
+ * Generated on Tue, 09 Jun 2026 08:11:04 GMT
1994
1994
  */
1995
1995
 
1996
1996
  .wds-sentiment-negative-light-base {
@@ -26549,6 +26549,7 @@ a[data-toggle="tooltip"] {
26549
26549
  }
26550
26550
 
26551
26551
  .np-avatar-view .np-avatar-view-content {
26552
+ --circle-border-color: var(--color-sentiment-border-overlay, var(--color-border-neutral));
26552
26553
  color: #37517e;
26553
26554
  color: var(--color-sentiment-content-primary, var(--color-content-primary));
26554
26555
  }
@@ -28754,12 +28755,15 @@ button.np-option {
28754
28755
  }
28755
28756
 
28756
28757
  .np-flow-navigation {
28758
+ display: flex;
28759
+ align-items: center;
28760
+ justify-content: center;
28757
28761
  width: 100%;
28758
- min-height: 97px;
28762
+ box-sizing: border-box;
28763
+ min-height: 96px;
28759
28764
  }
28760
28765
 
28761
28766
  .np-flow-navigation--border-bottom {
28762
- min-height: 96px;
28763
28767
  border-bottom: 1px solid rgba(0,0,0,0.10196);
28764
28768
  border-bottom: 1px solid var(--color-border-neutral);
28765
28769
  }
@@ -28844,6 +28848,20 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
28844
28848
  visibility: hidden;
28845
28849
  }
28846
28850
 
28851
+ .np-flow-navigation--composable {
28852
+ min-height: 80px;
28853
+ }
28854
+
28855
+ @media (min-width: 320.02px) {
28856
+ .np-flow-navigation--composable {
28857
+ min-height: 128px;
28858
+ }
28859
+ }
28860
+
28861
+ .np-flow-navigation--composable .np-flow-navigation__content {
28862
+ max-width: none;
28863
+ }
28864
+
28847
28865
  .np-theme-personal--forest-green .np-flow-navigation .np-flow-header__left path,
28848
28866
  .np-theme-personal--bright-green .np-flow-navigation .np-flow-header__left path,
28849
28867
  .np-theme-personal--dark .np-flow-navigation .np-flow-header__left path {
@@ -31938,6 +31956,9 @@ html:not([dir="rtl"]) .np-navigation-option {
31938
31956
  --Prompt-actions-gap: var(--size-8);
31939
31957
  --Prompt-gap: var(--size-10) var(--size-16);
31940
31958
  --Prompt-border-radius: 0;
31959
+ --critical-banner-background-base: transparent;
31960
+ --critical-banner-background-surface: var(--color-sentiment-background-surface);
31961
+ --critical-banner-background: linear-gradient(var(--critical-banner-background-surface), var(--critical-banner-background-surface)), var(--critical-banner-background-base);
31941
31962
  container-type: inline-size;
31942
31963
  position: relative;
31943
31964
  --critical-banner-easing: cubic-bezier(0.9, 0, 0.7, 1);
@@ -31946,6 +31967,11 @@ html:not([dir="rtl"]) .np-navigation-option {
31946
31967
  actions only go full-width below mobile-max token (container query) */
31947
31968
  }
31948
31969
 
31970
+ .wds-critical-banner.wds-prompt--neutral {
31971
+ --critical-banner-background-base: var(--color-background-elevated);
31972
+ background: var(--critical-banner-background);
31973
+ }
31974
+
31949
31975
  .wds-critical-banner--media-image {
31950
31976
  width: 48px;
31951
31977
  width: var(--size-48);
@@ -32011,19 +32037,6 @@ html:not([dir="rtl"]) .np-navigation-option {
32011
32037
  min-width: 0;
32012
32038
  max-width: 480px;
32013
32039
  height: 100%;
32014
- padding-top: 3px;
32015
- }
32016
-
32017
- @media (max-width: 320px) {
32018
- .wds-critical-banner__text-wrapper {
32019
- padding-top: 0;
32020
- }
32021
- }
32022
-
32023
- @container (width < 320px) {
32024
- .wds-critical-banner__text-wrapper {
32025
- padding-top: 0;
32026
- }
32027
32040
  }
32028
32041
 
32029
32042
  .wds-critical-banner--collapsed .wds-critical-banner__title,
@@ -32096,6 +32109,15 @@ html:not([dir="rtl"]) .np-navigation-option {
32096
32109
  @container critical-banner-overhang (max-width: 600px) {
32097
32110
  .wds-critical-banner__entry-mask {
32098
32111
  --critical-banner-mobile-overhang-size: 32px;
32112
+ --critical-banner-overhang-mask: radial-gradient(circle at 100% 100%, transparent var(--critical-banner-mobile-overhang-size), #000 var(--critical-banner-mobile-overhang-size)) 0 0 / var(--critical-banner-mobile-overhang-size)
32113
+ var(--critical-banner-mobile-overhang-size) no-repeat,
32114
+ radial-gradient(
32115
+ circle at 0% 100%,
32116
+ transparent var(--critical-banner-mobile-overhang-size),
32117
+ #000 var(--critical-banner-mobile-overhang-size)
32118
+ )
32119
+ 100% 0 / var(--critical-banner-mobile-overhang-size)
32120
+ var(--critical-banner-mobile-overhang-size) no-repeat;
32099
32121
  }
32100
32122
  .wds-critical-banner__entry-mask .wds-critical-banner-overhang {
32101
32123
  margin-bottom: var(--critical-banner-mobile-overhang-size);
@@ -32108,7 +32130,9 @@ html:not([dir="rtl"]) .np-navigation-option {
32108
32130
  left: 0;
32109
32131
  height: var(--critical-banner-mobile-overhang-size);
32110
32132
  pointer-events: none;
32111
- background: radial-gradient(circle at 100% 100%, transparent var(--critical-banner-mobile-overhang-size), var(--color-sentiment-background-surface) var(--critical-banner-mobile-overhang-size)) 0 0 / var(--critical-banner-mobile-overhang-size) var(--critical-banner-mobile-overhang-size) no-repeat, radial-gradient(circle at 0% 100%, transparent var(--critical-banner-mobile-overhang-size), var(--color-sentiment-background-surface) var(--critical-banner-mobile-overhang-size)) 100% 0 / var(--critical-banner-mobile-overhang-size) var(--critical-banner-mobile-overhang-size) no-repeat;
32133
+ background: var(--critical-banner-background);
32134
+ -webkit-mask: var(--critical-banner-overhang-mask);
32135
+ mask: var(--critical-banner-overhang-mask);
32112
32136
  }
32113
32137
  }
32114
32138
 
@@ -1,10 +1,7 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
3
  import Markdown from './Markdown';
4
- import {
5
- createSandboxStory,
6
- globalScope,
7
- } from '../../.storybook/components/sandbox/SandboxEditor';
4
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
8
5
 
9
6
  export default {
10
7
  component: Markdown,
@@ -34,4 +31,3 @@ export const Basic: Story = {
34
31
  - sublist`,
35
32
  },
36
33
  };
37
-
@@ -21,4 +21,3 @@ export const Basic: Story = {
21
21
  currency: 'GBP',
22
22
  },
23
23
  };
24
-
@@ -3,10 +3,7 @@ import { within, userEvent, expect } from 'storybook/test';
3
3
  import { Padlock } from '@transferwise/icons';
4
4
  import { useState } from 'react';
5
5
 
6
- import {
7
- createSandboxStory,
8
- globalScope,
9
- } from '../../.storybook/components/sandbox/SandboxEditor';
6
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
10
7
  import MoneyInput, { CurrencyOptionItem } from '.';
11
8
  import { Field } from '../field/Field';
12
9
  import translations from '../i18n/en.json';
@@ -15,9 +15,13 @@ interface CustomControls {
15
15
  }
16
16
  export type StoryArgs = OverlayHeaderProps & CustomControls;
17
17
 
18
+ /**
19
+ * @deprecated Use `FlowNavigation` component instead
20
+ */
18
21
  const meta: Meta<StoryArgs> = {
19
22
  component: OverlayHeader,
20
23
  title: 'Navigation/OverlayHeader',
24
+ tags: ['deprecated'],
21
25
  argTypes: {
22
26
  avatarType: { control: 'select', options: ['', 'Business', 'Profile'] },
23
27
  avatarURL: { control: 'text' },
@@ -5,6 +5,9 @@ import { CloseButton } from '../common/closeButton';
5
5
  import FlowHeader from '../common/flowHeader';
6
6
  import Logo from '../logo';
7
7
 
8
+ /**
9
+ * @deprecated Use `FlowNavigation` component instead, with `steps={[]}`
10
+ */
8
11
  export interface OverlayHeaderProps {
9
12
  /** An Avatar */
10
13
  avatar?: React.ReactNode;
@@ -15,6 +18,9 @@ export interface OverlayHeaderProps {
15
18
 
16
19
  const defaultLogo = <Logo />;
17
20
 
21
+ /**
22
+ * @deprecated Use `FlowNavigation` component instead
23
+ */
18
24
  export default function OverlayHeader({ avatar, onClose, logo = defaultLogo }: OverlayHeaderProps) {
19
25
  const closeButton = onClose && <CloseButton size={Size.LARGE} onClick={onClose} />;
20
26
  return (
@@ -1,9 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
- import {
4
- createSandboxStory,
5
- globalScope,
6
- } from '../../.storybook/components/sandbox/SandboxEditor';
3
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
7
4
  import { Field } from '../field/Field';
8
5
  import PhoneNumberInput from './PhoneNumberInput';
9
6
 
@@ -2,10 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { StarFill } from '@transferwise/icons';
3
3
 
4
4
  import PromoCard, { type PromoCardCheckedProps, type PromoCardLinkProps } from './PromoCard';
5
- import {
6
- createSandboxStory,
7
- globalScope,
8
- } from '../../.storybook/components/sandbox/SandboxEditor';
5
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
9
6
 
10
7
  const meta: Meta<typeof PromoCard> = {
11
8
  component: PromoCard,
@@ -2,10 +2,7 @@ import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
3
  import PromoCard from './PromoCard';
4
4
  import PromoCardGroup from './PromoCardGroup';
5
- import {
6
- createSandboxStory,
7
- globalScope,
8
- } from '../../.storybook/components/sandbox/SandboxEditor';
5
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
9
6
 
10
7
  const PromoCards = () => {
11
8
  return (
@@ -4,6 +4,9 @@
4
4
  --Prompt-actions-gap: var(--size-8);
5
5
  --Prompt-gap: var(--size-10) var(--size-16);
6
6
  --Prompt-border-radius: 0;
7
+ --critical-banner-background-base: transparent;
8
+ --critical-banner-background-surface: var(--color-sentiment-background-surface);
9
+ --critical-banner-background: linear-gradient(var(--critical-banner-background-surface), var(--critical-banner-background-surface)), var(--critical-banner-background-base);
7
10
  container-type: inline-size;
8
11
  position: relative;
9
12
  --critical-banner-easing: cubic-bezier(0.9, 0, 0.7, 1);
@@ -11,6 +14,10 @@
11
14
  /* Override PrimitivePrompt's --screen-sm-max actions behaviour:
12
15
  actions only go full-width below mobile-max token (container query) */
13
16
  }
17
+ .wds-critical-banner.wds-prompt--neutral {
18
+ --critical-banner-background-base: var(--color-background-elevated);
19
+ background: var(--critical-banner-background);
20
+ }
14
21
  .wds-critical-banner--media-image {
15
22
  width: 48px;
16
23
  width: var(--size-48);
@@ -68,17 +75,6 @@
68
75
  min-width: 0;
69
76
  max-width: 480px;
70
77
  height: 100%;
71
- padding-top: 3px;
72
- }
73
- @media (max-width: 320px) {
74
- .wds-critical-banner__text-wrapper {
75
- padding-top: 0;
76
- }
77
- }
78
- @container (width < 320px) {
79
- .wds-critical-banner__text-wrapper {
80
- padding-top: 0;
81
- }
82
78
  }
83
79
  .wds-critical-banner--collapsed .wds-critical-banner__title,
84
80
  .wds-critical-banner--collapsed .wds-critical-banner__description {
@@ -140,6 +136,15 @@
140
136
  @container critical-banner-overhang (max-width: 600px) {
141
137
  .wds-critical-banner__entry-mask {
142
138
  --critical-banner-mobile-overhang-size: 32px;
139
+ --critical-banner-overhang-mask: radial-gradient(circle at 100% 100%, transparent var(--critical-banner-mobile-overhang-size), #000 var(--critical-banner-mobile-overhang-size)) 0 0 / var(--critical-banner-mobile-overhang-size)
140
+ var(--critical-banner-mobile-overhang-size) no-repeat,
141
+ radial-gradient(
142
+ circle at 0% 100%,
143
+ transparent var(--critical-banner-mobile-overhang-size),
144
+ #000 var(--critical-banner-mobile-overhang-size)
145
+ )
146
+ 100% 0 / var(--critical-banner-mobile-overhang-size)
147
+ var(--critical-banner-mobile-overhang-size) no-repeat;
143
148
  }
144
149
  .wds-critical-banner__entry-mask .wds-critical-banner-overhang {
145
150
  margin-bottom: var(--critical-banner-mobile-overhang-size);
@@ -152,7 +157,9 @@
152
157
  left: 0;
153
158
  height: var(--critical-banner-mobile-overhang-size);
154
159
  pointer-events: none;
155
- background: radial-gradient(circle at 100% 100%, transparent var(--critical-banner-mobile-overhang-size), var(--color-sentiment-background-surface) var(--critical-banner-mobile-overhang-size)) 0 0 / var(--critical-banner-mobile-overhang-size) var(--critical-banner-mobile-overhang-size) no-repeat, radial-gradient(circle at 0% 100%, transparent var(--critical-banner-mobile-overhang-size), var(--color-sentiment-background-surface) var(--critical-banner-mobile-overhang-size)) 100% 0 / var(--critical-banner-mobile-overhang-size) var(--critical-banner-mobile-overhang-size) no-repeat;
160
+ background: var(--critical-banner-background);
161
+ -webkit-mask: var(--critical-banner-overhang-mask);
162
+ mask: var(--critical-banner-overhang-mask);
156
163
  }
157
164
  }
158
165
  .wds-critical-banner__entry-track {
@@ -7,6 +7,16 @@
7
7
  --Prompt-actions-gap: var(--size-8);
8
8
  --Prompt-gap: var(--size-10) var(--size-16);
9
9
  --Prompt-border-radius: 0;
10
+ --critical-banner-background-base: transparent;
11
+ --critical-banner-background-surface: var(--color-sentiment-background-surface);
12
+ // The sentiment surface can be translucent, so layer it over an opaque base
13
+ // for neutral banners and their mobile overhang.
14
+ --critical-banner-background:
15
+ linear-gradient(
16
+ var(--critical-banner-background-surface),
17
+ var(--critical-banner-background-surface)
18
+ ),
19
+ var(--critical-banner-background-base);
10
20
  container-type: inline-size;
11
21
  position: relative;
12
22
 
@@ -14,6 +24,11 @@
14
24
  --critical-banner-easing: cubic-bezier(0.9, 0, 0.7, 1);
15
25
  --critical-banner-duration: 150ms;
16
26
 
27
+ &.wds-prompt--neutral {
28
+ --critical-banner-background-base: var(--color-background-elevated);
29
+ background: var(--critical-banner-background);
30
+ }
31
+
17
32
  &--media-image {
18
33
  width: var(--size-48);
19
34
  height: var(--size-48);
@@ -79,16 +94,6 @@
79
94
  min-width: 0;
80
95
  max-width: 480px;
81
96
  height: 100%;
82
-
83
- // Padding prevents text shifting when collapsing/expanding layout shift
84
- padding-top: 3px;
85
-
86
- @media (--screen-400-zoom) {
87
- padding-top: 0;
88
- }
89
- @container (width < @screen-xs-min) {
90
- padding-top: 0;
91
- }
92
97
  }
93
98
 
94
99
  &--collapsed &__title,
@@ -163,6 +168,21 @@
163
168
 
164
169
  @container critical-banner-overhang (max-width: @wds-critical-banner-mobile-overhang-max) {
165
170
  --critical-banner-mobile-overhang-size: 32px;
171
+ --critical-banner-overhang-mask:
172
+ radial-gradient(
173
+ circle at 100% 100%,
174
+ transparent var(--critical-banner-mobile-overhang-size),
175
+ #000 var(--critical-banner-mobile-overhang-size)
176
+ )
177
+ 0 0 / var(--critical-banner-mobile-overhang-size)
178
+ var(--critical-banner-mobile-overhang-size) no-repeat,
179
+ radial-gradient(
180
+ circle at 0% 100%,
181
+ transparent var(--critical-banner-mobile-overhang-size),
182
+ #000 var(--critical-banner-mobile-overhang-size)
183
+ )
184
+ 100% 0 / var(--critical-banner-mobile-overhang-size)
185
+ var(--critical-banner-mobile-overhang-size) no-repeat;
166
186
 
167
187
  .wds-critical-banner-overhang {
168
188
  margin-bottom: var(--critical-banner-mobile-overhang-size);
@@ -175,21 +195,9 @@
175
195
  left: 0;
176
196
  height: var(--critical-banner-mobile-overhang-size);
177
197
  pointer-events: none;
178
- background:
179
- radial-gradient(
180
- circle at 100% 100%,
181
- transparent var(--critical-banner-mobile-overhang-size),
182
- var(--color-sentiment-background-surface) var(--critical-banner-mobile-overhang-size)
183
- )
184
- 0 0 / var(--critical-banner-mobile-overhang-size)
185
- var(--critical-banner-mobile-overhang-size) no-repeat,
186
- radial-gradient(
187
- circle at 0% 100%,
188
- transparent var(--critical-banner-mobile-overhang-size),
189
- var(--color-sentiment-background-surface) var(--critical-banner-mobile-overhang-size)
190
- )
191
- 100% 0 / var(--critical-banner-mobile-overhang-size)
192
- var(--critical-banner-mobile-overhang-size) no-repeat;
198
+ background: var(--critical-banner-background);
199
+ -webkit-mask: var(--critical-banner-overhang-mask);
200
+ mask: var(--critical-banner-overhang-mask);
193
201
  }
194
202
  }
195
203
  }
@@ -19,7 +19,7 @@ const meta = {
19
19
  component: CriticalBanner,
20
20
  title: 'Prompts/CriticalBanner',
21
21
  tags: ['new'],
22
- parameters: { docs: { toc: true }, padding: '0', },
22
+ parameters: { docs: { toc: true }, padding: '0' },
23
23
  args: {
24
24
  title: 'Your account requires verification',
25
25
  description: 'Please verify your identity to continue using all features.',
@@ -351,12 +351,17 @@ export const Actions: Story = {
351
351
  * Each sentiment has a default status icon. Override it with a custom image or an AvatarView.
352
352
  */
353
353
  export const MediaTypes: Story = {
354
+ args: {
355
+ sentiment: 'neutral',
356
+ },
354
357
  decorators: [ContainerDecorator('2rem')],
355
358
  parameters: {
356
359
  docs: {
357
360
  source: {
358
- code: `{/* Default sentiment icon */}
359
- <CriticalBanner sentiment="neutral" />
361
+ code: `{/* Change sentiment using the story controls */}
362
+
363
+ {/* Default — sentiment icon */}
364
+ <CriticalBanner sentiment={sentiment} />
360
365
 
361
366
  {/* Custom image */}
362
367
  <CriticalBanner media={{ imgSrc: '/card.svg', 'aria-label': 'Wise card' }} ... />
@@ -375,8 +380,14 @@ export const MediaTypes: Story = {
375
380
  },
376
381
  },
377
382
  },
378
- argTypes: hiddenArgTypes,
379
- render: function Render() {
383
+ argTypes: {
384
+ ...hiddenArgTypes,
385
+ sentiment: {
386
+ control: 'radio',
387
+ options: ['negative', 'warning', 'neutral', 'success'],
388
+ },
389
+ },
390
+ render: function Render({ sentiment }) {
380
391
  const [expandedStates, setExpandedStates] = useState<Record<string, boolean>>({
381
392
  default: true,
382
393
  image: true,
@@ -392,7 +403,7 @@ export const MediaTypes: Story = {
392
403
  return (
393
404
  <>
394
405
  <CriticalBanner
395
- sentiment="neutral"
406
+ sentiment={sentiment}
396
407
  title="Default status icon"
397
408
  description="When no media is provided, the sentiment's default icon is displayed."
398
409
  action={{ label: 'Continue', onClick: fn() }}
@@ -400,7 +411,7 @@ export const MediaTypes: Story = {
400
411
  onToggle={() => toggle('default')}
401
412
  />
402
413
  <CriticalBanner
403
- sentiment="neutral"
414
+ sentiment={sentiment}
404
415
  title="Custom image"
405
416
  description="Your card has been blocked for security reasons."
406
417
  media={{ imgSrc: '../../wise-card.svg', 'aria-label': 'Wise debit card' }}
@@ -409,7 +420,7 @@ export const MediaTypes: Story = {
409
420
  onToggle={() => toggle('image')}
410
421
  />
411
422
  <CriticalBanner
412
- sentiment="neutral"
423
+ sentiment={sentiment}
413
424
  title="Avatar with photo"
414
425
  description="The default badge is the status icon for the sentiment."
415
426
  media={{ avatar: { imgSrc: '../../avatar-rectangle-fox.webp' } }}
@@ -418,7 +429,7 @@ export const MediaTypes: Story = {
418
429
  onToggle={() => toggle('avatarPhoto')}
419
430
  />
420
431
  <CriticalBanner
421
- sentiment="neutral"
432
+ sentiment={sentiment}
422
433
  title="Avatar with initials"
423
434
  description="The default badge is the status icon for the sentiment."
424
435
  media={{ avatar: { profileName: 'John Doe' } }}
@@ -427,7 +438,7 @@ export const MediaTypes: Story = {
427
438
  onToggle={() => toggle('avatarInitials')}
428
439
  />
429
440
  <CriticalBanner
430
- sentiment="neutral"
441
+ sentiment={sentiment}
431
442
  title="Avatar with custom icon"
432
443
  description="The default badge is the status icon for the sentiment."
433
444
  media={{ avatar: { asset: <Bank title="Bank account" /> } }}
@@ -436,7 +447,7 @@ export const MediaTypes: Story = {
436
447
  onToggle={() => toggle('avatarIcon')}
437
448
  />
438
449
  <CriticalBanner
439
- sentiment="neutral"
450
+ sentiment={sentiment}
440
451
  title="Business profile with badge"
441
452
  description="Your business account requires additional documentation."
442
453
  media={{ avatar: { profileType: 'BUSINESS', badge: { flagCode: 'GB' } } }}
@@ -21,10 +21,24 @@ const wait = async (ms: number) =>
21
21
  });
22
22
 
23
23
  const ANIMATION_DURATION = 200; // 150ms animation + 50ms buffer
24
+ const ENTRY_ANIMATION_DURATION = 950; // 500ms delay + 400ms animation + 50ms buffer
24
25
 
25
26
  const longDescription =
26
27
  'We have detected unusual activity on your account that does not match your typical usage patterns. To protect your funds and personal information, we have temporarily restricted access. Please verify your identity to restore full access to your account.';
27
28
 
29
+ const BACKGROUND_SCROLL_CONTENT = [
30
+ 'Manage your card settings, limits, and delivery details from this page.',
31
+ 'Your recent payments, subscriptions, and cash withdrawals will appear here.',
32
+ 'Freeze your card any time if it is lost, stolen, or somewhere unexpected.',
33
+ 'Set spending limits for online, in-store, and contactless payments.',
34
+ 'Add your card to a digital wallet for quicker checkout in supported stores.',
35
+ 'Choose the currency balance you want to spend from before you travel.',
36
+ 'Review fees before using an ATM or paying in a currency you do not hold.',
37
+ 'Order a replacement card if yours is damaged or about to expire.',
38
+ 'Keep your delivery address up to date so new cards arrive in the right place.',
39
+ 'Contact support if a card payment looks unfamiliar or incorrect.',
40
+ ];
41
+
28
42
  function AllVariants({ gap = '1rem' }: { gap?: string }) {
29
43
  const [states, setStates] = useState({
30
44
  negativeExpanded: true,
@@ -137,6 +151,63 @@ export const MobileVariants: Story = {
137
151
  ...withVariantConfig(['mobile']),
138
152
  };
139
153
 
154
+ /** Neutral background regression test with page content scrolled under the mobile overhang. */
155
+ export const BackgroundIsNotTransparent: Story = {
156
+ args: {
157
+ sentiment: 'neutral',
158
+ },
159
+ argTypes: {
160
+ sentiment: {
161
+ control: 'radio',
162
+ options: ['negative', 'warning', 'neutral', 'success'],
163
+ },
164
+ },
165
+ render: function Render({ sentiment }) {
166
+ return (
167
+ <div
168
+ data-testid="background-scroll-container"
169
+ style={{
170
+ width: 350,
171
+ height: 640,
172
+ overflowY: 'auto',
173
+ border: '1px solid var(--color-border-neutral)',
174
+ }}
175
+ >
176
+ <div style={{ position: 'sticky', top: 0, zIndex: 1 }}>
177
+ <CriticalBanner
178
+ sentiment={sentiment}
179
+ title="Your account requires verification"
180
+ description="Please verify your identity to continue using all features."
181
+ action={{ label: 'Verify now', onClick: fn() }}
182
+ />
183
+ </div>
184
+ <main style={{ padding: 'var(--size-24) var(--size-16) var(--size-48)' }}>
185
+ <h1 style={{ margin: '0 0 var(--size-8)', fontSize: 32, lineHeight: 1.1 }}>Debit card</h1>
186
+ <p style={{ margin: '0 0 var(--size-24)' }}>Spend in 150+ currencies</p>
187
+ {BACKGROUND_SCROLL_CONTENT.map((paragraph) => (
188
+ <p key={paragraph}>{paragraph}</p>
189
+ ))}
190
+ </main>
191
+ </div>
192
+ );
193
+ },
194
+ play: async ({ canvasElement }) => {
195
+ const scrollContainer = canvasElement.querySelector(
196
+ '[data-testid="background-scroll-container"]',
197
+ );
198
+
199
+ if (scrollContainer) {
200
+ scrollContainer.scrollTop = 250;
201
+ await wait(ENTRY_ANIMATION_DURATION);
202
+ }
203
+ },
204
+ ...withVariantConfig(['mobile'], {
205
+ parameters: {
206
+ controls: { include: ['sentiment'] },
207
+ },
208
+ }),
209
+ };
210
+
140
211
  /** Mobile entry animation visual regression test. */
141
212
  export const AnimatedEntryMobile: Story = {
142
213
  render: function Render() {