@transferwise/components 46.137.1 → 46.139.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 (60) 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/i18n/uk.json +2 -0
  6. package/build/i18n/uk.json.js +2 -0
  7. package/build/i18n/uk.json.js.map +1 -1
  8. package/build/i18n/uk.json.mjs +2 -0
  9. package/build/i18n/uk.json.mjs.map +1 -1
  10. package/build/loader/Loader.js +16 -6
  11. package/build/loader/Loader.js.map +1 -1
  12. package/build/loader/Loader.mjs +17 -7
  13. package/build/loader/Loader.mjs.map +1 -1
  14. package/build/logo/Logo.js +3 -1
  15. package/build/logo/Logo.js.map +1 -1
  16. package/build/logo/Logo.mjs +3 -1
  17. package/build/logo/Logo.mjs.map +1 -1
  18. package/build/logo/logo-assets.js +147 -15
  19. package/build/logo/logo-assets.js.map +1 -1
  20. package/build/logo/logo-assets.mjs +147 -15
  21. package/build/logo/logo-assets.mjs.map +1 -1
  22. package/build/main.css +16 -4
  23. package/build/moneyInput/MoneyInput.js +2 -1
  24. package/build/moneyInput/MoneyInput.js.map +1 -1
  25. package/build/moneyInput/MoneyInput.mjs +2 -1
  26. package/build/moneyInput/MoneyInput.mjs.map +1 -1
  27. package/build/styles/listItem/ListItem.css +1 -0
  28. package/build/styles/loader/Loader.css +14 -4
  29. package/build/styles/main.css +16 -4
  30. package/build/types/flowNavigation/FlowNavigation.d.ts.map +1 -1
  31. package/build/types/loader/Loader.d.ts +4 -1
  32. package/build/types/loader/Loader.d.ts.map +1 -1
  33. package/build/types/logo/Logo.d.ts +7 -1
  34. package/build/types/logo/Logo.d.ts.map +1 -1
  35. package/build/types/logo/logo-assets.d.ts +144 -12
  36. package/build/types/logo/logo-assets.d.ts.map +1 -1
  37. package/build/types/moneyInput/MoneyInput.d.ts +1 -0
  38. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/flowNavigation/FlowNavigation.story.tsx +14 -9
  41. package/src/flowNavigation/FlowNavigation.test.js +2 -2
  42. package/src/flowNavigation/FlowNavigation.test.story.tsx +77 -0
  43. package/src/flowNavigation/FlowNavigation.tsx +2 -5
  44. package/src/i18n/uk.json +2 -0
  45. package/src/listItem/ListItem.css +1 -0
  46. package/src/listItem/ListItem.less +1 -0
  47. package/src/loader/Loader.css +14 -4
  48. package/src/loader/Loader.less +54 -88
  49. package/src/loader/Loader.story.tsx +4 -0
  50. package/src/loader/Loader.test.tsx +20 -5
  51. package/src/loader/Loader.tsx +18 -7
  52. package/src/logo/Logo.story.tsx +40 -0
  53. package/src/logo/Logo.test.story.tsx +51 -0
  54. package/src/logo/Logo.tsx +11 -1
  55. package/src/logo/logo-assets.tsx +55 -8
  56. package/src/main.css +16 -4
  57. package/src/moneyInput/MoneyInput.story.tsx +20 -0
  58. package/src/moneyInput/MoneyInput.test.tsx +49 -0
  59. package/src/moneyInput/MoneyInput.tsx +2 -0
  60. package/src/ssr.test.tsx +1 -0
@@ -10,6 +10,16 @@
10
10
  }
11
11
 
