@transferwise/components 46.138.0 → 46.140.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 (59) hide show
  1. package/build/flowNavigation/FlowNavigation.js +2 -4
  2. package/build/flowNavigation/FlowNavigation.js.map +1 -1
  3. package/build/flowNavigation/FlowNavigation.mjs +2 -4
  4. package/build/flowNavigation/FlowNavigation.mjs.map +1 -1
  5. package/build/loader/Loader.js +16 -6
  6. package/build/loader/Loader.js.map +1 -1
  7. package/build/loader/Loader.mjs +17 -7
  8. package/build/loader/Loader.mjs.map +1 -1
  9. package/build/main.css +33 -285
  10. package/build/moneyInput/MoneyInput.js +2 -1
  11. package/build/moneyInput/MoneyInput.js.map +1 -1
  12. package/build/moneyInput/MoneyInput.mjs +2 -1
  13. package/build/moneyInput/MoneyInput.mjs.map +1 -1
  14. package/build/popover/Popover.js +2 -2
  15. package/build/popover/Popover.js.map +1 -1
  16. package/build/popover/Popover.mjs +2 -2
  17. package/build/popover/Popover.mjs.map +1 -1
  18. package/build/select/Select.js +0 -3
  19. package/build/select/Select.js.map +1 -1
  20. package/build/select/Select.mjs +0 -3
  21. package/build/select/Select.mjs.map +1 -1
  22. package/build/styles/css/neptune.css +11 -275
  23. package/build/styles/less/neptune-tokens.less +2 -2
  24. package/build/styles/listItem/ListItem.css +1 -0
  25. package/build/styles/loader/Loader.css +14 -4
  26. package/build/styles/main.css +33 -285
  27. package/build/styles/props/neptune-tokens.css +1 -1
  28. package/build/styles/styles/less/neptune.css +11 -275
  29. package/build/types/flowNavigation/FlowNavigation.d.ts.map +1 -1
  30. package/build/types/loader/Loader.d.ts +4 -1
  31. package/build/types/loader/Loader.d.ts.map +1 -1
  32. package/build/types/moneyInput/MoneyInput.d.ts +1 -0
  33. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  34. package/build/types/select/Select.d.ts.map +1 -1
  35. package/package.json +1 -1
  36. package/src/flowNavigation/FlowNavigation.story.tsx +14 -9
  37. package/src/flowNavigation/FlowNavigation.test.js +2 -2
  38. package/src/flowNavigation/FlowNavigation.test.story.tsx +77 -0
  39. package/src/flowNavigation/FlowNavigation.tsx +2 -5
  40. package/src/inputs/SelectInput/_stories/SelectInput.test.story.tsx +82 -0
  41. package/src/listItem/ListItem.css +1 -0
  42. package/src/listItem/ListItem.less +1 -0
  43. package/src/loader/Loader.css +14 -4
  44. package/src/loader/Loader.less +54 -88
  45. package/src/loader/Loader.story.tsx +4 -0
  46. package/src/loader/Loader.test.tsx +20 -5
  47. package/src/loader/Loader.tsx +18 -7
  48. package/src/main.css +33 -285
  49. package/src/modal/Modal.test.story.tsx +61 -0
  50. package/src/moneyInput/MoneyInput.story.tsx +20 -0
  51. package/src/moneyInput/MoneyInput.test.tsx +49 -0
  52. package/src/moneyInput/MoneyInput.tsx +2 -0
  53. package/src/popover/Popover.story.tsx +45 -0
  54. package/src/popover/Popover.test.story.tsx +124 -0
  55. package/src/popover/Popover.test.tsx +55 -0
  56. package/src/popover/Popover.tsx +2 -2
  57. package/src/select/Select.test.story.tsx +74 -1
  58. package/src/select/Select.tsx +0 -3
  59. package/src/styles/less/neptune.css +11 -275
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 Fri, 10 Apr 2026 14:46:00 GMT
3
+ * Generated on Wed, 13 May 2026 12:45:11 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 Fri, 10 Apr 2026 14:46:00 GMT
147
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
148
148
  */
149
149
 
150
150
  .np-theme-personal {
@@ -326,75 +326,9 @@
326
326
  --font-family-display: 'Wise Sans', 'Inter', sans-serif;
327
327
  }
328
328
 
