@transferwise/components 46.9.0 → 46.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/i18n/de.json +1 -0
- package/build/i18n/en.json +1 -0
- package/build/i18n/es.json +1 -0
- package/build/i18n/fr.json +1 -0
- package/build/i18n/hu.json +1 -0
- package/build/i18n/id.json +1 -0
- package/build/i18n/it.json +1 -0
- package/build/i18n/ja.json +1 -0
- package/build/i18n/pl.json +1 -0
- package/build/i18n/pt.json +1 -0
- package/build/i18n/ro.json +1 -0
- package/build/i18n/ru.json +1 -0
- package/build/i18n/th.json +1 -0
- package/build/i18n/tr.json +1 -0
- package/build/i18n/zh-CN.json +1 -0
- package/build/i18n/zh-HK.json +1 -0
- package/build/index.esm.js +82 -88
- package/build/index.esm.js.map +1 -1
- package/build/index.js +82 -88
- package/build/index.js.map +1 -1
- package/build/main.css +6 -0
- package/build/styles/drawer/Drawer.css +3 -0
- package/build/styles/main.css +6 -0
- package/build/styles/modal/Modal.css +3 -0
- package/build/types/common/index.d.ts +0 -1
- package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts +2 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.messages.d.ts +8 -0
- package/build/types/phoneNumberInput/PhoneNumberInput.messages.d.ts.map +1 -0
- package/build/types/select/Select.d.ts.map +1 -1
- package/build/types/switch/Switch.d.ts.map +1 -1
- package/build/types/tabs/Tabs.d.ts.map +1 -1
- package/build/types/typeahead/Typeahead.d.ts.map +1 -1
- package/package.json +14 -17
- package/src/button/Button.story.tsx +3 -3
- package/src/common/fakeEvents.js +2 -2
- package/src/common/index.js +0 -1
- package/src/dateInput/DateInput.story.tsx +4 -3
- package/src/dateLookup/DateLookup.js +6 -7
- package/src/dateLookup/DateLookup.keyboardEvents.spec.js +24 -25
- package/src/dateLookup/DateLookup.story.js +4 -3
- package/src/dateLookup/dateTrigger/DateTrigger.spec.js +3 -3
- package/src/drawer/Drawer.css +3 -0
- package/src/drawer/Drawer.less +4 -0
- package/src/i18n/de.json +1 -0
- package/src/i18n/en.json +1 -0
- package/src/i18n/es.json +1 -0
- package/src/i18n/fr.json +1 -0
- package/src/i18n/hu.json +1 -0
- package/src/i18n/id.json +1 -0
- package/src/i18n/it.json +1 -0
- package/src/i18n/ja.json +1 -0
- package/src/i18n/pl.json +1 -0
- package/src/i18n/pt.json +1 -0
- package/src/i18n/ro.json +1 -0
- package/src/i18n/ru.json +1 -0
- package/src/i18n/th.json +1 -0
- package/src/i18n/tr.json +1 -0
- package/src/i18n/zh-CN.json +1 -0
- package/src/i18n/zh-HK.json +1 -0
- package/src/info/Info.story.tsx +3 -3
- package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.js +2 -7
- package/src/inputs/SelectInput.spec.tsx +7 -0
- package/src/inputs/SelectInput.story.tsx +223 -317
- package/src/inputs/SelectInput.tsx +4 -0
- package/src/logo/Logo.js +4 -4
- package/src/main.css +6 -0
- package/src/modal/Modal.css +3 -0
- package/src/modal/Modal.less +4 -0
- package/src/modal/Modal.story.tsx +55 -21
- package/src/moneyInput/MoneyInput.story.tsx +3 -3
- package/src/moneyInput/MoneyInput.tsx +14 -24
- package/src/phoneNumberInput/PhoneNumberInput.messages.ts +8 -0
- package/src/phoneNumberInput/PhoneNumberInput.spec.js +12 -7
- package/src/phoneNumberInput/PhoneNumberInput.tsx +3 -2
- package/src/select/Select.js +8 -9
- package/src/snackbar/Snackbar.story.tsx +3 -3
- package/src/switch/Switch.spec.js +2 -3
- package/src/switch/Switch.tsx +1 -2
- package/src/switchOption/SwitchOption.spec.js +1 -4
- package/src/tabs/Tabs.js +1 -2
- package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.story.tsx +5 -4
- package/src/tile/Tile.js +2 -2
- package/src/tile/Tile.spec.js +5 -5
- package/src/tooltip/Tooltip.story.tsx +3 -3
- package/src/typeahead/Typeahead.js +5 -6
- package/src/typeahead/Typeahead.spec.js +3 -8
- package/src/typeahead/Typeahead.story.js +3 -4
- package/build/types/common/key.d.ts +0 -9
- package/build/types/common/key.d.ts.map +0 -1
- package/build/types/common/keyCodes.d.ts +0 -16
- package/build/types/common/keyCodes.d.ts.map +0 -1
- package/src/common/key.js +0 -8
- package/src/common/keyCodes.js +0 -19
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react';
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { expect, fn, type Mock, screen, userEvent, within } from '@storybook/test';
|
|
2
3
|
import { Calendar, ChevronDown } from '@transferwise/icons';
|
|
3
4
|
import { Flag } from '@wise/art';
|
|
4
5
|
import classNames from 'classnames';
|
|
@@ -7,186 +8,85 @@ import { useState } from 'react';
|
|
|
7
8
|
import { getMonthNames } from '../common/dateUtils';
|
|
8
9
|
import Drawer from '../drawer';
|
|
9
10
|
import Modal from '../modal';
|
|
10
|
-
import { within, userEvent } from '../test-utils';
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
SelectInput,
|
|
14
14
|
type SelectInputItem,
|
|
15
15
|
SelectInputOptionContent,
|
|
16
|
+
type SelectInputProps,
|
|
16
17
|
SelectInputTriggerButton,
|
|
17
18
|
} from './SelectInput';
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
const meta = {
|
|
21
|
+
title: 'components/SelectInput',
|
|
20
22
|
component: SelectInput,
|
|
23
|
+
tags: ['autodocs'],
|
|
24
|
+
parameters: { actions: { argTypesRegex: '' } },
|
|
21
25
|
} satisfies Meta<typeof SelectInput>;
|
|
26
|
+
export default meta;
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
type Story<T, M extends boolean = false> = StoryObj<SelectInputProps<T, M>>;
|
|
29
|
+
|
|
30
|
+
interface Month {
|
|
24
31
|
id: number;
|
|
25
32
|
name: string;
|
|
26
|
-
unavailable: boolean;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
const
|
|
35
|
+
const months: Month[] = getMonthNames('en-US').map((name, index) => ({
|
|
30
36
|
id: index + 1,
|
|
31
37
|
name,
|
|
32
|
-
unavailable: index % 6 === 2,
|
|
33
38
|
}));
|
|
34
39
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
size: 'md' | 'lg';
|
|
49
|
-
onChange: (value: TestMonth | null) => void;
|
|
50
|
-
onClear: () => void;
|
|
51
|
-
}> = {
|
|
52
|
-
render: function Story({
|
|
53
|
-
filterable,
|
|
54
|
-
filterPlaceholder,
|
|
55
|
-
clearable,
|
|
56
|
-
disabled,
|
|
57
|
-
size,
|
|
58
|
-
onChange,
|
|
59
|
-
onClear,
|
|
60
|
-
}) {
|
|
61
|
-
const [selectedMonth, setSelectedMonth] = useState<TestMonth | null>(null);
|
|
40
|
+
export const Months: Story<Month | null> = {
|
|
41
|
+
args: {
|
|
42
|
+
placeholder: 'Month',
|
|
43
|
+
items: months.map((month) => ({
|
|
44
|
+
type: 'option',
|
|
45
|
+
value: month,
|
|
46
|
+
})),
|
|
47
|
+
renderValue: (month) => <SelectInputOptionContent title={month.name} />,
|
|
48
|
+
onChange: fn() satisfies Mock,
|
|
49
|
+
onClear: fn() satisfies Mock,
|
|
50
|
+
},
|
|
51
|
+
render: function Render({ onChange, onClear, ...args }) {
|
|
52
|
+
const [selectedMonth, setSelectedMonth] = useState<Month | null>(null);
|
|
62
53
|
|
|
63
54
|
return (
|
|
64
|
-
<
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{
|
|
77
|
-
type: 'group',
|
|
78
|
-
label: `Quarter #${index + 1}`,
|
|
79
|
-
options: quarterMonths.map((month) => ({
|
|
80
|
-
type: 'option',
|
|
81
|
-
value: month,
|
|
82
|
-
filterMatchers: [month.name],
|
|
83
|
-
disabled: month.unavailable,
|
|
84
|
-
})),
|
|
85
|
-
},
|
|
86
|
-
{ type: 'separator' },
|
|
87
|
-
])
|
|
88
|
-
.slice(0, -1)}
|
|
89
|
-
value={selectedMonth}
|
|
90
|
-
renderValue={(month, withinTrigger) => (
|
|
91
|
-
<SelectInputOptionContent
|
|
92
|
-
title={month.name}
|
|
93
|
-
note="Note"
|
|
94
|
-
description={withinTrigger ? undefined : `Month #${month.id}`}
|
|
95
|
-
icon={<Calendar size={24} />}
|
|
96
|
-
/>
|
|
97
|
-
)}
|
|
98
|
-
filterable={filterable}
|
|
99
|
-
filterPlaceholder={filterPlaceholder}
|
|
100
|
-
size={size}
|
|
101
|
-
disabled={disabled}
|
|
102
|
-
onChange={(month) => {
|
|
103
|
-
setSelectedMonth(month);
|
|
104
|
-
onChange(month);
|
|
105
|
-
}}
|
|
106
|
-
onClear={
|
|
107
|
-
clearable
|
|
108
|
-
? () => {
|
|
109
|
-
setSelectedMonth(null);
|
|
110
|
-
onClear();
|
|
111
|
-
}
|
|
112
|
-
: undefined
|
|
113
|
-
}
|
|
114
|
-
/>
|
|
115
|
-
</div>
|
|
55
|
+
<SelectInput
|
|
56
|
+
{...args}
|
|
57
|
+
value={selectedMonth}
|
|
58
|
+
onChange={(month) => {
|
|
59
|
+
setSelectedMonth(month);
|
|
60
|
+
onChange?.(month);
|
|
61
|
+
}}
|
|
62
|
+
onClear={() => {
|
|
63
|
+
setSelectedMonth(null);
|
|
64
|
+
onClear?.();
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
116
67
|
);
|
|
117
68
|
},
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
filterPlaceholder: 'Type a month’s name',
|
|
121
|
-
clearable: true,
|
|
122
|
-
invalid: false,
|
|
123
|
-
disabled: false,
|
|
124
|
-
size: 'md',
|
|
125
|
-
},
|
|
126
|
-
argTypes: {
|
|
127
|
-
onChange: {
|
|
128
|
-
action: 'changed',
|
|
129
|
-
},
|
|
130
|
-
onClear: {
|
|
131
|
-
action: 'cleared',
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
play: ({ canvasElement }) => {
|
|
135
|
-
const triggerButton = within(canvasElement).getByRole('button');
|
|
136
|
-
userEvent.click(triggerButton);
|
|
137
|
-
},
|
|
138
|
-
};
|
|
69
|
+
play: async ({ canvasElement, step }) => {
|
|
70
|
+
const canvas = within(canvasElement);
|
|
139
71
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
72
|
+
await step('renders placeholder', async () => {
|
|
73
|
+
const triggerButton = canvas.getByRole('button');
|
|
74
|
+
await expect(triggerButton).toHaveTextContent('Month');
|
|
75
|
+
});
|
|
144
76
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
name,
|
|
148
|
-
}));
|
|
77
|
+
await step('selects option via mouse', async () => {
|
|
78
|
+
const triggerButton = canvas.getByRole('button');
|
|
149
79
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
onClear: () => void;
|
|
153
|
-
}> = {
|
|
154
|
-
render: function Story({ onChange, onClear }) {
|
|
155
|
-
const [selectedMonth, setSelectedMonth] = useState<Month | null>(months[0]);
|
|
80
|
+
await userEvent.click(triggerButton);
|
|
81
|
+
await userEvent.unhover(triggerButton);
|
|
156
82
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}))}
|
|
165
|
-
value={selectedMonth}
|
|
166
|
-
renderValue={(month) => <SelectInputOptionContent title={month.name} />}
|
|
167
|
-
onChange={(month) => {
|
|
168
|
-
setSelectedMonth(month);
|
|
169
|
-
onChange(month);
|
|
170
|
-
}}
|
|
171
|
-
onClear={() => {
|
|
172
|
-
setSelectedMonth(null);
|
|
173
|
-
onClear();
|
|
174
|
-
}}
|
|
175
|
-
/>
|
|
176
|
-
</div>
|
|
177
|
-
);
|
|
178
|
-
},
|
|
179
|
-
argTypes: {
|
|
180
|
-
onChange: {
|
|
181
|
-
action: 'changed',
|
|
182
|
-
},
|
|
183
|
-
onClear: {
|
|
184
|
-
action: 'cleared',
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
play: ({ canvasElement }) => {
|
|
188
|
-
const triggerButton = within(canvasElement).getByText('January');
|
|
189
|
-
userEvent.click(triggerButton);
|
|
83
|
+
const option = within(screen.getByRole('listbox')).getByRole('option', {
|
|
84
|
+
name: 'May',
|
|
85
|
+
});
|
|
86
|
+
await userEvent.click(option);
|
|
87
|
+
|
|
88
|
+
await expect(triggerButton).toHaveTextContent('May');
|
|
89
|
+
});
|
|
190
90
|
},
|
|
191
91
|
};
|
|
192
92
|
|
|
@@ -238,180 +138,188 @@ function currencyOption(currency: Currency) {
|
|
|
238
138
|
} satisfies SelectInputItem<Currency>;
|
|
239
139
|
}
|
|
240
140
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
label: 'Popular currencies',
|
|
253
|
-
options: popularCurrencies.map((currency) => currencyOption(currency)),
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
type: 'group',
|
|
257
|
-
label: 'All currencies',
|
|
258
|
-
options: allCurrencies.map((currency) => currencyOption(currency)),
|
|
259
|
-
},
|
|
260
|
-
]}
|
|
261
|
-
value={selectedCurrency}
|
|
262
|
-
renderValue={(currency, withinTrigger) => (
|
|
263
|
-
<SelectInputOptionContent
|
|
264
|
-
title={currency.code}
|
|
265
|
-
note={withinTrigger ? undefined : currency.name}
|
|
266
|
-
icon={<Flag code={currency.code} intrinsicSize={24} />}
|
|
267
|
-
/>
|
|
268
|
-
)}
|
|
269
|
-
renderFooter={({ resultsEmpty, queryNormalized: normalizedQuery }) =>
|
|
270
|
-
resultsEmpty && normalizedQuery != null && /^[a-z]{3}$/u.test(normalizedQuery) ? (
|
|
271
|
-
<>
|
|
272
|
-
It’s not possible use {normalizedQuery.toUpperCase()} yet.{' '}
|
|
273
|
-
<a href="#_" className="np-text-link-default">
|
|
274
|
-
Email me when it’s available.
|
|
275
|
-
</a>
|
|
276
|
-
</>
|
|
277
|
-
) : (
|
|
278
|
-
<>
|
|
279
|
-
Can’t find it?{' '}
|
|
280
|
-
<a href="#_" className="np-text-link-default">
|
|
281
|
-
Request the currency you need,
|
|
282
|
-
</a>{' '}
|
|
283
|
-
and we’ll notify you once it’s available.
|
|
284
|
-
</>
|
|
285
|
-
)
|
|
286
|
-
}
|
|
287
|
-
filterable
|
|
288
|
-
filterPlaceholder="Type a currency / country"
|
|
289
|
-
size="lg"
|
|
290
|
-
onChange={(currency) => {
|
|
291
|
-
setSelectedCurrency(currency);
|
|
292
|
-
onChange(currency);
|
|
293
|
-
}}
|
|
294
|
-
/>
|
|
295
|
-
);
|
|
296
|
-
},
|
|
297
|
-
argTypes: {
|
|
298
|
-
onChange: {
|
|
299
|
-
action: 'changed',
|
|
141
|
+
const CurrenciesArgs = {
|
|
142
|
+
items: [
|
|
143
|
+
{
|
|
144
|
+
type: 'group',
|
|
145
|
+
label: 'Popular currencies',
|
|
146
|
+
options: popularCurrencies.map((currency) => currencyOption(currency)),
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
type: 'group',
|
|
150
|
+
label: 'All currencies',
|
|
151
|
+
options: allCurrencies.map((currency) => currencyOption(currency)),
|
|
300
152
|
},
|
|
153
|
+
],
|
|
154
|
+
defaultValue: popularCurrencies[0],
|
|
155
|
+
renderValue: (currency, withinTrigger) => (
|
|
156
|
+
<SelectInputOptionContent
|
|
157
|
+
title={currency.code}
|
|
158
|
+
note={withinTrigger ? undefined : currency.name}
|
|
159
|
+
icon={<Flag code={currency.code} intrinsicSize={24} />}
|
|
160
|
+
/>
|
|
161
|
+
),
|
|
162
|
+
renderFooter: ({ resultsEmpty, queryNormalized }) =>
|
|
163
|
+
resultsEmpty && queryNormalized != null && /^[a-z]{3}$/u.test(queryNormalized) ? (
|
|
164
|
+
<>
|
|
165
|
+
It’s not possible use {queryNormalized.toUpperCase()} yet.{' '}
|
|
166
|
+
<a href="#_" className="np-text-link-default" onClick={(event) => event.preventDefault()}>
|
|
167
|
+
Email me when it’s available.
|
|
168
|
+
</a>
|
|
169
|
+
</>
|
|
170
|
+
) : (
|
|
171
|
+
<>
|
|
172
|
+
Can’t find it?{' '}
|
|
173
|
+
<a href="#_" className="np-text-link-default" onClick={(event) => event.preventDefault()}>
|
|
174
|
+
Request the currency you need,
|
|
175
|
+
</a>{' '}
|
|
176
|
+
and we’ll notify you once it’s available.
|
|
177
|
+
</>
|
|
178
|
+
),
|
|
179
|
+
filterable: true,
|
|
180
|
+
filterPlaceholder: 'Type a currency / country',
|
|
181
|
+
size: 'lg',
|
|
182
|
+
onChange: fn() satisfies Mock,
|
|
183
|
+
} satisfies Story<Currency>['args'];
|
|
184
|
+
|
|
185
|
+
export const Currencies: Story<Currency> = {
|
|
186
|
+
args: CurrenciesArgs,
|
|
187
|
+
play: async ({ step }) => {
|
|
188
|
+
await step('filters options via keyboard', async () => {
|
|
189
|
+
await userEvent.tab();
|
|
190
|
+
await userEvent.keyboard(' ');
|
|
191
|
+
|
|
192
|
+
await expect(within(screen.getByRole('listbox')).queryAllByRole('option')).toHaveLength(8);
|
|
193
|
+
await expect(screen.getByText(/^Can’t find it?/u)).toBeInTheDocument();
|
|
194
|
+
|
|
195
|
+
const input = screen.getByRole('searchbox');
|
|
196
|
+
|
|
197
|
+
await userEvent.type(input, 'huf');
|
|
198
|
+
await expect(
|
|
199
|
+
within(screen.getByRole('listbox')).queryByRole('option'),
|
|
200
|
+
).not.toBeInTheDocument();
|
|
201
|
+
await expect(screen.getByText(/^It’s not possible use HUF yet./u)).toBeInTheDocument();
|
|
202
|
+
|
|
203
|
+
await userEvent.type(input, '{Backspace}{Backspace}');
|
|
204
|
+
await expect(within(screen.getByRole('listbox')).queryAllByRole('option')).toHaveLength(2);
|
|
205
|
+
|
|
206
|
+
await userEvent.type(input, '{Backspace}eu');
|
|
207
|
+
await expect(input).toHaveAttribute('aria-activedescendant');
|
|
208
|
+
});
|
|
301
209
|
},
|
|
302
210
|
};
|
|
303
211
|
|
|
304
|
-
export const MultipleCurrencies:
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
212
|
+
export const MultipleCurrencies: Story<Currency, true> = {
|
|
213
|
+
args: {
|
|
214
|
+
...CurrenciesArgs,
|
|
215
|
+
multiple: true,
|
|
216
|
+
placeholder: 'Choose currencies…',
|
|
217
|
+
defaultValue: [popularCurrencies[0]],
|
|
218
|
+
renderValue: (currency, withinTrigger) =>
|
|
219
|
+
withinTrigger ? (
|
|
220
|
+
currency.code
|
|
221
|
+
) : (
|
|
222
|
+
<SelectInputOptionContent
|
|
223
|
+
title={currency.code}
|
|
224
|
+
note={currency.name}
|
|
225
|
+
icon={<Flag code={currency.code} intrinsicSize={24} />}
|
|
226
|
+
/>
|
|
227
|
+
),
|
|
228
|
+
},
|
|
229
|
+
play: async ({ canvasElement, step }) => {
|
|
230
|
+
const canvas = within(canvasElement);
|
|
311
231
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
options: allCurrencies.map((currency) => currencyOption(currency)),
|
|
326
|
-
},
|
|
327
|
-
]}
|
|
328
|
-
value={selectedCurrencies}
|
|
329
|
-
renderValue={(currency, withinTrigger) =>
|
|
330
|
-
withinTrigger ? (
|
|
331
|
-
currency.code
|
|
332
|
-
) : (
|
|
333
|
-
<SelectInputOptionContent
|
|
334
|
-
title={currency.code}
|
|
335
|
-
note={currency.name}
|
|
336
|
-
icon={<Flag code={currency.code} intrinsicSize={24} />}
|
|
337
|
-
/>
|
|
338
|
-
)
|
|
339
|
-
}
|
|
340
|
-
// eslint-disable-next-line sonarjs/no-identical-functions
|
|
341
|
-
renderFooter={({ resultsEmpty, queryNormalized: normalizedQuery }) =>
|
|
342
|
-
resultsEmpty && normalizedQuery != null && /^[a-z]{3}$/u.test(normalizedQuery) ? (
|
|
343
|
-
<>
|
|
344
|
-
It’s not possible use {normalizedQuery.toUpperCase()} yet.{' '}
|
|
345
|
-
<a href="#_" className="np-text-link-default">
|
|
346
|
-
Email me when it’s available.
|
|
347
|
-
</a>
|
|
348
|
-
</>
|
|
349
|
-
) : (
|
|
350
|
-
<>
|
|
351
|
-
Can’t find it?{' '}
|
|
352
|
-
<a href="#_" className="np-text-link-default">
|
|
353
|
-
Request the currency you need,
|
|
354
|
-
</a>{' '}
|
|
355
|
-
and we’ll notify you once it’s available.
|
|
356
|
-
</>
|
|
357
|
-
)
|
|
358
|
-
}
|
|
359
|
-
filterable
|
|
360
|
-
filterPlaceholder="Type a currency / country"
|
|
361
|
-
size="lg"
|
|
362
|
-
onChange={(currency) => {
|
|
363
|
-
setSelectedCurrencies(currency);
|
|
364
|
-
onChange(currency);
|
|
365
|
-
}}
|
|
366
|
-
/>
|
|
367
|
-
);
|
|
232
|
+
await step('selects multiple options via mouse', async () => {
|
|
233
|
+
const triggerButton = canvas.getByRole('button');
|
|
234
|
+
|
|
235
|
+
await userEvent.click(triggerButton);
|
|
236
|
+
await userEvent.unhover(triggerButton);
|
|
237
|
+
|
|
238
|
+
const option = within(screen.getByRole('listbox')).getAllByRole('option', {
|
|
239
|
+
name: /^EUR/u,
|
|
240
|
+
})[0];
|
|
241
|
+
await userEvent.click(option);
|
|
242
|
+
|
|
243
|
+
await expect(triggerButton).toHaveTextContent('USD, EUR');
|
|
244
|
+
});
|
|
368
245
|
},
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export const CustomTrigger: Story<Month> = {
|
|
249
|
+
args: {
|
|
250
|
+
placeholder: 'Month',
|
|
251
|
+
items: months.map((month) => ({
|
|
252
|
+
type: 'option',
|
|
253
|
+
value: month,
|
|
254
|
+
})),
|
|
255
|
+
renderValue: (month, withinTrigger) =>
|
|
256
|
+
withinTrigger ? month.name : <SelectInputOptionContent title={month.name} />,
|
|
257
|
+
renderTrigger: ({ content, className }) => (
|
|
258
|
+
<SelectInputTriggerButton
|
|
259
|
+
className={classNames(className, 'btn-unstyled np-text-link-large align-items-center')}
|
|
260
|
+
style={{ display: 'inline-flex', columnGap: '0.25rem' }}
|
|
261
|
+
>
|
|
262
|
+
{content}
|
|
263
|
+
<ChevronDown size={16} />
|
|
264
|
+
</SelectInputTriggerButton>
|
|
265
|
+
),
|
|
266
|
+
onChange: fn() satisfies Mock,
|
|
267
|
+
},
|
|
268
|
+
play: async ({ canvasElement }) => {
|
|
269
|
+
const canvas = within(canvasElement);
|
|
270
|
+
|
|
271
|
+
const triggerButton = canvas.getByRole('button');
|
|
272
|
+
await userEvent.click(triggerButton);
|
|
373
273
|
},
|
|
374
274
|
};
|
|
375
275
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
276
|
+
const quarters = [
|
|
277
|
+
months.slice(0, 3),
|
|
278
|
+
months.slice(3, 6),
|
|
279
|
+
months.slice(6, 9),
|
|
280
|
+
months.slice(9, 12),
|
|
281
|
+
] as const;
|
|
282
|
+
|
|
283
|
+
export const Advanced: Story<Month> = {
|
|
284
|
+
args: {
|
|
285
|
+
placeholder: 'Month',
|
|
286
|
+
items: quarters
|
|
287
|
+
.flatMap<SelectInputItem<Month>>((quarterMonths, quarterIndex) => [
|
|
288
|
+
{
|
|
289
|
+
type: 'group',
|
|
290
|
+
label: `Quarter #${quarterIndex + 1}`,
|
|
291
|
+
options: quarterMonths.map((month, monthIndex) => ({
|
|
383
292
|
type: 'option',
|
|
384
293
|
value: month,
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
);
|
|
294
|
+
filterMatchers: [month.name],
|
|
295
|
+
disabled: monthIndex % 6 === 2,
|
|
296
|
+
})),
|
|
297
|
+
},
|
|
298
|
+
{ type: 'separator' },
|
|
299
|
+
])
|
|
300
|
+
.slice(0, -1),
|
|
301
|
+
renderValue: (month, withinTrigger) => (
|
|
302
|
+
<SelectInputOptionContent
|
|
303
|
+
title={month.name}
|
|
304
|
+
note="Note"
|
|
305
|
+
description={withinTrigger ? undefined : `Month #${month.id}`}
|
|
306
|
+
icon={<Calendar size={24} />}
|
|
307
|
+
/>
|
|
308
|
+
),
|
|
309
|
+
filterable: true,
|
|
310
|
+
filterPlaceholder: 'Type a month’s name',
|
|
311
|
+
onChange: fn() satisfies Mock,
|
|
404
312
|
},
|
|
405
|
-
play: ({ canvasElement }) => {
|
|
406
|
-
const
|
|
407
|
-
|
|
313
|
+
play: async ({ canvasElement }) => {
|
|
314
|
+
const canvas = within(canvasElement);
|
|
315
|
+
|
|
316
|
+
const triggerButton = canvas.getByRole('button');
|
|
317
|
+
await userEvent.click(triggerButton);
|
|
408
318
|
},
|
|
409
319
|
};
|
|
410
320
|
|
|
411
|
-
export const WithinDrawer:
|
|
412
|
-
|
|
413
|
-
}> = {
|
|
414
|
-
...Currencies,
|
|
321
|
+
export const WithinDrawer: Story<Currency> = {
|
|
322
|
+
args: CurrenciesArgs,
|
|
415
323
|
decorators: [
|
|
416
324
|
(Story) => (
|
|
417
325
|
<Drawer open headerTitle="This is the title of the drawer">
|
|
@@ -421,9 +329,7 @@ export const WithinDrawer: StoryObj<{
|
|
|
421
329
|
],
|
|
422
330
|
};
|
|
423
331
|
|
|
424
|
-
export const WithinModal:
|
|
425
|
-
|
|
426
|
-
}> = {
|
|
427
|
-
...Currencies,
|
|
332
|
+
export const WithinModal: Story<Currency> = {
|
|
333
|
+
args: CurrenciesArgs,
|
|
428
334
|
decorators: [(Story) => <Modal open body={<Story />} onClose={() => {}} />],
|
|
429
335
|
};
|
|
@@ -41,6 +41,7 @@ function inferSearchableStrings(value: unknown) {
|
|
|
41
41
|
|
|
42
42
|
const SelectInputTriggerButtonPropsContext = createContext<{
|
|
43
43
|
ref?: React.ForwardedRef<HTMLButtonElement>;
|
|
44
|
+
id?: string;
|
|
44
45
|
onClick?: (event: React.MouseEvent) => void;
|
|
45
46
|
onKeyDown?: (event: React.KeyboardEvent) => void;
|
|
46
47
|
[key: string]: unknown;
|
|
@@ -125,6 +126,7 @@ function filterSelectInputItems<T>(items: readonly SelectInputItem<T>[], needle:
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
export interface SelectInputProps<T = string, M extends boolean = false> {
|
|
129
|
+
id?: string;
|
|
128
130
|
name?: string;
|
|
129
131
|
multiple?: M;
|
|
130
132
|
placeholder?: string;
|
|
@@ -218,6 +220,7 @@ function SelectInputClearButton({ className, onClick }: SelectInputClearButtonPr
|
|
|
218
220
|
const noop = () => {};
|
|
219
221
|
|
|
220
222
|
export function SelectInput<T = string, M extends boolean = false>({
|
|
223
|
+
id,
|
|
221
224
|
name,
|
|
222
225
|
multiple,
|
|
223
226
|
placeholder,
|
|
@@ -288,6 +291,7 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
288
291
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
289
292
|
value={{
|
|
290
293
|
ref: mergeRefs([ref, triggerRef]),
|
|
294
|
+
id,
|
|
291
295
|
...mergeProps(
|
|
292
296
|
{
|
|
293
297
|
onClick: () => {
|
package/src/logo/Logo.js
CHANGED
|
@@ -2,10 +2,10 @@ import classNames from 'classnames';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
|
|
4
4
|
import { LogoType } from './logoTypes';
|
|
5
|
-
import { LogoFlagInverse } from './svg/flag-inverse.svg';
|
|
6
|
-
import { LogoFlag } from './svg/flag.svg';
|
|
7
|
-
import { LogoWiseInverse } from './svg/logo-inverse.svg';
|
|
8
|
-
import { LogoWise } from './svg/logo.svg';
|
|
5
|
+
import { ReactComponent as LogoFlagInverse } from './svg/flag-inverse.svg';
|
|
6
|
+
import { ReactComponent as LogoFlag } from './svg/flag.svg';
|
|
7
|
+
import { ReactComponent as LogoWiseInverse } from './svg/logo-inverse.svg';
|
|
8
|
+
import { ReactComponent as LogoWise } from './svg/logo.svg';
|
|
9
9
|
|
|
10
10
|
const svgPaths = {
|
|
11
11
|
WISE: LogoWise,
|
package/src/main.css
CHANGED
|
@@ -1884,6 +1884,9 @@ button.np-option {
|
|
|
1884
1884
|
overflow-y: auto;
|
|
1885
1885
|
flex: 1;
|
|
1886
1886
|
}
|
|
1887
|
+
.np-drawer .np-drawer-content .np-theme-personal {
|
|
1888
|
+
background-color: transparent;
|
|
1889
|
+
}
|
|
1887
1890
|
.np-drawer .np-drawer-footer,
|
|
1888
1891
|
.np-drawer .np-drawer-content {
|
|
1889
1892
|
padding: 16px;
|
|
@@ -3197,6 +3200,9 @@ a {
|
|
|
3197
3200
|
min-height: var(--size-32);
|
|
3198
3201
|
padding-bottom: 4px !important;
|
|
3199
3202
|
}
|
|
3203
|
+
.tw-modal .tw-modal-content .np-theme-personal {
|
|
3204
|
+
background-color: transparent;
|
|
3205
|
+
}
|
|
3200
3206
|
.tw-modal table,
|
|
3201
3207
|
.tw-modal .table {
|
|
3202
3208
|
background-color: transparent;
|
package/src/modal/Modal.css
CHANGED