12
12
  .tw-loader {
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: center;
16
+ gap: var(--size-16);
17
+ width: 190px;
18
+ text-align: center;
19
+ word-break: break-word;
20
+ }
21
+
22
+ .tw-loader-asset {
13
23
  overflow: hidden;
14
24
  border-radius: 50%;
15
25
  backface-visibility: hidden;
@@ -49,44 +59,26 @@
49
59
  --coin-edge-width-offset: translateX(0.275rem);
50
60
  --coin-edge-width-negative-offset: translateX(-0.275rem);
51
61
  --box-shadow-forwards:
52
- 0.025rem 0 0 var(--coin-colour),
53
- 0.05rem 0 0 var(--coin-colour),
54
- 0.075rem 0 0 var(--coin-colour),
55
- 0.1rem 0 0 var(--coin-colour),
56
- 0.125rem 0 0 var(--coin-colour),
57
- 0.15rem 0 0 var(--coin-colour),
58
- 0.175rem 0 0 var(--coin-colour),
59
- 0.2rem 0 0 var(--coin-colour),
60
- 0.225rem 0 0 var(--coin-colour),
61
- 0.25rem 0 0 var(--coin-colour),
62
- 0.275rem 0 0 var(--coin-colour),
63
- 0.3rem 0 0 var(--coin-colour),
64
- 0.325rem 0 0 var(--coin-colour),
65
- 0.35rem 0 0 var(--coin-colour),
66
- 0.375rem 0 0 var(--coin-colour),
67
- 0.4rem 0 0 var(--coin-colour),
68
- 0.425rem 0 0 var(--coin-colour),
69
- 0.45rem 0 0 var(--coin-colour),
62
+ 0.025rem 0 0 var(--coin-colour), 0.05rem 0 0 var(--coin-colour),
63
+ 0.075rem 0 0 var(--coin-colour), 0.1rem 0 0 var(--coin-colour),
64
+ 0.125rem 0 0 var(--coin-colour), 0.15rem 0 0 var(--coin-colour),
65
+ 0.175rem 0 0 var(--coin-colour), 0.2rem 0 0 var(--coin-colour),
66
+ 0.225rem 0 0 var(--coin-colour), 0.25rem 0 0 var(--coin-colour),
67
+ 0.275rem 0 0 var(--coin-colour), 0.3rem 0 0 var(--coin-colour),
68
+ 0.325rem 0 0 var(--coin-colour), 0.35rem 0 0 var(--coin-colour),
69
+ 0.375rem 0 0 var(--coin-colour), 0.4rem 0 0 var(--coin-colour),
70
+ 0.425rem 0 0 var(--coin-colour), 0.45rem 0 0 var(--coin-colour),
70
71
  0.475rem 0 0 var(--coin-colour);
71
72
  --box-shadow-backwards:
72
- -0.025rem 0 0 var(--coin-colour),
73
- -0.05rem 0 0 var(--coin-colour),
74
- -0.075rem 0 0 var(--coin-colour),
75
- -0.1rem 0 0 var(--coin-colour),
76
- -0.125rem 0 0 var(--coin-colour),
77
- -0.15rem 0 0 var(--coin-colour),
78
- -0.175rem 0 0 var(--coin-colour),
79
- -0.2rem 0 0 var(--coin-colour),
80
- -0.225rem 0 0 var(--coin-colour),
81
- -0.25rem 0 0 var(--coin-colour),
82
- -0.275rem 0 0 var(--coin-colour),
83
- -0.3rem 0 0 var(--coin-colour),
84
- -0.325rem 0 0 var(--coin-colour),
85
- -0.35rem 0 0 var(--coin-colour),
86
- -0.375rem 0 0 var(--coin-colour),
87
- -0.4rem 0 0 var(--coin-colour),
88
- -0.425rem 0 0 var(--coin-colour),
89
- -0.45rem 0 0 var(--coin-colour),
73
+ -0.025rem 0 0 var(--coin-colour), -0.05rem 0 0 var(--coin-colour),
74
+ -0.075rem 0 0 var(--coin-colour), -0.1rem 0 0 var(--coin-colour),
75
+ -0.125rem 0 0 var(--coin-colour), -0.15rem 0 0 var(--coin-colour),
76
+ -0.175rem 0 0 var(--coin-colour), -0.2rem 0 0 var(--coin-colour),
77
+ -0.225rem 0 0 var(--coin-colour), -0.25rem 0 0 var(--coin-colour),
78
+ -0.275rem 0 0 var(--coin-colour), -0.3rem 0 0 var(--coin-colour),
79
+ -0.325rem 0 0 var(--coin-colour), -0.35rem 0 0 var(--coin-colour),
80
+ -0.375rem 0 0 var(--coin-colour), -0.4rem 0 0 var(--coin-colour),
81
+ -0.425rem 0 0 var(--coin-colour), -0.45rem 0 0 var(--coin-colour),
90
82
  -0.475rem 0 0 var(--coin-colour);
91
83
  }