329
- /**
330
- * We added new shape theme into tokens to prevent breaking changes. This is a temporary measure.
331
- *
332
- * We delete this hack once all consumers no longer import tokens in their projects (e.g Next.js app.tsx or Storybook's preivew.tsx)
333
- */
334
-
335
- @media (max-width: 320px) {
336
- .np-theme-personal {
337
- --delta: 2;
338
- --size-4: calc(4px / var(--delta));
339
- --size-5: calc(5px / var(--delta));
340
- --size-8: calc(8px / var(--delta));
341
- --size-10: calc(10px / var(--delta));
342
- --size-12: calc(12px / var(--delta));
343
- --size-14: calc(14px / var(--delta));
344
- --size-16: calc(16px / var(--delta));
345
- --size-24: calc(24px / var(--delta));
346
- --size-32: calc(32px / var(--delta));
347
- --size-40: calc(40px / var(--delta));
348
- --size-48: calc(48px / var(--delta));
349
- --size-52: calc(52px / var(--delta));
350
- --size-56: calc(56px / var(--delta));
351
- --size-60: calc(60px / var(--delta));
352
- --size-64: calc(64px / var(--delta));
353
- --size-72: calc(72px / var(--delta));
354
- --size-80: calc(80px / var(--delta));
355
- --size-88: calc(88px / var(--delta));
356
- --size-96: calc(96px / var(--delta));
357
- --size-104: calc(104px / var(--delta));
358
- --size-112: calc(112px / var(--delta));
359
- --size-120: calc(120px / var(--delta));
360
- --size-126: calc(126px / var(--delta));
361
- --size-128: calc(128px / var(--delta));
362
- --size-146: calc(146px / var(--delta));
363
- --size-154: calc(154px / var(--delta));
364
- --size-x-small: calc(24px / var(--delta));
365
- --size-small: calc(32px / var(--delta));
366
- --size-medium: calc(40px / var(--delta));
367
- --size-large: calc(48px / var(--delta));
368
- --size-x-large: calc(56px / var(--delta));
369
- --size-2x-large: calc(72px / var(--delta));
370
- --space-content-horizontal: calc(16px / var(--delta));
371
- --space-small: calc(16px / var(--delta));
372
- --space-medium: calc(32px / var(--delta));
373
- --space-large: calc(40px / var(--delta));
374
- --space-x-large: calc(56px / var(--delta));
375
- --padding-x-small: var(--size-8);
376
- --padding-small: var(--size-16);
377
- --padding-medium: var(--size-24);
378
- --padding-large: var(--size-32);
379
- --input-height-base: var(--size-32);
380
- --input-height-large: var(--input-height-small);
381
- --input-padding: var(--input-padding-small);
382
- --input-padding-large: var(--input-padding-small);
383
- --input-group-addon-padding: var(--input-group-addon-sm-padding);
384
- --input-group-addon-lg-padding: var(--input-group-addon-sm-padding);
385
- --btn-height: var(--input-height-base);
386
- --btn-lg-height: var(--btn-height);
387
- --btn-sm-height: var(--btn-height);
388
- --btn-padding: var(--input-padding);
389
- --btn-sm-padding: var(--btn-padding);
390
- --btn-lg-padding: var(--btn-padding);
391
- --dropdown-link-padding: var(--size-12) var(--size-16);
392
- }
393
- }
394
-
395
329
  /**
396
330
  * Do not edit directly, this file was auto-generated.
397
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
331
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
398
332
  */
399
333
 
400
334
  .np-theme-personal--forest-green {
@@ -576,75 +510,9 @@
576
510
  --font-family-display: 'Wise Sans', 'Inter', sans-serif;
577
511
  }
578
512
 
