@transferwise/components 45.15.0 → 45.16.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 (111) hide show
  1. package/build/i18n/en.json +8 -0
  2. package/build/index.esm.js +550 -488
  3. package/build/index.esm.js.map +1 -1
  4. package/build/index.js +549 -487
  5. package/build/index.js.map +1 -1
  6. package/build/main.css +1 -1
  7. package/build/styles/dateLookup/DateLookup.css +1 -1
  8. package/build/styles/main.css +1 -1
  9. package/build/styles/popover/Popover.css +1 -1
  10. package/build/styles/promoCard/PromoCard.css +1 -1
  11. package/build/types/alert/Alert.d.ts.map +1 -1
  12. package/build/types/avatarWrapper/AvatarWrapper.d.ts +14 -5
  13. package/build/types/avatarWrapper/AvatarWrapper.d.ts.map +1 -1
  14. package/build/types/common/Option/Option.d.ts.map +1 -1
  15. package/build/types/common/card/Card.d.ts.map +1 -1
  16. package/build/types/common/card/index.d.ts +1 -0
  17. package/build/types/common/card/index.d.ts.map +1 -1
  18. package/build/types/common/focusBoundary/FocusBoundary.d.ts +2 -2
  19. package/build/types/common/focusBoundary/FocusBoundary.d.ts.map +1 -1
  20. package/build/types/dateInput/DateInput.d.ts +2 -0
  21. package/build/types/dateInput/DateInput.d.ts.map +1 -1
  22. package/build/types/dateLookup/DateLookup.messages.d.ts +65 -0
  23. package/build/types/dateLookup/DateLookup.messages.d.ts.map +1 -0
  24. package/build/types/dateLookup/dateHeader/DateHeader.d.ts +3 -1
  25. package/build/types/dateLookup/dateHeader/DateHeader.d.ts.map +1 -1
  26. package/build/types/dateLookup/tableLink/TableLink.d.ts +4 -26
  27. package/build/types/dateLookup/tableLink/TableLink.d.ts.map +1 -1
  28. package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts +4 -29
  29. package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts.map +1 -1
  30. package/build/types/inputs/_BottomSheet.d.ts.map +1 -1
  31. package/build/types/inputs/_Popover.d.ts.map +1 -1
  32. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  33. package/build/types/promoCard/PromoCard.d.ts +9 -3
  34. package/build/types/promoCard/PromoCard.d.ts.map +1 -1
  35. package/build/types/promoCard/PromoCardIndicator.d.ts +5 -3
  36. package/build/types/promoCard/PromoCardIndicator.d.ts.map +1 -1
  37. package/build/types/snackbar/Snackbar.d.ts.map +1 -1
  38. package/build/types/tabs/Tabs.d.ts.map +1 -1
  39. package/build/types/upload/steps/completeStep/completeStep.d.ts.map +1 -1
  40. package/build/types/upload/steps/processingStep/processingStep.d.ts.map +1 -1
  41. package/package.json +4 -3
  42. package/src/accordion/AccordionItem/__snapshots__/AccordionItem.spec.js.snap +6 -6
  43. package/src/alert/Alert.js +11 -9
  44. package/src/alert/Alert.spec.js +22 -13
  45. package/src/alert/withArrow/withArrow.spec.js +4 -4
  46. package/src/avatarWrapper/AvatarWrapper.tsx +20 -8
  47. package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +1 -1
  48. package/src/card/Card.spec.js +2 -2
  49. package/src/common/Option/Option.tsx +1 -7
  50. package/src/common/bottomSheet/__snapshots__/BottomSheet.spec.tsx.snap +8 -1
  51. package/src/common/card/Card.tsx +6 -2
  52. package/src/common/card/index.ts +1 -0
  53. package/src/common/focusBoundary/FocusBoundary.tsx +9 -32
  54. package/src/dateInput/DateInput.js +6 -0
  55. package/src/dateInput/DateInput.story.tsx +2 -0
  56. package/src/dateLookup/DateLookup.css +1 -1
  57. package/src/dateLookup/DateLookup.keyboardEvents.spec.js +3 -3
  58. package/src/dateLookup/DateLookup.less +4 -0
  59. package/src/dateLookup/DateLookup.messages.js +44 -0
  60. package/src/dateLookup/DateLookup.testingLibrary.spec.js +39 -0
  61. package/src/dateLookup/dateHeader/DateHeader.js +48 -26
  62. package/src/dateLookup/dateHeader/DateHeader.spec.js +37 -0
  63. package/src/dateLookup/dayCalendar/DayCalendar.js +3 -1
  64. package/src/dateLookup/dayCalendar/DayCalendar.spec.js +7 -1
  65. package/src/dateLookup/dayCalendar/table/DayCalendarTable.js +7 -3
  66. package/src/dateLookup/dayCalendar/table/DayCalendarTable.spec.js +1 -0
  67. package/src/dateLookup/monthCalendar/MonthCalendar.js +3 -1
  68. package/src/dateLookup/monthCalendar/MonthCalendar.spec.js +7 -1
  69. package/src/dateLookup/monthCalendar/table/MonthCalendarTable.spec.js +4 -5
  70. package/src/dateLookup/tableLink/TableLink.js +25 -3
  71. package/src/dateLookup/tableLink/TableLink.spec.js +66 -4
  72. package/src/dateLookup/yearCalendar/YearCalendar.js +16 -3
  73. package/src/dateLookup/yearCalendar/YearCalendar.spec.js +14 -1
  74. package/src/dateLookup/yearCalendar/table/YearCalendarTable.spec.js +4 -5
  75. package/src/i18n/en.json +8 -0
  76. package/src/inputs/SelectInput.story.tsx +36 -9
  77. package/src/inputs/_BottomSheet.less +1 -1
  78. package/src/inputs/_BottomSheet.tsx +57 -52
  79. package/src/inputs/_Popover.less +1 -1
  80. package/src/inputs/_Popover.tsx +31 -24
  81. package/src/listItem/ListItem.story.tsx +1 -1
  82. package/src/main.css +1 -1
  83. package/src/phoneNumberInput/PhoneNumberInput.js +1 -0
  84. package/src/popover/Popover.css +1 -1
  85. package/src/promoCard/PromoCard.css +1 -1
  86. package/src/promoCard/PromoCard.less +9 -9
  87. package/src/promoCard/PromoCard.spec.tsx +1 -0
  88. package/src/promoCard/PromoCard.story.tsx +90 -30
  89. package/src/promoCard/PromoCard.tsx +69 -22
  90. package/src/promoCard/PromoCardIndicator.tsx +20 -8
  91. package/src/snackbar/Snackbar.js +6 -1
  92. package/src/snackbar/Snackbar.spec.js +1 -3
  93. package/src/tabs/Tabs.js +2 -1
  94. package/src/upload/Upload.js +1 -1
  95. package/src/upload/steps/completeStep/completeStep.js +4 -1
  96. package/src/upload/steps/processingStep/processingStep.js +1 -0
  97. package/src/uploadInput/uploadItem/UploadItem.tsx +1 -1
  98. package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts +0 -2
  99. package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts.map +0 -1
  100. package/build/types/common/focusBoundary/utils/index.d.ts +0 -3
  101. package/build/types/common/focusBoundary/utils/index.d.ts.map +0 -1
  102. package/build/types/common/focusBoundary/utils/resetFocus.d.ts +0 -2
  103. package/build/types/common/focusBoundary/utils/resetFocus.d.ts.map +0 -1
  104. package/src/common/focusBoundary/FocusBoundary.spec.tsx +0 -66
  105. package/src/common/focusBoundary/__snapshots__/FocusBoundary.spec.tsx.snap +0 -16
  106. package/src/common/focusBoundary/utils/getFocusableElements.js +0 -25
  107. package/src/common/focusBoundary/utils/getFocusableElements.spec.js +0 -51
  108. package/src/common/focusBoundary/utils/index.js +0 -2
  109. package/src/common/focusBoundary/utils/resetFocus.js +0 -23
  110. package/src/common/focusBoundary/utils/resetFocus.spec.js +0 -103
  111. package/src/snackbar/__snapshots__/Snackbar.spec.js.snap +0 -5