92
84
 
@@ -95,59 +87,33 @@
95
87
  --coin-edge-width-offset: translateX(0.375rem);
96
88
  --coin-edge-width-negative-offset: translateX(-0.375rem);
97
89
  --box-shadow-forwards:
98
- 0.025rem 0 0 var(--coin-colour),
99
- 0.05rem 0 0 var(--coin-colour),
100
- 0.075rem 0 0 var(--coin-colour),
101
- 0.1rem 0 0 var(--coin-colour),
102
- 0.125rem 0 0 var(--coin-colour),
103
- 0.15rem 0 0 var(--coin-colour),
104
- 0.175rem 0 0 var(--coin-colour),
105
- 0.2rem 0 0 var(--coin-colour),
106
- 0.225rem 0 0 var(--coin-colour),
107
- 0.25rem 0 0 var(--coin-colour),
108
- 0.275rem 0 0 var(--coin-colour),
109
- 0.3rem 0 0 var(--coin-colour),
110
- 0.325rem 0 0 var(--coin-colour),
111
- 0.35rem 0 0 var(--coin-colour),
112
- 0.375rem 0 0 var(--coin-colour),
113
- 0.4rem 0 0 var(--coin-colour),
114
- 0.425rem 0 0 var(--coin-colour),
115
- 0.45rem 0 0 var(--coin-colour),
116
- 0.475rem 0 0 var(--coin-colour),
117
- 0.5rem 0 0 var(--coin-colour),
118
- 0.525rem 0 0 var(--coin-colour),
119
- 0.55rem 0 0 var(--coin-colour),
120
- 0.575rem 0 0 var(--coin-colour),
121
- 0.6rem 0 0 var(--coin-colour),
122
- 0.625rem 0 0 var(--coin-colour),
123
- 0.65rem 0 0 var(--coin-colour);
90
+ 0.025rem 0 0 var(--coin-colour), 0.05rem 0 0 var(--coin-colour),
91
+ 0.075rem 0 0 var(--coin-colour), 0.1rem 0 0 var(--coin-colour),
92
+ 0.125rem 0 0 var(--coin-colour), 0.15rem 0 0 var(--coin-colour),
93
+ 0.175rem 0 0 var(--coin-colour), 0.2rem 0 0 var(--coin-colour),
94
+ 0.225rem 0 0 var(--coin-colour), 0.25rem 0 0 var(--coin-colour),
95
+ 0.275rem 0 0 var(--coin-colour), 0.3rem 0 0 var(--coin-colour),
96
+ 0.325rem 0 0 var(--coin-colour), 0.35rem 0 0 var(--coin-colour),
97
+ 0.375rem 0 0 var(--coin-colour), 0.4rem 0 0 var(--coin-colour),
98
+ 0.425rem 0 0 var(--coin-colour), 0.45rem 0 0 var(--coin-colour),
99
+ 0.475rem 0 0 var(--coin-colour), 0.5rem 0 0 var(--coin-colour),
100
+ 0.525rem 0 0 var(--coin-colour), 0.55rem 0 0 var(--coin-colour),
101
+ 0.575rem 0 0 var(--coin-colour), 0.6rem 0 0 var(--coin-colour),
102
+ 0.625rem 0 0 var(--coin-colour), 0.65rem 0 0 var(--coin-colour);
124
103
  --box-shadow-backwards:
125
- -0.025rem 0 0 var(--coin-colour),
126
- -0.05rem 0 0 var(--coin-colour),
127
- -0.075rem 0 0 var(--coin-colour),
128
- -0.1rem 0 0 var(--coin-colour),
129
- -0.125rem 0 0 var(--coin-colour),
130
- -0.15rem 0 0 var(--coin-colour),
131
- -0.175rem 0 0 var(--coin-colour),
132
- -0.2rem 0 0 var(--coin-colour),
133
- -0.225rem 0 0 var(--coin-colour),
134
- -0.25rem 0 0 var(--coin-colour),
135
- -0.275rem 0 0 var(--coin-colour),
136
- -0.3rem 0 0 var(--coin-colour),
137
- -0.325rem 0 0 var(--coin-colour),
138
- -0.35rem 0 0 var(--coin-colour),
139
- -0.375rem 0 0 var(--coin-colour),
140
- -0.4rem 0 0 var(--coin-colour),
141
- -0.425rem 0 0 var(--coin-colour),
142
- -0.45rem 0 0 var(--coin-colour),
143
- -0.475rem 0 0 var(--coin-colour),
144
- -0.5rem 0 0 var(--coin-colour),
145
- -0.525rem 0 0 var(--coin-colour),
146
- -0.55rem 0 0 var(--coin-colour),
147
- -0.575rem 0 0 var(--coin-colour),
148
- -0.6rem 0 0 var(--coin-colour),
149
- -0.625rem 0 0 var(--coin-colour),
150
- -0.65rem 0 0 var(--coin-colour);
104
+ -0.025rem 0 0 var(--coin-colour), -0.05rem 0 0 var(--coin-colour),
105
+ -0.075rem 0 0 var(--coin-colour), -0.1rem 0 0 var(--coin-colour),
106
+ -0.125rem 0 0 var(--coin-colour), -0.15rem 0 0 var(--coin-colour),
107
+ -0.175rem 0 0 var(--coin-colour), -0.2rem 0 0 var(--coin-colour),
108
+ -0.225rem 0 0 var(--coin-colour), -0.25rem 0 0 var(--coin-colour),
109
+ -0.275rem 0 0 var(--coin-colour), -0.3rem 0 0 var(--coin-colour),
110
+ -0.325rem 0 0 var(--coin-colour), -0.35rem 0 0 var(--coin-colour),
111
+ -0.375rem 0 0 var(--coin-colour), -0.4rem 0 0 var(--coin-colour),
112
+ -0.425rem 0 0 var(--coin-colour), -0.45rem 0 0 var(--coin-colour),
113
+ -0.475rem 0 0 var(--coin-colour), -0.5rem 0 0 var(--coin-colour),
114
+ -0.525rem 0 0 var(--coin-colour), -0.55rem 0 0 var(--coin-colour),
115
+ -0.575rem 0 0 var(--coin-colour), -0.6rem 0 0 var(--coin-colour),
116
+ -0.625rem 0 0 var(--coin-colour), -0.65rem 0 0 var(--coin-colour);
151
117
  }
152
118
  }
153
119
 
@@ -7,6 +7,7 @@ export default {
7
7
  title: 'Loading/Loader',
8
8
  args: {
9
9
  size: 'md',
10
+ label: 'Sending your money',
10
11
  },
11
12
  argTypes: {
12
13
  size: {
@@ -15,6 +16,9 @@ export default {
15
16
  value: ['sm', 'md'],
16
17
  },
17
18
  },
19
+ label: {
20
+ control: 'text',
21
+ },
18
22
  },
19
23
  } satisfies Meta<typeof Loader>;
20
24
 