579
- /**
580
- * We added new shape theme into tokens to prevent breaking changes. This is a temporary measure.
581
- *
582
- * We delete this hack once all consumers no longer import tokens in their projects (e.g Next.js app.tsx or Storybook's preivew.tsx)
583
- */
584
-
585
- @media (max-width: 320px) {
586
- .np-theme-personal {
587
- --delta: 2;
588
- --size-4: calc(4px / var(--delta));
589
- --size-5: calc(5px / var(--delta));
590
- --size-8: calc(8px / var(--delta));
591
- --size-10: calc(10px / var(--delta));
592
- --size-12: calc(12px / var(--delta));
593
- --size-14: calc(14px / var(--delta));
594
- --size-16: calc(16px / var(--delta));
595
- --size-24: calc(24px / var(--delta));
596
- --size-32: calc(32px / var(--delta));
597
- --size-40: calc(40px / var(--delta));
598
- --size-48: calc(48px / var(--delta));
599
- --size-52: calc(52px / var(--delta));
600
- --size-56: calc(56px / var(--delta));
601
- --size-60: calc(60px / var(--delta));
602
- --size-64: calc(64px / var(--delta));
603
- --size-72: calc(72px / var(--delta));
604
- --size-80: calc(80px / var(--delta));
605
- --size-88: calc(88px / var(--delta));
606
- --size-96: calc(96px / var(--delta));
607
- --size-104: calc(104px / var(--delta));
608
- --size-112: calc(112px / var(--delta));
609
- --size-120: calc(120px / var(--delta));
610
- --size-126: calc(126px / var(--delta));
611
- --size-128: calc(128px / var(--delta));
612
- --size-146: calc(146px / var(--delta));
613
- --size-154: calc(154px / var(--delta));
614
- --size-x-small: calc(24px / var(--delta));
615
- --size-small: calc(32px / var(--delta));
616
- --size-medium: calc(40px / var(--delta));
617
- --size-large: calc(48px / var(--delta));
618
- --size-x-large: calc(56px / var(--delta));
619
- --size-2x-large: calc(72px / var(--delta));
620
- --space-content-horizontal: calc(16px / var(--delta));
621
- --space-small: calc(16px / var(--delta));
622
- --space-medium: calc(32px / var(--delta));
623
- --space-large: calc(40px / var(--delta));
624
- --space-x-large: calc(56px / var(--delta));
625
- --padding-x-small: var(--size-8);
626
- --padding-small: var(--size-16);
627
- --padding-medium: var(--size-24);
628
- --padding-large: var(--size-32);
629
- --input-height-base: var(--size-32);
630
- --input-height-large: var(--input-height-small);
631
- --input-padding: var(--input-padding-small);
632
- --input-padding-large: var(--input-padding-small);
633
- --input-group-addon-padding: var(--input-group-addon-sm-padding);
634
- --input-group-addon-lg-padding: var(--input-group-addon-sm-padding);
635
- --btn-height: var(--input-height-base);
636
- --btn-lg-height: var(--btn-height);
637
- --btn-sm-height: var(--btn-height);
638
- --btn-padding: var(--input-padding);
639
- --btn-sm-padding: var(--btn-padding);
640
- --btn-lg-padding: var(--btn-padding);
641
- --dropdown-link-padding: var(--size-12) var(--size-16);
642
- }
643
- }
644
-
645
513
  /**
646
514
  * Do not edit directly, this file was auto-generated.
647
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
515
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
648
516
  */
649
517
 
650
518
  .np-theme-personal--bright-green {
@@ -826,75 +694,9 @@
826
694
  --font-family-display: 'Wise Sans', 'Inter', sans-serif;
827
695
  }
828
696
 