@@ -157,6 +157,7 @@ const PhoneNumberInput = (props) => {
157
157
  <div className={`input-group input-group-${size}`}>
158
158
  <input
159
159
  id={id}
160
+ autoComplete="tel-national"
160
161
  name="phoneNumber"
161
162
  inputMode="numeric"
162
163
  value={internalValue.suffix}
@@ -1 +1 @@
1
- .np-theme-personal .np-popover__container{border-radius:16px;border-radius:var(--radius-medium)}.np-popover__container .np-popover__content{color:#5d7079;color:var(--color-content-secondary);font-size:.875rem;font-size:var(--font-size-14)}.np-popover__container .np-popover__content p:last-child{margin-bottom:0}.np-popover__container.np-panel .np-popover__content{max-width:276px;padding:16px 24px;padding:var(--size-16) var(--size-24)}.np-theme-personal .np-popover__container.np-panel .np-popover__content{padding:24px;padding:var(--size-24)}.np-popover__container.np-bottom-sheet .np-popover__title{color:#37517e;color:var(--color-content-primary);font-size:1.625rem;font-size:var(--font-size-26);font-weight:600;font-weight:var(--font-weight-semi-bold);letter-spacing:0;letter-spacing:-.02em;line-height:1.2;line-height:var(--line-height-title);line-height:122%;margin:0}.np-popover__container.np-bottom-sheet .np-popover__title+p{margin-top:8px;margin-top:var(--size-8)}.np-popover__container.np-bottom-sheet .np-popover__content{padding:32px 24px;padding:var(--size-32) var(--size-24)}
1
+ .np-theme-personal .np-popover__container{border-radius:16px;border-radius:var(--radius-medium)}.np-popover__container .np-popover__content{color:#5d7079;color:var(--color-content-secondary);font-size:.875rem;font-size:var(--font-size-14)}.np-popover__container .np-popover__content p:last-child{margin-bottom:0}.np-popover__container.np-panel .np-popover__content{max-width:276px;padding:16px 24px;padding:var(--size-16) var(--size-24)}.np-theme-personal .np-popover__container.np-panel .np-popover__content{padding:24px;padding:var(--size-24)}.np-popover__container.np-bottom-sheet .np-popover__title{color:#37517e;color:var(--color-content-primary);font-size:1.625rem;font-size:var(--font-size-26);font-weight:600;font-weight:var(--font-weight-semi-bold);letter-spacing:0;letter-spacing:-.02em;line-height:1.2;line-height:var(--line-height-title);line-height:122%;margin:0}.np-popover__container.np-bottom-sheet .np-popover__title+ol:not(.list-unstyled),.np-popover__container.np-bottom-sheet .np-popover__title+p,.np-popover__container.np-bottom-sheet .np-popover__title+ul:not(.list-unstyled){margin-top:8px;margin-top:var(--size-8)}.np-popover__container.np-bottom-sheet .np-popover__content{padding:32px 24px;padding:var(--size-32) var(--size-24)}
@@ -1 +1 @@
1
- .np-Card{--Card-image-scale:1;--Card-image-translate:0;--Card-indicator-text-background-color:var(--color-background-neutral);--Card-indicator-icon-background-color:var(--color-interactive-accent);--Card-indicator-icon-color:var(--color-interactive-control);--Card-check-background-color:var(--color-interactive-primary);--Card-check-color:var(--color-interactive-control)}.np-Card--promoCard{--Card-max-width:358px}.np-Card--promoCard.is-disabled{filter:grayscale(1);opacity:.45}.np-Card-image{height:auto;left:-24px;left:calc(var(--size-24)*-1);margin:0 auto;position:relative;transform:scale(var(--Card-image-scale)) translateY(var(--Card-image-translate));transition:transform .5s ease-in-out;width:100%;width:calc(100% + 48px);width:calc(100% + var(--size-48))}[dir=rtl] .np-Card-image{left:auto;right:-24px;right:calc(var(--size-24)*-1)}.np-Card-indicator{bottom:8px;bottom:var(--size-8);display:flex;gap:4px;gap:var(--size-4);position:absolute;right:8px;right:var(--size-8)}[dir=rtl] .np-Card-indicator{left:8px;left:var(--size-8);right:auto}.np-Card-indicatorText{background:var(--Card-indicator-text-background-color);border-radius:100px;display:inline-block;padding:16px;padding:var(--size-16);text-align:left;vertical-align:middle}.np-Card-indicatorIcon{align-items:center;background:var(--Card-indicator-icon-background-color);border-radius:9999px;border-radius:var(--radius-full);color:var(--Card-indicator-icon-color);display:inline-block;display:flex;height:56px;height:var(--size-56);justify-content:center;width:56px;width:var(--size-56)}[dir=rtl] .np-Card-indicatorIcon{transform:scaleX(-1)}.np-Card--checked,.np-Card--link{box-shadow:none;color:currentColor;cursor:pointer;transform:scale(1);transition:box-shadow .2s ease-in-out,transform .5s ease-in-out}.np-theme-personal:not(.np-theme-personal--dark,.np-theme-personal--bright-green,.np-theme-personal--forest-green) .np-Card--checked,.np-theme-personal:not(.np-theme-personal--dark,.np-theme-personal--bright-green,.np-theme-personal--forest-green) .np-Card--link{--Card-box-shadow:0px 20px var(--size-40) 0px var(--color-background-neutral);--Card-check-color:var(--color-interactive-accent)}.np-Card--checked.is-disabled,.np-Card--link.is-disabled{cursor:not-allowed}@media (prefers-reduced-motion:reduce){.np-Card--checked,.np-Card--link{transition:none}}.np-Card--checked:hover:not(.is-disabled,:disabled,.is-checked,:focus-within),.np-Card--link:hover:not(.is-disabled,:disabled,.is-checked,:focus-within){--Card-image-scale:1.1;box-shadow:var(--Card-box-shadow)}.np-Card--checked:active:not(.is-disabled,:disabled,.is-checked),.np-Card--link:active:not(.is-disabled,:disabled,.is-checked){--Card-background-color:var(--color-background-neutral-active);--Card-image-scale:1.1;--Card-image-translate:var(--size-8);box-shadow:var(--Card-box-shadow);transform:scale(98%)}.np-theme-personal--bright-green .np-Card--checked:active:not(.is-disabled,:disabled,.is-checked),.np-theme-personal--bright-green .np-Card--link:active:not(.is-disabled,:disabled,.is-checked){--Card-background-color:var(--color-background-neutral)}.np-Card--checked:focus-visible:not(.is-disabled,:disabled),.np-Card--checked:has(:focus-visible):not(.np-Card--checked),.np-Card--link:focus-visible:not(.is-disabled,:disabled),.np-Card--link:has(:focus-visible):not(.np-Card--checked){--Card-image-scale:1.1;box-shadow:var(--Card-box-shadow);outline:var(--ring-outline-color) solid 4px;outline:var(--ring-outline-color) solid var(--size-4);outline-offset:4px;outline-offset:var(--size-4)}.np-Card--link .np-Card-titleLink{color:#37517e;color:var(--color-content-primary);text-decoration:none}.np-Card--link .np-Card-titleLink:focus-visible{outline:none}.np-Card--link .np-Card-titleLink:after{content:"";display:block;height:100%;left:0;position:absolute;top:0;width:100%;z-index:10}.np-Card--checked.is-checked{box-shadow:0 0 0 4px var(--color-interactive-primary);box-shadow:0 0 0 var(--size-4) var(--color-interactive-primary)}.np-Card--checked.is-checked .np-Card-check{align-items:center;background:var(--Card-check-background-color);border-radius:9999px;border-radius:var(--radius-full);color:var(--Card-check-color);display:flex;height:40px;height:var(--size-40);justify-content:center;position:absolute;right:8px;right:var(--size-8);top:8px;top:var(--size-8);width:40px;width:var(--size-40)}[dir=rtl] .np-Card--checked.is-checked .np-Card-check{left:8px;left:var(--size-8);right:auto}.np-Card--checked.is-checked:focus-visible:not(.is-disabled,:disabled){box-shadow:none}.np-CardGroup{display:flex;flex-direction:column;gap:24px;gap:var(--size-24);width:100%}@media (min-width:768px){.np-CardGroup{flex-direction:row}}.np-CardGroup .np-Card.np-Card--promoCard{max-width:100%}
1
+ .np-Card{--Card-image-scale:1;--Card-image-translate:0;--Card-indicator-text-background-color:var(--color-background-neutral);--Card-indicator-icon-background-color:var(--color-interactive-accent);--Card-indicator-icon-color:var(--color-interactive-control);--Card-check-background-color:var(--color-interactive-primary);--Card-check-color:var(--color-interactive-control)}.np-Card--promoCard{--Card-max-width:358px}.np-Card--promoCard.is-disabled{filter:grayscale(1);opacity:.45}.np-Card-image{height:auto;left:-24px;left:calc(var(--size-24)*-1);margin:0 auto;position:relative;transform:scale(var(--Card-image-scale)) translateY(var(--Card-image-translate));transition:transform .5s ease-in-out;width:100%;width:calc(100% + 48px);width:calc(100% + var(--size-48))}[dir=rtl] .np-Card-image{left:auto;right:-24px;right:calc(var(--size-24)*-1)}.np-Card-description{color:#5d7079;color:var(--color-content-secondary)}.np-Card-indicator{bottom:8px;bottom:var(--size-8);display:flex;gap:4px;gap:var(--size-4);position:absolute;right:8px;right:var(--size-8)}[dir=rtl] .np-Card-indicator{left:8px;left:var(--size-8);right:auto}.np-Card-indicatorText{background:var(--Card-indicator-text-background-color);border-radius:100px;display:inline-block;padding:16px;padding:var(--size-16);text-align:left;vertical-align:middle}.np-Card-indicatorIcon .tw-icon{color:var(--Card-indicator-icon-color)}[dir=rtl] .np-Card-indicatorIcon .tw-icon{transform:scaleX(-1)}.np-Card--checked,.np-Card--link{box-shadow:none;color:currentColor;cursor:pointer;transform:scale(1);transition:box-shadow .2s ease-in-out,transform .5s ease-in-out}.np-theme-personal:not(.np-theme-personal--dark,.np-theme-personal--bright-green,.np-theme-personal--forest-green) .np-Card--checked,.np-theme-personal:not(.np-theme-personal--dark,.np-theme-personal--bright-green,.np-theme-personal--forest-green) .np-Card--link{--Card-box-shadow:0px 20px var(--size-40) 0px var(--color-background-neutral);--Card-check-color:var(--color-interactive-accent)}.np-Card--checked.is-disabled,.np-Card--link.is-disabled{cursor:not-allowed}@media (prefers-reduced-motion:reduce){.np-Card--checked,.np-Card--link{transition:none}}.np-Card--checked:hover:not(.is-disabled,:disabled,.is-checked,:focus-within),.np-Card--link:hover:not(.is-disabled,:disabled,.is-checked,:focus-within){--Card-image-scale:1.1;box-shadow:var(--Card-box-shadow)}.np-Card--checked:active:not(.is-disabled,:disabled,.is-checked),.np-Card--link:active:not(.is-disabled,:disabled,.is-checked){--Card-background-color:var(--color-background-neutral-active);--Card-image-scale:1.1;--Card-image-translate:var(--size-8);box-shadow:var(--Card-box-shadow);transform:scale(98%)}.np-theme-personal--bright-green .np-Card--checked:active:not(.is-disabled,:disabled,.is-checked),.np-theme-personal--bright-green .np-Card--link:active:not(.is-disabled,:disabled,.is-checked){--Card-background-color:var(--color-background-neutral)}.np-Card--checked:focus-visible:not(.is-disabled,:disabled),.np-Card--checked:has(:focus-visible):not(.np-Card--checked),.np-Card--link:focus-visible:not(.is-disabled,:disabled),.np-Card--link:has(:focus-visible):not(.np-Card--checked){--Card-image-scale:1.1;box-shadow:var(--Card-box-shadow);outline:var(--ring-outline-color) solid 4px;outline:var(--ring-outline-color) solid var(--size-4);outline-offset:4px;outline-offset:var(--size-4)}.np-Card--checked:has(.np-Card-closeButton:focus-visible),.np-Card--link:has(.np-Card-closeButton:focus-visible){outline:none}.np-Card--link .np-Card-titleLink{color:#37517e;color:var(--color-content-primary);text-decoration:none}.np-Card--link .np-Card-titleLink:focus-visible{outline:none}.np-Card--link .np-Card-titleLink:after{content:"";display:block;height:100%;left:0;position:absolute;top:0;width:100%;z-index:10}.np-Card--checked.is-checked{box-shadow:0 0 0 4px var(--color-interactive-primary);box-shadow:0 0 0 var(--size-4) var(--color-interactive-primary)}.np-Card--checked.is-checked .np-Card-check{align-items:center;background:var(--Card-check-background-color);border-radius:9999px;border-radius:var(--radius-full);color:var(--Card-check-color);display:flex;height:40px;height:var(--size-40);justify-content:center;position:absolute;right:8px;right:var(--size-8);top:8px;top:var(--size-8);width:40px;width:var(--size-40)}[dir=rtl] .np-Card--checked.is-checked .np-Card-check{left:8px;left:var(--size-8);right:auto}.np-Card--checked.is-checked:focus-visible:not(.is-disabled,:disabled){box-shadow:none}.np-CardGroup{display:flex;flex-direction:column;gap:24px;gap:var(--size-24);width:100%}@media (min-width:768px){.np-CardGroup{flex-direction:row}}.np-CardGroup .np-Card.np-Card--promoCard{max-width:100%}
@@ -32,6 +32,10 @@
32
32
  right: calc(var(--size-24) * -1);
33
33
  }
34
34
  }
35
+
36
+ &-description {
37
+ color: var(--color-content-secondary);
38
+ }
35
39
 
36
40
  &-indicator {
37
41
  position: absolute;
@@ -54,16 +58,8 @@
54
58
  border-radius: 100px;
55
59
  }
56
60
 
57
- &Icon {
61
+ &Icon .tw-icon {
58
62
  color: var(--Card-indicator-icon-color);
59
- width: var(--size-56);
60
- height: var(--size-56);
61
- display: inline-block;
62
- background: var(--Card-indicator-icon-background-color);
63
- border-radius: var(--radius-full);
64
- display: flex;
65
- justify-content: center;
66
- align-items: center;
67
63
 
68
64
  // Flips icon for right to left content
69
65
  [dir="rtl"] & {
@@ -123,6 +119,10 @@
123
119
  outline-offset: var(--size-4);
124
120
  box-shadow: var(--Card-box-shadow);
125
121
  }
122
+
123
+ &:has(.np-Card-closeButton:focus-visible) {
124
+ outline: none;
125
+ }
126
126
  }
127
127
 
128
128
  &--link {
@@ -11,6 +11,7 @@ describe('PromoCard', () => {
11
11
  description: 'Test Description',
12
12
  indicatorLabel: 'Test Indicator Label',
13
13
  testId: 'test-promo-card',
14
+ children: 'Test Content',
14
15
  };
15
16
 
16
17
  let rerenderPromoCard: (props?: PromoCardProps) => void;
@@ -1,11 +1,15 @@
1
1
  import { Meta, StoryObj } from '@storybook/react';
2
+ import { StarFill } from '@transferwise/icons';
2
3
 
3
- import PromoCard from './PromoCard';
4
+ import PromoCard, { PromoCardCheckedProps, PromoCardLinkProps } from './PromoCard';
4
5
 
5
6
  const meta: Meta<typeof PromoCard> = {
6
7
  component: PromoCard,
7
8
  title: 'Layouts/PromoCard',
8
9
  tags: ['autodocs'],
10
+ parameters: {
11
+ actions: { argTypesRegex: null },
12
+ },
9
13
  };
10
14
 
11
15
  export default meta;
@@ -22,54 +26,110 @@ export const Default: Story = {
22
26
 
23
27
  export const Link: Story = {
24
28
  args: {
25
- description: 'A card that lives online and works anywhere. Easy, secure, and always on hand.',
26
- title: 'Digital',
27
- href: 'https://wise.com',
28
- indicatorLabel: 'Free',
29
- imageSource: 'https://wise.com/web-art/assets/illustrations/digital-card-2-medium@2x.webp',
30
- },
29
+ ...Default.args,
30
+ href: '#',
31
+ } as PromoCardLinkProps,
32
+ };
33
+
34
+ export const TaskCard: Story = {
35
+ args: {
36
+ ...Link.args,
37
+ title: 'Add money for when you need it',
38
+ description: 'Get ready to send and spend.',
39
+ indicatorLabel: undefined,
40
+ imageSource: undefined,
41
+ onDismiss: () => {
42
+ alert('Dismissed!');
43
+ },
44
+ onClick: () => {
45
+ alert('Clicked!');
46
+ },
47
+ isSmall: true,
48
+ useDisplayFont: false,
49
+ className: 'taskCard',
50
+ } as PromoCardLinkProps,
51
+ decorators: [
52
+ (Story) => (
53
+ <div>
54
+ <style>
55
+ {`
56
+ .storybook-container {
57
+ background-color: var(--color-background-neutral);
58
+ }
59
+
60
+ .taskCard {
61
+ background-color: var(--color-background-screen);
62
+ position: relative;
63
+ width: 208px;
64
+ height: 268px;
65
+ }
66
+
67
+ .taskCard .np-Card-title {
68
+ margin-top: var(--size-24);
69
+ }
70
+
71
+
72
+ .taskCard.np-Card--link:hover:not(.is-disabled, :disabled, :focus-within) {
73
+ box-shadow: none;
74
+ background-color: var(--color-background-screen-hover);
75
+ }
76
+
77
+ .taskCard.np-Card--link:active:not(.is-disabled, :disabled) {
78
+ box-shadow: none;
79
+ background-color: var(--color-background-screen-hover);
80
+ }
81
+ `}
82
+ </style>
83
+ <Story />
84
+ </div>
85
+ ),
86
+ ],
87
+ };
88
+
89
+ export const TaskCardWithCustomIcon: Story = {
90
+ args: {
91
+ ...TaskCard.args,
92
+ indicatorIcon: <StarFill size={24} aria-hidden="true" />,
93
+ } as PromoCardLinkProps,
94
+ decorators: TaskCard.decorators,
95
+ };
96
+
97
+ export const TaskCardCompleted: Story = {
98
+ args: {
99
+ ...TaskCard.args,
100
+ onDismiss: undefined,
101
+ href: undefined,
102
+ indicatorIcon: 'check',
103
+ className: 'taskCard taskCard--completed np-theme--personal np-theme-personal--forest-green',
104
+ } as PromoCardLinkProps,
105
+ decorators: TaskCard.decorators,
31
106
  };
32
107
 
33
108
  export const Check: Story = {
34
109
  args: {
35
- description: 'A card that lives online and works anywhere. Easy, secure, and always on hand.',
36
- title: 'Digital',
110
+ ...Default.args,
37
111
  type: 'checkbox',
38
- indicatorLabel: 'Free',
39
- imageSource: 'https://wise.com/web-art/assets/illustrations/digital-card-2-medium@2x.webp',
40
- },
112
+ } as PromoCardCheckedProps,
41
113
  };
42
114
 
43
115
  export const DefaultChecked: Story = {
44
116
  args: {
45
- description: 'A card that lives online and works anywhere. Easy, secure, and always on hand.',
46
- title: 'Digital',
47
- type: 'checkbox',
48
- indicatorLabel: 'Free',
117
+ ...Check.args,
49
118
  defaultChecked: true,
50
- imageSource: 'https://wise.com/web-art/assets/illustrations/digital-card-2-medium@2x.webp',
51
- },
119
+ } as PromoCardCheckedProps,
52
120
  };
53
121
 
54
122
  export const Disabled: Story = {
55
123
  args: {
56
- description: 'A card that lives online and works anywhere. Easy, secure, and always on hand.',
57
- title: 'Digital',
58
- type: 'checkbox',
124
+ ...Check.args,
59
125
  isDisabled: true,
60
- indicatorLabel: 'Free',
61
- imageSource: 'https://wise.com/web-art/assets/illustrations/digital-card-2-medium@2x.webp',
62
126
  },
63
127
  };
64
128
 
65
129
  export const CustomClass: Story = {
66
130
  args: {
67
- description: 'A card that lives online and works anywhere. Easy, secure, and always on hand.',
68
- title: 'Digital',
69
- href: 'https://wise.com',
131
+ ...Link.args,
70
132
  className: 'np-CustomPromoCard',
71
- indicatorLabel: 'Free',
72
- imageSource: 'https://wise.com/web-art/assets/illustrations/digital-card-medium@2x.webp',
73
133
  },
74
134
  decorators: [
75
135
  (Story) => (
@@ -78,8 +138,8 @@ export const CustomClass: Story = {
78
138
  {`
79
139
  .np-CustomPromoCard {
80
140
  --Card-background-color: var(--color-bright-yellow);
81
- --Card-indicator-icon-background-color: var(--color-dark-gold);
82
- --Card-indicator-icon-color: var(--color-contrast);
141
+ --Card-indicator-icon-background-color: var(--color-background-neutral);
142
+ --color-interactive-control: var(--color-primary);
83
143
  }
84
144
  `}
85
145
  </style>
@@ -1,15 +1,16 @@
1
1
  import { Check } from '@transferwise/icons';
2
2
  import classNames from 'classnames';
3
- import React, { forwardRef, FunctionComponent, useState, useEffect, useMemo } from 'react';
3
+ import React, { forwardRef, FunctionComponent, ReactElement, useEffect, useState } from 'react';
4
4
 
5
5
  import Body from '../body';
6
6
  import { Typography } from '../common';
7
- import Card from '../common/card';
7
+ import Card, { CardProps } from '../common/card';
8
8
  import Display from '../display';
9
9
  import Image from '../image/Image';
10
+ import Title from '../title';
10
11
 
11
12
  import { usePromoCardContext } from './PromoCardContext';
12
- import PromoCardIndicator from './PromoCardIndicator';
13
+ import PromoCardIndicator, { PromoCardIndicatorProps } from './PromoCardIndicator';
13
14
 
14
15
  export type ReferenceType = React.Ref<HTMLInputElement>;
15
16
  export type LinkTarget = '_blank' | '_parent' | '_self' | '_top';
@@ -49,6 +50,9 @@ export interface PromoCardCommonProps {
49
50
  /** Optional prop to specify text for the indicator label of the PromoCard */
50
51
  indicatorLabel?: string;
51
52
 
53
+ /** Optional prop to specify the icon for the indicator icon of the PromoCard */
54
+ indicatorIcon?: PromoCardIndicatorProps['icon'];
55
+
52
56
  /** Optional prop to specify an image alt text */
53
57
  imageAlt?: string;
54
58
 
@@ -56,7 +60,7 @@ export interface PromoCardCommonProps {
56
60
  imageClass?: string;
57
61
 
58
62
  /** Optional prop to specify an image source url */
59
- imageSource: string;
63
+ imageSource?: string;
60
64
 
61
65
  /** Specify whether the PromoCard is disabled, or not */
62
66
  isDisabled?: boolean;
@@ -69,9 +73,12 @@ export interface PromoCardCommonProps {
69
73
 
70
74
  /** Required prop to specify the title text of the PromoCard */
71
75
  title: string;
76
+
77
+ /** Set to false to use body font style for the title */
78
+ useDisplayFont?: boolean;
72
79
  }
73
80
 
74
- export interface PromoCardLinkProps extends PromoCardCommonProps {
81
+ export interface PromoCardLinkProps extends PromoCardCommonProps, Omit<CardProps, 'children'> {
75
82
  /**
76
83
  * Optional prop to prompts a user to save the linked URL instead of
77
84
  * navigating to it
@@ -102,7 +109,7 @@ export interface PromoCardLinkProps extends PromoCardCommonProps {
102
109
  value?: never;
103
110
  }
104
111
 
105
- export interface PromoCardCheckedProps extends PromoCardCommonProps {
112
+ export interface PromoCardCheckedProps extends PromoCardCommonProps, Omit<CardProps, 'children'> {
106
113
  /** Specify the initial checked attribute of the PromoCard */
107
114
  defaultChecked?: boolean;
108
115
 
@@ -206,6 +213,7 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
206
213
  imageClass,
207
214
  imageSource,
208
215
  indicatorLabel,
216
+ indicatorIcon,
209
217
  isChecked,
210
218
  isDisabled,
211
219
  onClick,
@@ -216,6 +224,8 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
216
224
  title,
217
225
  type,
218
226
  value,
227
+ isSmall,
228
+ useDisplayFont = true,
219
229
  ...props
220
230
  },
221
231
  reference,
@@ -241,7 +251,25 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
241
251
  // Set the icon to `'arrow'` if `href` is truthy and `type` is falsy, or
242
252
  // `'download'` if `download` is truthy. If neither condition is true, set
243
253
  // `icon` to `undefined`.
244
- const icon = href && download ? 'download' : href ? 'arrow' : undefined;
254
+
255
+ // Create a function to get icon type
256
+ const getIconType = () => {
257
+ if (indicatorIcon) {
258
+ return indicatorIcon;
259
+ }
260
+
261
+ if (download) {
262
+ return 'download';
263
+ }
264
+
265
+ if (href && !type) {
266
+ return 'arrow';
267
+ }
268
+
269
+ return undefined;
270
+ };
271
+
272
+ const CardTitle = useDisplayFont ? Display : Title;
245
273
 
246
274
  // Define all class names string based on the values of the `href`, `type`,
247
275
  // `checked`, and `className` props.
@@ -261,6 +289,7 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
261
289
  onClick,
262
290
  ref: reference,
263
291
  'data-testid': testId,
292
+ isSmall,
264
293
  };
265
294
 
266
295
  // Object with Anchor props that will be passed to the `a` element. These
@@ -298,6 +327,33 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
298
327
  }
299
328
  : {};
300
329
 
330
+ const getTitle = () => {
331
+ const titleContent =
332
+ href && !type ? (
333
+ <a className="np-Card-titleLink" {...anchorProps}>
334
+ {title}
335
+ </a>
336
+ ) : (
337
+ title
338
+ );
339
+
340
+ const titleProps = {
341
+ id: `${componentId}-title`,
342
+ as: headingLevel,
343
+ className: 'np-Card-title',
344
+ };
345
+
346
+ return useDisplayFont ? (
347
+ <Display type={Typography.DISPLAY_SMALL} {...titleProps}>
348
+ {titleContent}
349
+ </Display>
350
+ ) : (
351
+ <Title type={Typography.TITLE_SUBSECTION} {...titleProps}>
352
+ {titleContent}
353
+ </Title>
354
+ );
355
+ };
356
+
301
357
  useEffect(() => {
302
358
  setChecked(defaultChecked ?? isChecked ?? false);
303
359
  }, [defaultChecked, isChecked]);
@@ -309,27 +365,18 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
309
365
  <Check size={24} aria-hidden="true" />
310
366
  </span>
311
367
  )}
312
- <Display
313
- id={`${componentId}-title`}
314
- as={headingLevel}
315
- className="np-Card-title"
316
- type={Typography.DISPLAY_SMALL}
317
- >
318
- {href && !type ? (
319
- <a className="np-Card-titleLink" {...anchorProps}>
320
- {title}
321
- </a>
322
- ) : (
323
- title
324
- )}
325
- </Display>
368
+
369
+ {getTitle()}
370
+
326
371
  <Body className="np-Card-description">{description}</Body>
372
+
327
373
  {imageSource && (
328
374
  <div className={classNames('np-Card-image', { imageClass })}>
329
375
  <Image src={imageSource} alt={imageAlt || ''} loading="lazy" />
330
376
  </div>
331
377
  )}
332
- <PromoCardIndicator label={indicatorLabel} icon={icon} />
378
+
379
+ <PromoCardIndicator label={indicatorLabel} icon={getIconType()} isSmall={isSmall} />
333
380
  </Card>
334
381
  );
335
382
  },
@@ -1,7 +1,8 @@
1
1
  import { ArrowRight, Check, Download } from '@transferwise/icons';
2
2
  import classNames from 'classnames';
3
- import { ReactNode } from 'react';
3
+ import { ReactElement, ReactNode } from 'react';
4
4
 
5
+ import Avatar, { AvatarType } from '../avatar';
5
6
  import Body from '../body';
6
7
  import { Typography } from '../common';
7
8
 
@@ -13,7 +14,10 @@ export type PromoCardIndicatorProps = {
13
14
  label?: string;
14
15
 
15
16
  /** Optional icon to display in the indicator. */
16
- icon?: 'check' | 'arrow' | 'download';
17
+ icon?: 'check' | 'arrow' | 'download' | ReactElement;
18
+
19
+ /** Optional prop to specify whether the indicator is sized small or not. */
20
+ isSmall?: boolean;
17
21
 
18
22
  /** Optional ID to add to the indicator container for testing purposes. */
19
23
  testid?: string;
@@ -31,7 +35,7 @@ export type PromoCardIndicatorProps = {
31
35
  *
32
36
  * @param {string} className - Optional class name(s) to add to the indicator container.
33
37
  * @param {string} label - Optional label to display next to the indicator.
34
- * @param {string} icon - Optional icon to display in the indicator.
38
+ * @param {string | ReactElement} icon - Optional icon to display in the indicator.
35
39
  * @param {string} testid - Optional ID to add to the indicator container for testing purposes.
36
40
  * @param {ReactNode} children - Optional children to display inside the indicator.
37
41
  * @returns {JSX.Element} - The PromoCardIndicator component.
@@ -43,11 +47,14 @@ const PromoCardIndicator: React.FC<PromoCardIndicatorProps> = ({
43
47
  children,
44
48
  label,
45
49
  icon,
50
+ isSmall = false,
46
51
  testid,
47
52
  ...rest
48
53
  }) => {
54
+ const isIconString = icon && typeof icon === 'string';
55
+
49
56
  const IconComponent =
50
- icon &&
57
+ isIconString &&
51
58
  {
52
59
  check: Check,
53
60
  arrow: ArrowRight,
@@ -61,10 +68,15 @@ const PromoCardIndicator: React.FC<PromoCardIndicatorProps> = ({
61
68
  {label}
62
69
  </Body>
63
70
  )}
64
- {IconComponent && (
65
- <span className="np-Card-indicatorIcon">
66
- <IconComponent size={24} aria-hidden="true" />
67
- </span>
71
+ {icon && (
72
+ <Avatar
73
+ type={AvatarType.ICON}
74
+ size={isSmall ? 40 : 56}
75
+ backgroundColor="var(--Card-indicator-icon-background-color)"
76
+ className="np-Card-indicatorIcon"
77
+ >
78
+ {IconComponent ? <IconComponent size={24} aria-hidden="true" /> : icon}
79
+ </Avatar>
68
80
  )}
69
81
  {children}
70
82
  </div>
@@ -91,7 +91,12 @@ export class Snackbar extends Component {
91
91
  }}
92
92
  unmountOnExit
93
93
  >
94
- <Body ref={this.bodyRef} as="span" className={`snackbar__text snackbar__text--${theme}`}>
94
+ <Body
95
+ ref={this.bodyRef}
96
+ as="span"
97
+ className={`snackbar__text snackbar__text--${theme}`}
98
+ aria-live="polite"
99
+ >
95
100
  {text}
96
101
  {action ? (
97
102
  <ActionButton className="snackbar__text__action" onClick={action.onClick}>
@@ -71,8 +71,6 @@ describe('Snackbar', () => {
71
71
  const snackbarWithNode = () => componentWithNode.find(Snackbar);
72
72
  componentWithNode.find('.button-trigger').simulate('click');
73
73
  expect(snackbarWithNode().text()).toContain('test');
74
-
75
- expect(snackbarWithNode().html()).toMatchSnapshot();
76
74
  });
77
75
 
78
76
  it('displays a single snack for the given duration with the given text', async () => {
@@ -107,6 +105,6 @@ describe('Snackbar', () => {
107
105
  );
108
106
  const snackbarWithNode = () => componentWithNode.find(Snackbar);
109
107
  componentWithNode.find('.button-trigger').simulate('click');
110
- expect(snackbarWithNode().html()).toMatchSnapshot();
108
+ expect(snackbarWithNode().prop('theme')).toBe('dark');
111
109
  });
112
110
  });
package/src/tabs/Tabs.js CHANGED
@@ -488,7 +488,8 @@ class Tabs extends Component {
488
488
  })}
489
489
  {translateLineX ? (
490
490
  <li
491
- className={classNames('tabs__line')}
491
+ role="none"
492
+ className="tabs__line"
492
493
  style={{
493
494
  width: this.getTabLineWidth(),
494
495
  transform: isRTL
@@ -344,7 +344,7 @@ class Upload extends Component {
344
344
  />
345
345
  )}
346
346
  {!isProcessing && (
347
- <div className="droppable-dropping-card droppable-card">
347
+ <div className="droppable-dropping-card droppable-card" aria-live="polite">
348
348
  <div className="droppable-card-content">
349
349
  <div className="circle circle-sm text-primary">
350
350
  <PlusIcon size="16" />
@@ -26,7 +26,10 @@ const CompleteStep = (props) => {
26
26
  return (
27
27
  <div className="droppable-complete-card droppable-card" aria-hidden={!isComplete}>
28
28
  <div className="droppable-card-content">
29
- <div className="droppable-card-content d-flex flex-column align-items-center">
29
+ <div
30
+ className="droppable-card-content d-flex flex-column align-items-center"
31
+ aria-live="polite"
32
+ >
30
33
  {isError ? (
31
34
  <>
32
35
  {isModern ? (
@@ -45,6 +45,7 @@ const ProcessingStep = (props) => {
45
45
  'm-b-2': isModern,
46
46
  })}
47
47
  type={Typography.TITLE_BODY}
48
+ aria-live="polite"
48
49
  >
49
50
  {psProcessingText}
50
51
  </Title>
@@ -134,7 +134,7 @@ const UploadItem = ({
134
134
  singleFileUpload={singleFileUpload}
135
135
  onDownload={onDownloadFile}
136
136
  >
137
- <div className="np-upload-button">
137
+ <div className="np-upload-button" aria-live="polite">
138
138
  <div className="media">
139
139
  <div className="np-upload-icon media-left">{getIcon()}</div>
140
140
  <div className="media-body text-xs-left" data-testid={TEST_IDS.mediaBody}>
@@ -1,2 +0,0 @@
1
- export function getFocusableElements(focusBoundaryContainer: Node): object;
2
- //# sourceMappingURL=getFocusableElements.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFocusableElements.d.ts","sourceRoot":"","sources":["../../../../../src/common/focusBoundary/utils/getFocusableElements.js"],"names":[],"mappings":"AAOO,6DAJI,IAAI,GACF,MAAM,CAoBlB"}
@@ -1,3 +0,0 @@
1
- export { getFocusableElements } from "./getFocusableElements";
2
- export { resetFocus } from "./resetFocus";
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/common/focusBoundary/utils/index.js"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export function resetFocus({ focusableEls: { first, last }, event }: object): void;
2
- //# sourceMappingURL=resetFocus.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resetFocus.d.ts","sourceRoot":"","sources":["../../../../../src/common/focusBoundary/utils/resetFocus.js"],"names":[],"mappings":"AAOO,qEAJI,MAAM,QAmBhB"}