@@ -9,7 +9,7 @@ describe('Loader', () => {
9
9
 
10
10
  it('tests default state', () => {
11
11
  const { container } = render(<Loader />);
12
- expect(container.querySelectorAll('div.tw-loader--md')).toHaveLength(1);
12
+ expect(container.querySelectorAll('div.tw-loader-asset--md')).toHaveLength(1);
13
13
  expect(container.querySelector('div[data-testid]')).toBeNull();
14
14
  });
15
15
 
@@ -19,33 +19,48 @@ describe('Loader', () => {
19
19
  expect(screen.getByTestId(dataTestId)).toBeInTheDocument();
20
20
  });
21
21
 
22
+ it('renders label when displayInstantly is true', () => {
23
+ render(<Loader label="Sending your money" displayInstantly />);
24
+ expect(screen.getByText('Sending your money')).toBeInTheDocument();
25
+ });
26
+
27
+ it('does not render label before debounce completes', () => {
28
+ render(<Loader label="Sending your money" />);
29
+ expect(screen.queryByText('Sending your money')).not.toBeInTheDocument();
30
+ });
31
+
32
+ it('does not render label when label is not provided', () => {
33
+ render(<Loader displayInstantly />);
34
+ expect(screen.queryByText('Sending your money')).not.toBeInTheDocument();
35
+ });
36
+
22
37
  it('shows renders the next best size of loader when using a deprecated size on the new theme', () => {
23
38
  const { container, rerender } = render(
24
39
  <ThemeProvider theme="personal">
25
40
  <Loader {...{ small: true }} />
26
41
  </ThemeProvider>,
27
42
  );
28
- expect(container.querySelectorAll('div.tw-loader--sm')).toHaveLength(1);
43
+ expect(container.querySelectorAll('div.tw-loader-asset--sm')).toHaveLength(1);
29
44
 
30
45
  rerender(
31
46
  <ThemeProvider theme="personal">
32
47
  <Loader size="xs" />
33
48
  </ThemeProvider>,
34
49
  );
35
- expect(container.querySelectorAll('div.tw-loader--sm')).toHaveLength(1);
50
+ expect(container.querySelectorAll('div.tw-loader-asset--sm')).toHaveLength(1);
36
51
 
37
52
  rerender(
38
53
  <ThemeProvider theme="personal">
39
54
  <Loader size="lg" />
40
55
  </ThemeProvider>,
41
56
  );
42
- expect(container.querySelectorAll('div.tw-loader--md')).toHaveLength(1);
57
+ expect(container.querySelectorAll('div.tw-loader-asset--md')).toHaveLength(1);
43
58
 
44
59
  rerender(
45
60
  <ThemeProvider theme="personal">
46
61
  <Loader size="xl" />
47
62
  </ThemeProvider>,
48
63
  );
49
- expect(container.querySelectorAll('div.tw-loader--md')).toHaveLength(1);
64
+ expect(container.querySelectorAll('div.tw-loader-asset--md')).toHaveLength(1);
50
65
  });
51
66
  });
@@ -1,8 +1,10 @@
1
1
  import { useTheme } from '@wise/components-theming';
2
2
  import { clsx } from 'clsx';
3
- import { useEffect, useState } from 'react';
3
+ import { ReactNode, useEffect, useState } from 'react';
4
4
 
5
+ import Body from '../body';
5
6
  import { Size, SizeExtraSmall, SizeSmall, SizeMedium, SizeLarge, SizeExtraLarge } from '../common';
7
+ import { Typography } from '../common/propsValues/typography';
6
8
 
7
9
  // TODO: We gracefully deprecated xs, lg and xl -- remove these as part of a future breaking change to this component
8
10
  type DeprecatedSize = SizeExtraSmall | SizeLarge | SizeExtraLarge;