829
- /**
830
- * We added new shape theme into tokens to prevent breaking changes. This is a temporary measure.
831
- *
832
- * We delete this hack once all consumers no longer import tokens in their projects (e.g Next.js app.tsx or Storybook's preivew.tsx)
833
- */
834
-
835
- @media (max-width: 320px) {
836
- .np-theme-personal {
837
- --delta: 2;
838
- --size-4: calc(4px / var(--delta));
839
- --size-5: calc(5px / var(--delta));
840
- --size-8: calc(8px / var(--delta));
841
- --size-10: calc(10px / var(--delta));
842
- --size-12: calc(12px / var(--delta));
843
- --size-14: calc(14px / var(--delta));
844
- --size-16: calc(16px / var(--delta));
845
- --size-24: calc(24px / var(--delta));
846
- --size-32: calc(32px / var(--delta));
847
- --size-40: calc(40px / var(--delta));
848
- --size-48: calc(48px / var(--delta));
849
- --size-52: calc(52px / var(--delta));
850
- --size-56: calc(56px / var(--delta));
851
- --size-60: calc(60px / var(--delta));
852
- --size-64: calc(64px / var(--delta));
853
- --size-72: calc(72px / var(--delta));
854
- --size-80: calc(80px / var(--delta));
855
- --size-88: calc(88px / var(--delta));
856
- --size-96: calc(96px / var(--delta));
857
- --size-104: calc(104px / var(--delta));
858
- --size-112: calc(112px / var(--delta));
859
- --size-120: calc(120px / var(--delta));
860
- --size-126: calc(126px / var(--delta));
861
- --size-128: calc(128px / var(--delta));
862
- --size-146: calc(146px / var(--delta));
863
- --size-154: calc(154px / var(--delta));
864
- --size-x-small: calc(24px / var(--delta));
865
- --size-small: calc(32px / var(--delta));
866
- --size-medium: calc(40px / var(--delta));
867
- --size-large: calc(48px / var(--delta));
868
- --size-x-large: calc(56px / var(--delta));
869
- --size-2x-large: calc(72px / var(--delta));
870
- --space-content-horizontal: calc(16px / var(--delta));
871
- --space-small: calc(16px / var(--delta));
872
- --space-medium: calc(32px / var(--delta));
873
- --space-large: calc(40px / var(--delta));
874
- --space-x-large: calc(56px / var(--delta));
875
- --padding-x-small: var(--size-8);
876
- --padding-small: var(--size-16);
877
- --padding-medium: var(--size-24);
878
- --padding-large: var(--size-32);
879
- --input-height-base: var(--size-32);
880
- --input-height-large: var(--input-height-small);
881
- --input-padding: var(--input-padding-small);
882
- --input-padding-large: var(--input-padding-small);
883
- --input-group-addon-padding: var(--input-group-addon-sm-padding);
884
- --input-group-addon-lg-padding: var(--input-group-addon-sm-padding);
885
- --btn-height: var(--input-height-base);
886
- --btn-lg-height: var(--btn-height);
887
- --btn-sm-height: var(--btn-height);
888
- --btn-padding: var(--input-padding);
889
- --btn-sm-padding: var(--btn-padding);
890
- --btn-lg-padding: var(--btn-padding);
891
- --dropdown-link-padding: var(--size-12) var(--size-16);
892
- }
893
- }
894
-
895
697
  /**
896
698
  * Do not edit directly, this file was auto-generated.
897
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
699
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
898
700
  */
899
701
 
900
702
  .np-theme-personal--dark {
@@ -1076,75 +878,9 @@
1076
878
  --font-family-display: 'Wise Sans', 'Inter', sans-serif;
1077
879
  }
1078
880
 
1079
- /**
1080
- * We added new shape theme into tokens to prevent breaking changes. This is a temporary measure.
1081
- *
1082
- * We delete this hack once all consumers no longer import tokens in their projects (e.g Next.js app.tsx or Storybook's preivew.tsx)
1083
- */
1084
-
1085
- @media (max-width: 320px) {
1086
- .np-theme-personal {
1087
- --delta: 2;
1088
- --size-4: calc(4px / var(--delta));
1089
- --size-5: calc(5px / var(--delta));
1090
- --size-8: calc(8px / var(--delta));
1091
- --size-10: calc(10px / var(--delta));
1092
- --size-12: calc(12px / var(--delta));
1093
- --size-14: calc(14px / var(--delta));
1094
- --size-16: calc(16px / var(--delta));
1095
- --size-24: calc(24px / var(--delta));
1096
- --size-32: calc(32px / var(--delta));
1097
- --size-40: calc(40px / var(--delta));
1098
- --size-48: calc(48px / var(--delta));
1099
- --size-52: calc(52px / var(--delta));
1100
- --size-56: calc(56px / var(--delta));
1101
- --size-60: calc(60px / var(--delta));
1102
- --size-64: calc(64px / var(--delta));
1103
- --size-72: calc(72px / var(--delta));
1104
- --size-80: calc(80px / var(--delta));
1105
- --size-88: calc(88px / var(--delta));
1106
- --size-96: calc(96px / var(--delta));
1107
- --size-104: calc(104px / var(--delta));
1108
- --size-112: calc(112px / var(--delta));
1109
- --size-120: calc(120px / var(--delta));
1110
- --size-126: calc(126px / var(--delta));
1111
- --size-128: calc(128px / var(--delta));
1112
- --size-146: calc(146px / var(--delta));
1113
- --size-154: calc(154px / var(--delta));
1114
- --size-x-small: calc(24px / var(--delta));
1115
- --size-small: calc(32px / var(--delta));
1116
- --size-medium: calc(40px / var(--delta));
1117
- --size-large: calc(48px / var(--delta));
1118
- --size-x-large: calc(56px / var(--delta));
1119
- --size-2x-large: calc(72px / var(--delta));
1120
- --space-content-horizontal: calc(16px / var(--delta));
1121
- --space-small: calc(16px / var(--delta));
1122
- --space-medium: calc(32px / var(--delta));
1123
- --space-large: calc(40px / var(--delta));
1124
- --space-x-large: calc(56px / var(--delta));
1125
- --padding-x-small: var(--size-8);
1126
- --padding-small: var(--size-16);
1127
- --padding-medium: var(--size-24);
1128
- --padding-large: var(--size-32);
1129
- --input-height-base: var(--size-32);
1130
- --input-height-large: var(--input-height-small);
1131
- --input-padding: var(--input-padding-small);
1132
- --input-padding-large: var(--input-padding-small);
1133
- --input-group-addon-padding: var(--input-group-addon-sm-padding);
1134
- --input-group-addon-lg-padding: var(--input-group-addon-sm-padding);
1135
- --btn-height: var(--input-height-base);
1136
- --btn-lg-height: var(--btn-height);
1137
- --btn-sm-height: var(--btn-height);
1138
- --btn-padding: var(--input-padding);
1139
- --btn-sm-padding: var(--btn-padding);
1140
- --btn-lg-padding: var(--btn-padding);
1141
- --dropdown-link-padding: var(--size-12) var(--size-16);
1142
- }
1143
- }
1144
-
1145
881
  /**
1146
882
  * Do not edit directly, this file was auto-generated.
1147
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
883
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
1148
884
  */