@@ -19,6 +21,8 @@ export type LoaderProps = {
19
21
  size?: SizeType | DeprecatedSize;
20
22
  /** @default false */
21
23
  displayInstantly?: boolean;
24
+ /** Optional label displayed below the loader */
25
+ label?: ReactNode;
22
26
  // TODO: refactor in favor of prop from `CommonProps` type
23
27
  /** @default {} */
24
28
  classNames?: Record<string, string>;
@@ -39,6 +43,7 @@ const Loader = ({
39
43
  small = false,
40
44
  size = Size.MEDIUM,
41
45
  displayInstantly = false,
46
+ label,
42
47
  classNames = {},
43
48
  ...restProps
44
49
  }: LoaderProps) => {
@@ -77,12 +82,18 @@ const Loader = ({
77
82
  }
78
83
 
79
84
  return (
80
- <div
81
- className={clsx(style('tw-loader'), style(`tw-loader--${supportedSize}`), {
82
- 'tw-loader--visible': hasDebounced,
83
- })}
84
- data-testid={restProps['data-testid']}
85
- />
85
+ <div className={style('tw-loader')} data-testid={restProps['data-testid']}>
86
+ <div
87
+ className={clsx(style('tw-loader-asset'), style(`tw-loader-asset--${supportedSize}`), {
88
+ 'tw-loader-asset--visible': hasDebounced,
89
+ })}
90
+ />
91
+ {label && hasDebounced && (
92
+ <Body type={Typography.BODY_LARGE_BOLD} as="span" className={style('text-secondary')}>
93
+ {label}
94
+ </Body>
95
+ )}
96
+ </div>
86
97
  );
87
98
  };
88
99
 
@@ -1,7 +1,9 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
3
  import Logo, { LogoType, LogoDisplay, LogoFormat } from './Logo';
4
+ import type { LogoSize } from './Logo';
4
5
  import { withVariantConfig } from '../../.storybook/helpers';
6
+ import Body from '../body';
5
7
 
6
8
  /**
7
9
  * **Design guidance**: <a href="https://wise.design/foundations/logo" target="_blank">wise.design/foundations/logo</a>
@@ -25,6 +27,10 @@ const meta: Meta<typeof Logo> = {
25
27
  control: 'radio',
26
28
  options: Object.values(LogoFormat),
27
29
  },
30
+ size: {
31
+ control: 'radio',
32
+ options: [16, 18, 20, 24, 28, 36] satisfies LogoSize[],
33
+ },
28
34
  inverse: { control: { disable: true } },
29
35
  },
30
36
  parameters: {
@@ -162,6 +168,40 @@ export const SecondaryLockup: Story = {
162
168
  },
163
169
  };
164
170
 
171
+ /**
172
+ * Controls the height and width of the logo in pixels.
173
+ */
174
+ export const Sizes: Story = {
175
+ argTypes: {
176
+ size: { table: { disable: true } },
177
+ },
178
+ render: (args) => (
179
+ <div style={{ display: 'flex', gap: '2rem', alignItems: 'flex-end', padding: '2rem' }}>
180
+ {([16, 18, 20, 24, 28, 36] as const).map((size) => (
181
+ <div
182
+ key={size}
183
+ style={{
184
+ display: 'flex',
185
+ flexDirection: 'column',
186
+ alignItems: 'center',
187
+ gap: '0.5rem',
188
+ }}
189
+ >
190
+ <Logo {...args} size={size} />
191
+ <Body>{size}</Body>
192
+ </div>
193
+ ))}
194
+ </div>
195
+ ),
196
+ parameters: {
197
+ docs: {
198
+ source: {
199
+ code: `<Logo size={..} />`,
200
+ },
201
+ },
202
+ },
203
+ };
204
+
165
205
  /**
166
206
  * When `display` is `"compact"`, only the fast-flag mark is rendered regardless of type or other settings.
167
207
  */
@@ -1,7 +1,10 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
3
  import Logo, { LogoType } from '.';
4
+ import { LogoFormat } from './Logo';
5
+ import type { LogoSize } from './Logo';
4
6
  import { withVariantConfig } from '../../.storybook/helpers';
7
+ import Body from '../body';
5
8
 
6
9
  const meta: Meta<typeof Logo> = {
7
10
  component: Logo,
@@ -42,3 +45,51 @@ export const Responsive: Story = {
42
45
  render: () => <AllVariants />,
43
46
  ...withVariantConfig(['mobile']),
44
47
  };
48
+
49
+ const sizes: LogoSize[] = [16, 18, 20, 24, 28, 36];
50
+
51
+ export const Sizes = () => (
52
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '3rem' }}>
53
+ {(['compact', 'full'] as const).map((display) => (
54
+ <div key={display} style={{ display: 'flex', gap: '2rem', alignItems: 'flex-end' }}>
55
+ {sizes.map((size) => (
56
+ <div
57
+ key={size}
58
+ style={{
59
+ display: 'flex',
60
+ flexDirection: 'column',
61
+ alignItems: 'center',
62
+ gap: '0.5rem',
63
+ }}
64
+ >
65
+ <Logo type="WISE" size={size} display={display} />
66
+ <Body>{size}</Body>
67
+ </div>
68
+ ))}
69
+ </div>
70
+ ))}
71
+ {[LogoType.WISE_BUSINESS, LogoType.WISE_PLATFORM].map((type) =>
72
+ [LogoFormat.PRIMARY_LOCKUP, LogoFormat.SECONDARY_LOCKUP].map((format) => (
73
+ <div
74
+ key={`${type}-${format}`}
75
+ style={{ display: 'flex', gap: '2rem', alignItems: 'flex-end' }}
76
+ >
77
+ {sizes.map((size) => (
78
+ <div
79
+ key={size}
80
+ style={{
81
+ display: 'flex',
82
+ flexDirection: 'column',
83
+ alignItems: 'center',
84
+ gap: '0.5rem',
85
+ }}
86
+ >
87
+ <Logo type={type} format={format} size={size} display="full" />
88
+ <Body>{size}</Body>
89
+ </div>
90
+ ))}
91
+ </div>
92
+ )),
93
+ )}
94
+ </div>
95
+ );
package/src/logo/Logo.tsx CHANGED
@@ -32,6 +32,8 @@ export enum LogoFormat {
32
32
  SECONDARY_LOCKUP = 'secondary-lockup',
33
33
  }
34
34
 
35
+ export type LogoSize = 16 | 18 | 20 | 24 | 28 | 36 | '16' | '18' | '20' | '24' | '28' | '36';
36
+
35
37
  export interface LogoProps {
36
38
  /** Extra classes applied to Logo */
37
39
  className?: string;
@@ -62,6 +64,11 @@ export interface LogoProps {
62
64
  * @default 'default'
63
65
  */
64
66
  format?: `${LogoFormat}`;
67
+ /**
68
+ * Controls the height and width of the logo in pixels.
69
+ * @default 24
70
+ */
71
+ size?: LogoSize;
65
72
  /**
66
73
  * Override default ({@link labelByType}) screen reader messages
67
74
  */
@@ -94,6 +101,7 @@ export default function Logo({
94
101
  type = 'WISE',
95
102
  format = 'default',
96
103
  display = 'responsive',
104
+ size = 24,
97
105
  'aria-label': ariaLabel,
98
106
  }: LogoProps) {
99
107
  const isScreenSm = !useScreenSize(Breakpoint.SMALL);
@@ -101,7 +109,9 @@ export default function Logo({
101
109
 
102
110
  const assetName = compact ? 'FastFlag' : getAssetName(type, format);
103
111
  const Asset = logoAssets[assetName];
104
- const { width, height } = logoAssetsDimensions[assetName];
112
+ const sizes = logoAssetsDimensions[assetName];
113
+ const { width, height } =
114
+ logoAssetsDimensions[assetName][Number(size) as keyof typeof sizes] ?? sizes[24];
105
115
 
106
116
  return (
107
117
  <span
@@ -1,17 +1,64 @@
1
1
  export const logoAssetsDimensions = {
2
- FastFlag: { width: 22, height: 24 },
3
- WiseLogo: { width: 94, height: 24 },
4
- WiseBusinessPrimary: { width: 210, height: 24 },
5
- WiseBusinessSecondary: { width: 97, height: 46 },
6
- WisePlatformPrimary: { width: 205, height: 24 },
7
- WisePlatformSecondary: { width: 94, height: 46 },
2
+ FastFlag: {
3
+ 16: { width: 16, height: 16 },
4
+ 18: { width: 18, height: 18 },
5
+ 20: { width: 20, height: 20 },
6
+ 24: { width: 24, height: 24 },
7
+ 28: { width: 28, height: 28 },
8
+ 36: { width: 36, height: 36 },
9
+ },
10
+ WiseLogo: {
11
+ 16: { width: 64, height: 16 },
12
+ 18: { width: 72, height: 18 },
13
+ 20: { width: 80, height: 20 },
14
+ 24: { width: 96, height: 24 },
15
+ 28: { width: 112, height: 28 },
16
+ 36: { width: 144, height: 36 },
17
+ },
18
+ WiseBusinessPrimary: {
19
+ 16: { width: 140, height: 16 },
20
+ 18: { width: 157.5, height: 18 },
21
+ 20: { width: 175, height: 20 },
22
+ 24: { width: 210, height: 24 },
23
+ 28: { width: 245, height: 28 },
24
+ 36: { width: 315, height: 36 },
25
+ },
26
+ WiseBusinessSecondary: {
27
+ 16: { width: 68, height: 32 },
28
+ 18: { width: 76.5, height: 36 },
29
+ 20: { width: 85, height: 40 },
30
+ 24: { width: 102, height: 48 },
31
+ 28: { width: 119, height: 56 },
32
+ 36: { width: 153, height: 72 },
33
+ },
34
+ WisePlatformPrimary: {
35
+ 16: { width: 136, height: 16 },
36
+ 18: { width: 153, height: 18 },
37
+ 20: { width: 170, height: 20 },
38
+ 24: { width: 204, height: 24 },
39
+ 28: { width: 238, height: 28 },
40
+ 36: { width: 306, height: 36 },
41
+ },
42
+ WisePlatformSecondary: {
43
+ 16: { width: 64, height: 32 },
44
+ 18: { width: 72, height: 36 },
45
+ 20: { width: 80, height: 40 },
46
+ 24: { width: 96, height: 48 },
47
+ 28: { width: 112, height: 56 },
48
+ 36: { width: 144, height: 72 },
49
+ },
8
50
  } as const;
9
51
 
10
52
  export type LogoAssetName = keyof typeof logoAssetsDimensions;
11
53
 
12
54
  function svgProps(name: LogoAssetName) {
13
- const { width, height } = logoAssetsDimensions[name];
14
- return { xmlns: 'http://www.w3.org/2000/svg', width, height, viewBox: `0 0 ${width} ${height}` };
55
+ const { width, height } = logoAssetsDimensions[name][24];
56
+ return {
57
+ xmlns: 'http://www.w3.org/2000/svg',
58
+ width: '100%',
59
+ height: '100%',
60
+ viewBox: `0 0 ${width} ${height}`,
61
+ };
15
62
  }
16
63
 
17
64
  export function FastFlag() {
package/src/main.css CHANGED
@@ -30086,6 +30086,7 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
30086
30086
  .wds-list-item-navigation .tw-icon-chevron-right {
30087
30087
  color: #c9cbce;
30088
30088
  color: var(--color-interactive-secondary);
30089
+ display: block;
30089
30090
  }
30090
30091
 
30091
30092
  .wds-list-item-control {
@@ -30838,6 +30839,17 @@ button.np-link {
30838
30839
  }
30839
30840
 
30840
30841
  .tw-loader {
30842
+ display: flex;
30843
+ flex-direction: column;
30844
+ align-items: center;
30845
+ gap: 16px;
30846
+ gap: var(--size-16);
30847
+ width: 190px;
30848
+ text-align: center;
30849
+ word-break: break-word;
30850
+ }
30851
+
30852
+ .tw-loader-asset {
30841
30853
  overflow: hidden;
30842
30854
  border-radius: 50%;
30843
30855
  backface-visibility: hidden;
@@ -30854,11 +30866,11 @@ button.np-link {
30854
30866
  transition: opacity 300ms cubic-bezier(0.24, 0, 0.3, 1);
30855
30867
  }
30856
30868
 
30857
- .tw-loader--visible {
30869
+ .tw-loader-asset--visible {
30858
30870
  opacity: 1;
30859
30871
  }
30860
30872
 
30861
- .tw-loader::before {
30873
+ .tw-loader-asset::before {
30862
30874
  content: "";
30863
30875
  display: block;
30864
30876
  width: 4.5rem;
@@ -30878,7 +30890,7 @@ button.np-link {
30878
30890
  animation-iteration-count: infinite;
30879
30891
  }
30880
30892
 
30881
- .tw-loader--sm {
30893
+ .tw-loader-asset--sm {
30882
30894
  --coin-size: 3rem;
30883
30895
  --coin-edge-width-offset: translateX(0.275rem);
30884
30896
  --coin-edge-width-negative-offset: translateX(-0.275rem);
@@ -30886,7 +30898,7 @@ button.np-link {
30886
30898
  --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
30899
  }
30888
30900
 
30889
- .tw-loader--md {
30901
+ .tw-loader-asset--md {
30890
30902
  --coin-size: 4.5rem;
30891
30903
  --coin-edge-width-offset: translateX(0.375rem);
30892
30904
  --coin-edge-width-negative-offset: translateX(-0.375rem);
@@ -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(