1149
885
 
1150
886
  .np-theme-platform {
@@ -1328,7 +1064,7 @@
1328
1064
 
1329
1065
  /**
1330
1066
  * Do not edit directly, this file was auto-generated.
1331
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
1067
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
1332
1068
  */
1333
1069
 
1334
1070
  .np-theme-platform--forest-green {
@@ -1512,7 +1248,7 @@
1512
1248
 
1513
1249
  /**
1514
1250
  * Do not edit directly, this file was auto-generated.
1515
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
1251
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
1516
1252
  */
1517
1253
 
1518
1254
  .np-theme-business {
@@ -1697,7 +1433,7 @@
1697
1433
 
1698
1434
  /**
1699
1435
  * Do not edit directly, this file was auto-generated.
1700
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
1436
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
1701
1437
  */
1702
1438
 
1703
1439
  .np-theme-business--dark {
@@ -1882,7 +1618,7 @@
1882
1618
 
1883
1619
  /**
1884
1620
  * Do not edit directly, this file was auto-generated.
1885
- * Generated on Fri, 10 Apr 2026 14:46:00 GMT
1621
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
1886
1622
  */
1887
1623
 
1888
1624
  .np-theme-business--forest-green {
@@ -2067,7 +1803,7 @@
2067
1803
 
2068
1804
  /**
2069
1805
  * Do not edit directly, this file was auto-generated.
2070
- * Generated on Fri, 10 Apr 2026 14:46:01 GMT
1806
+ * Generated on Wed, 13 May 2026 12:45:12 GMT
2071
1807
  */
2072
1808
 
2073
1809
  .np-theme-business--bright-green {
@@ -28156,11 +27892,11 @@ a[data-toggle="tooltip"] {
28156
27892
  align-items: stretch;
28157
27893
  background-color: rgba(134,167,189,0.10196);
28158
27894
  background-color: var(--Card-background-color);
28159
- border-radius: calc(32px / 2);
27895
+ border-radius: 32px;
28160
27896
  border-radius: var(--Card-border-radius);
28161
- gap: calc(16px / 2);
27897
+ gap: 16px;
28162
27898
  gap: var(--Card-flex-gap);
28163
- padding: calc(24px / 2);
27899
+ padding: 24px;
28164
27900
  padding: var(--Card-padding);
28165
27901
  position: relative;
28166
27902
  box-sizing: border-box;
@@ -30086,6 +29822,7 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
30086
29822
  .wds-list-item-navigation .tw-icon-chevron-right {
30087
29823
  color: #c9cbce;
30088
29824
  color: var(--color-interactive-secondary);
29825
+ display: block;
30089
29826
  }
30090
29827
 
30091
29828
  .wds-list-item-control {
@@ -30838,6 +30575,17 @@ button.np-link {
30838
30575
  }
30839
30576
 
30840
30577
  .tw-loader {
30578
+ display: flex;
30579
+ flex-direction: column;
30580
+ align-items: center;
30581
+ gap: 16px;
30582
+ gap: var(--size-16);
30583
+ width: 190px;
30584
+ text-align: center;
30585
+ word-break: break-word;
30586
+ }
30587
+
30588
+ .tw-loader-asset {
30841
30589
  overflow: hidden;
30842
30590
  border-radius: 50%;
30843
30591
  backface-visibility: hidden;
@@ -30854,11 +30602,11 @@ button.np-link {
30854
30602
  transition: opacity 300ms cubic-bezier(0.24, 0, 0.3, 1);
30855
30603
  }
30856
30604
 
30857
- .tw-loader--visible {
30605
+ .tw-loader-asset--visible {
30858
30606
  opacity: 1;
30859
30607
  }
30860
30608
 
30861
- .tw-loader::before {
30609
+ .tw-loader-asset::before {
30862
30610
  content: "";
30863
30611
  display: block;
30864
30612
  width: 4.5rem;
@@ -30878,7 +30626,7 @@ button.np-link {
30878
30626
  animation-iteration-count: infinite;
30879
30627
  }
30880
30628
 
30881
- .tw-loader--sm {
30629
+ .tw-loader-asset--sm {
30882
30630
  --coin-size: 3rem;
30883
30631
  --coin-edge-width-offset: translateX(0.275rem);
30884
30632
  --coin-edge-width-negative-offset: translateX(-0.275rem);
@@ -30886,7 +30634,7 @@ button.np-link {
30886
30634
  --box-shadow-backwards: -0.025rem 0 0 var(--coin-colour), -0.05rem 0 0 var(--coin-colour), -0.075rem 0 0 var(--coin-colour), -0.1rem 0 0 var(--coin-colour), -0.125rem 0 0 var(--coin-colour), -0.15rem 0 0 var(--coin-colour), -0.175rem 0 0 var(--coin-colour), -0.2rem 0 0 var(--coin-colour), -0.225rem 0 0 var(--coin-colour), -0.25rem 0 0 var(--coin-colour), -0.275rem 0 0 var(--coin-colour), -0.3rem 0 0 var(--coin-colour), -0.325rem 0 0 var(--coin-colour), -0.35rem 0 0 var(--coin-colour), -0.375rem 0 0 var(--coin-colour), -0.4rem 0 0 var(--coin-colour), -0.425rem 0 0 var(--coin-colour), -0.45rem 0 0 var(--coin-colour), -0.475rem 0 0 var(--coin-colour);
30887
30635
  }
30888
30636
 
30889
- .tw-loader--md {
30637
+ .tw-loader-asset--md {
30890
30638
  --coin-size: 4.5rem;
30891
30639
  --coin-edge-width-offset: translateX(0.375rem);
30892
30640
  --coin-edge-width-negative-offset: translateX(-0.375rem);
@@ -31468,7 +31216,7 @@ html:not([dir="rtl"]) .np-navigation-option {
31468
31216
  border-radius: var(--nudge-border-radius);
31469
31217
  display: flex;
31470
31218
  flex: 1;
31471
- gap: calc(16px / 2);
31219
+ gap: 16px;
31472
31220
  gap: var(--nudge-flex-gap);
31473
31221
  min-height: 106px;
31474
31222
  min-height: var(--nudge-min-height);
@@ -34666,9 +34414,9 @@ html:not([dir="rtl"]) .np-navigation-option {
34666
34414
  --buttonTopRightOffset: var(--size-16);
34667
34415
  --clickAreaTopRightOffset: calc((var(--clickAreaSize) - var(--iconSize)) * -0.5);
34668
34416
  position: absolute;
34669
- right: calc(16px / 2);
34417
+ right: 16px;
34670
34418
  right: var(--buttonTopRightOffset);
34671
- top: calc(16px / 2);
34419
+ top: 16px;
34672
34420
  top: var(--buttonTopRightOffset);
34673
34421
  }
34674
34422
 
@@ -1,5 +1,6 @@
1
1
  import { action } from 'storybook/actions';
2
2
  import { Meta, StoryObj } from '@storybook/react-webpack5';
3
+ import { expect, userEvent, within } from 'storybook/test';
3
4
  import { ScreenMode, ThemeProvider } from '@wise/components-theming';
4
5
  import { useState } from 'react';
5
6
  import { Button, Modal, ModalProps } from '..';
@@ -123,3 +124,63 @@ export const WithThemeProviderInContentMobile: Story = {
123
124
  ),
124
125
  ...withVariantConfig(['mobile']),
125
126
  };
127
+
128
+ const wait = async (duration = 500) =>
129
+ new Promise<void>((resolve) => {
130
+ setTimeout(resolve, duration);
131
+ });
132
+
133
+ /**
134
+ * This test insures that there's no unintended page scroll after the modal
135
+ * is closed without selecting an option (e.g. clicking outside).
136
+ */
137
+ export const NoScrollAfterClose: Story = {
138
+ args: {
139
+ title: 'Modal Title',
140
+ body: lorem100,
141
+ scroll: Scroll.VIEWPORT,
142
+ },
143
+ render: function Render(args) {
144
+ const [open, setOpen] = useState(false);
145
+
146
+ return (
147
+ <div>
148
+ <style>
149
+ {`
150
+ .storybook-container{
151
+ min-height: unset;
152
+ height: unset;
153
+ }
154
+ `}
155
+ </style>
156
+ <p style={{ height: '70vh', background: 'blanchedalmond' }} />
157
+
158
+ <Button v2 onClick={() => setOpen(true)}>
159
+ Open Modal
160
+ </Button>
161
+ <Modal {...args} open={open} onClose={() => setOpen(false)} />
162
+
163
+ <p style={{ margin: '1rem 0', height: '150vh', background: 'blanchedalmond' }} />
164
+ </div>
165
+ );
166
+ },
167
+ play: async ({ canvasElement, step }) => {
168
+ const canvas = within(canvasElement);
169
+ const trigger = canvas.getByRole('button', { name: /Open Modal/i });
170
+
171
+ await step('Open the modal', async () => {
172
+ await userEvent.click(trigger);
173
+ await wait();
174
+ });
175
+
176
+ await step('Close the modal with Escape', async () => {
177
+ await userEvent.keyboard('{Escape}');
178
+ await wait();
179
+ });
180
+
181
+ await step('Verify the page has not scrolled', async () => {
182
+ const scrollParent = canvasElement.ownerDocument.documentElement;
183
+ await expect(scrollParent.scrollTop).toBe(0);
184
+ });
185
+ },
186
+ };
@@ -164,6 +164,26 @@ export const WithDecimals: Story = {
164
164
  },
165
165
  };
166
166
 
167
+ export const DisabledOptions: Story = {
168
+ args: {
169
+ currencies: [
170
+ { header: 'Popular currencies' },
171
+ exampleCurrency.eur,
172
+ exampleCurrency.gbp,
173
+ { ...exampleCurrency.usd, disabled: true },
174
+ { header: 'All currencies' },
175
+ exampleCurrency.aud,
176
+ { ...exampleCurrency.cny, disabled: true },
177
+ exampleCurrency.jpy,
178
+ ],
179
+ selectedCurrency: exampleCurrency.eur,
180
+ },
181
+ play: async ({ canvasElement }) => {
182
+ const canvas = within(canvasElement);
183
+ await userEvent.click(canvas.getByRole('combobox'));
184
+ },
185
+ };
186
+
167
187
  export const OpenedInput: Story = {
168
188
  ...MultipleCurrencies,
169
189
  play: async ({ canvasElement }) => {
@@ -566,6 +566,55 @@ describe('Money Input', () => {
566
566
  expect(screen.getByRole('listbox', { name: triggerLabel ?? '' })).toBeInTheDocument();
567
567
  });
568
568
 
569
+ describe('disabled options', () => {
570
+ const disabledCurrency: CurrencyOptionItem = {
571
+ value: 'CNY',
572
+ label: 'CNY',
573
+ note: 'Chinese yuan',
574
+ currency: 'cny',
575
+ disabled: true,
576
+ };
577
+
578
+ it('renders disabled currency option with aria-disabled', async () => {
579
+ customRender({
580
+ currencies: [{ header: 'Popular currencies' }, ...popularCurrencies, disabledCurrency],
581
+ });
582
+ await openDropdown();
583
+ const cnyOption = screen.getByRole('option', { name: /CNY/ });
584
+ expect(cnyOption).toHaveAttribute('aria-disabled', 'true');
585
+ });
586
+
587
+ it('does not call onCurrencyChange when a disabled option is clicked', async () => {
588
+ customRender({
589
+ currencies: [{ header: 'Popular currencies' }, ...popularCurrencies, disabledCurrency],
590
+ });
591
+ await openDropdown();
592
+ const cnyOption = screen.getByRole('option', { name: /CNY/ });
593
+ await userEvent.click(cnyOption);
594
+ expect(initialProps.onCurrencyChange).not.toHaveBeenCalled();
595
+ });
596
+
597
+ it('skips disabled option during keyboard navigation', async () => {
598
+ customRender({
599
+ currencies: [popularCurrencies[0], disabledCurrency, popularCurrencies[2]],
600
+ });
601
+ await openDropdown();
602
+ // Navigate down from first option — should skip disabled CNY and land on GBP
603
+ await userEvent.keyboard('{ArrowDown}{ArrowDown}');
604
+ await userEvent.keyboard('{Enter}');
605
+ await waitFor(() => {
606
+ expect(initialProps.onCurrencyChange).toHaveBeenCalledWith(popularCurrencies[2]);
607
+ });
608
+ });
609
+
610
+ it('does not mark options without disabled property as disabled', async () => {
611
+ customRender();
612
+ await openDropdown();
613
+ const eurOption = screen.getByRole('option', { name: /EUR/ });
614
+ expect(eurOption).not.toHaveAttribute('aria-disabled', 'true');
615
+ });
616
+ });
617
+
569
618
  it('renders custom action button in dropdown footer and calls onCustomAction', async () => {
570
619
  const onCustomAction = jest.fn();
571
620
  render(
@@ -34,6 +34,7 @@ export interface CurrencyOptionItem {
34
34
  currency: string;
35
35
  note?: string;
36
36
  searchable?: string;
37
+ disabled?: boolean;
37
38
  }
38
39
 
39
40
  export interface CurrencyHeaderItem {
@@ -256,6 +257,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
256
257
  type: 'option',
257
258
  value: item,
258
259
  filterMatchers: [item.value, item.label, item.note ?? '', item.searchable ?? ''],
260
+ disabled: item.disabled,
259
261
  });
260
262
  }
261
263
  });
@@ -71,3 +71,48 @@ export const WithoutVisibleTitle: Story = {
71
71
  ),
72
72
  },
73
73
  } satisfies Meta<typeof Popover>;
74
+
75
+ /**
76
+ * The `preferredPlacement` prop indicates where the Popover should appear
77
+ * relative to its trigger element. However, it is a preference, not a guarantee.
78
+ *
79
+ * If there isn't enough viewport space in the preferred direction, the Popover
80
+ * automatically flips to an alternative placement. The fallback order is:
81
+ * - `top` → tries `bottom`, then `right`, then `left`
82
+ * - `bottom` → tries `top`, then `right`, then `left`
83
+ * - `left` → tries `right`, then `top`, then `bottom`
84
+ * - `right` → tries `left`, then `top`, then `bottom`
85
+ *
86
+ * For example, if you set `preferredPlacement="top"` but the trigger is near
87
+ * the top of the viewport, the Popover will flip to `bottom` instead.
88
+ *
89
+ * Try scrolling this story so triggers are near viewport edges to see the
90
+ * flip behaviour in action.
91
+ */
92
+ export const PreferredPlacement: Story = {
93
+ render: () => (
94
+ <div
95
+ style={{
96
+ display: 'flex',
97
+ flexWrap: 'wrap',
98
+ gap: '48px',
99
+ justifyContent: 'center',
100
+ alignItems: 'center',
101
+ padding: '120px 80px',
102
+ }}
103
+ >
104
+ {([Position.TOP, Position.RIGHT, Position.BOTTOM, Position.LEFT] as const).map(
105
+ (placement) => (
106
+ <Popover
107
+ key={placement}
108
+ preferredPlacement={placement}
109
+ title="Guaranteed rate"
110
+ content={<Content />}
111
+ >
112
+ <Button v2>{placement}</Button>
113
+ </Popover>
114
+ ),
115
+ )}
116
+ </div>
117
+ ),
118
+ };