@transferwise/components 46.162.0 → 46.162.2

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 (90) hide show
  1. package/build/Calendar/DateHeader/DateHeader.js +2 -6
  2. package/build/Calendar/DateHeader/DateHeader.js.map +1 -1
  3. package/build/Calendar/DateHeader/DateHeader.mjs +3 -7
  4. package/build/Calendar/DateHeader/DateHeader.mjs.map +1 -1
  5. package/build/Carousel/Carousel.js +2 -2
  6. package/build/Carousel/Carousel.js.map +1 -1
  7. package/build/Carousel/Carousel.mjs +3 -3
  8. package/build/Carousel/Carousel.mjs.map +1 -1
  9. package/build/Inputs/SelectInput/OptionContent/SelectInputOptionContent.js +4 -3
  10. package/build/Inputs/SelectInput/OptionContent/SelectInputOptionContent.js.map +1 -1
  11. package/build/Inputs/SelectInput/OptionContent/SelectInputOptionContent.mjs +4 -3
  12. package/build/Inputs/SelectInput/OptionContent/SelectInputOptionContent.mjs.map +1 -1
  13. package/build/ListItem/Navigation/ListItemNavigation.js +1 -1
  14. package/build/ListItem/Navigation/ListItemNavigation.js.map +1 -1
  15. package/build/ListItem/Navigation/ListItemNavigation.mjs +2 -2
  16. package/build/ListItem/Navigation/ListItemNavigation.mjs.map +1 -1
  17. package/build/PhoneNumberInput/PhoneNumberInput.js +2 -1
  18. package/build/PhoneNumberInput/PhoneNumberInput.js.map +1 -1
  19. package/build/PhoneNumberInput/PhoneNumberInput.mjs +2 -1
  20. package/build/PhoneNumberInput/PhoneNumberInput.mjs.map +1 -1
  21. package/build/PromoCard/Indicator/PromoCardIndicator.js +1 -1
  22. package/build/PromoCard/Indicator/PromoCardIndicator.js.map +1 -1
  23. package/build/PromoCard/Indicator/PromoCardIndicator.mjs +2 -2
  24. package/build/PromoCard/Indicator/PromoCardIndicator.mjs.map +1 -1
  25. package/build/Provider/Provider.js +6 -10
  26. package/build/Provider/Provider.js.map +1 -1
  27. package/build/Provider/Provider.mjs +6 -10
  28. package/build/Provider/Provider.mjs.map +1 -1
  29. package/build/index.js +0 -2
  30. package/build/index.js.map +1 -1
  31. package/build/index.mjs +0 -1
  32. package/build/index.mjs.map +1 -1
  33. package/build/main.css +17 -7
  34. package/build/styles/Button/Button.css +0 -3
  35. package/build/styles/DateInput/DateInput.css +13 -0
  36. package/build/styles/ListItem/ListItem.css +1 -1
  37. package/build/styles/PhoneNumberInput/PhoneNumberInput.css +3 -0
  38. package/build/styles/PromoCard/PromoCard.css +0 -3
  39. package/build/styles/main.css +17 -7
  40. package/build/types/Inputs/SelectInput/OptionContent/SelectInputOptionContent.d.ts +2 -1
  41. package/build/types/Inputs/SelectInput/OptionContent/SelectInputOptionContent.d.ts.map +1 -1
  42. package/build/types/PhoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  43. package/build/types/Provider/Provider.d.ts.map +1 -1
  44. package/build/types/Provider/index.d.ts +0 -2
  45. package/build/types/Provider/index.d.ts.map +1 -1
  46. package/build/types/index.d.ts +2 -2
  47. package/build/types/index.d.ts.map +1 -1
  48. package/package.json +2 -2
  49. package/src/Button/Button.css +0 -3
  50. package/src/Button/Button.less +0 -16
  51. package/src/Button/_stories/Button.test.story.tsx +12 -12
  52. package/src/Calendar/DateHeader/DateHeader.tsx +3 -3
  53. package/src/Carousel/Carousel.tsx +3 -3
  54. package/src/DateInput/DateInput.css +13 -0
  55. package/src/DateInput/DateInput.less +10 -2
  56. package/src/DateInput/_stories/DateInput.rtl.test.story.tsx +36 -0
  57. package/src/DateInput/_stories/DateInput.test.story.tsx +0 -13
  58. package/src/ExpressiveMoneyInput/_stories/ExpressiveMoneyInput.rtl.test.story.tsx +1 -1
  59. package/src/InputWithDisplayFormat/_stories/InputWithDisplayFormat.test.story.tsx +52 -0
  60. package/src/Inputs/SelectInput/OptionContent/SelectInputOptionContent.tsx +4 -1
  61. package/src/Inputs/SelectInput/SelectInput.test.tsx +74 -0
  62. package/src/ListItem/ListItem.css +1 -1
  63. package/src/ListItem/ListItem.grid.less +4 -4
  64. package/src/ListItem/ListItem.less +1 -1
  65. package/src/ListItem/Navigation/ListItemNavigation.tsx +2 -2
  66. package/src/PhoneNumberInput/PhoneNumberInput.css +3 -0
  67. package/src/PhoneNumberInput/PhoneNumberInput.less +10 -2
  68. package/src/PhoneNumberInput/PhoneNumberInput.tsx +1 -0
  69. package/src/PhoneNumberInput/_stories/PhoneNumberInput.rtl.test.story.tsx +1 -1
  70. package/src/PromoCard/Indicator/PromoCardIndicator.tsx +2 -2
  71. package/src/PromoCard/PromoCard.css +0 -3
  72. package/src/PromoCard/PromoCard.less +0 -5
  73. package/src/Prompt/CriticalBanner/_stories/CriticalBanner.test.story.tsx +1 -1
  74. package/src/Provider/Provider.tsx +8 -11
  75. package/src/Provider/index.ts +0 -2
  76. package/src/i18n/en.json +1 -0
  77. package/src/index.ts +2 -2
  78. package/src/main.css +17 -7
  79. package/build/Provider/Language/LanguageProvider.js +0 -20
  80. package/build/Provider/Language/LanguageProvider.js.map +0 -1
  81. package/build/Provider/Language/LanguageProvider.mjs +0 -17
  82. package/build/Provider/Language/LanguageProvider.mjs.map +0 -1
  83. package/build/types/Provider/Language/LanguageProvider.d.ts +0 -7
  84. package/build/types/Provider/Language/LanguageProvider.d.ts.map +0 -1
  85. package/build/types/Provider/Language/index.d.ts +0 -3
  86. package/build/types/Provider/Language/index.d.ts.map +0 -1
  87. package/src/Icons/_stories/Icons.story.tsx +0 -389
  88. package/src/Provider/Language/LanguageProvider.test.tsx +0 -22
  89. package/src/Provider/Language/LanguageProvider.tsx +0 -11
  90. package/src/Provider/Language/index.ts +0 -2
@@ -1,389 +0,0 @@
1
- import React, { useState, useCallback, memo, useRef } from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react-webpack5';
3
- import * as AllIcons from '@transferwise/icons';
4
- import iconsPkg from '@transferwise/icons/package.json';
5
- import { ThemeProvider } from '@wise/components-theming';
6
-
7
- import Chips, { type ChipValue } from '../../Chips/Chips';
8
- import { SearchInput } from '../../Inputs/SearchInput/SearchInput';
9
- import SnackbarProvider from '../../Snackbar/SnackbarProvider';
10
- import useSnackbar from '../../Snackbar/useSnackbar';
11
-
12
- const ICONS_VERSION: string = iconsPkg.version;
13
-
14
- type IconComponent = React.FunctionComponent<{
15
- size?: '16' | '24' | '32' | 16 | 24 | 32;
16
- className?: string;
17
- title?: string;
18
- }>;
19
-
20
- const OLD_ICON_NAMES_MAP: Record<string, string> = {
21
- Alert: 'Warning',
22
- Ach: 'BankTransfer',
23
- OfficeExpenses: 'Stationery',
24
- Chat: 'SpeechBubble',
25
- Holidays: 'Beach',
26
- Cs: 'Headset',
27
- Family: 'Heart',
28
- Settings: 'Cog',
29
- Lightning: 'LightningBolt',
30
- Atm: 'InsertCard',
31
- SalesAndRoyalties: 'CashRegister',
32
- Tax: 'PercentageCircle',
33
- Recipients: 'People',
34
- Marketing: 'Target',
35
- DriversLicense: 'Car',
36
- PinCode: 'Dial',
37
- Rent: 'Building',
38
- Unlock: 'PadlockUnlocked',
39
- Lock: 'Padlock',
40
- CardNumber: 'CardDetail',
41
- Invite: 'GiftBox',
42
- Dont: 'SadEmoji',
43
- CardTransferwise: 'CardWise',
44
- ChipPin: 'Chip',
45
- Profile: 'Person',
46
- Home: 'House',
47
- PendingCircle: 'Clock',
48
- Activity: 'List',
49
- ExchangeRate: 'UpwardGraph',
50
- ContractServices: 'Handshake',
51
- Travel: 'Suitcase',
52
- TwoStep: 'MobileLock',
53
- EmailAndPhone: 'EmailAndMobile',
54
- Insights: 'Bulb',
55
- Salary: 'PayIn',
56
- Picture: 'Image',
57
- ECommerce: 'ShoppingBag',
58
- Feedback: 'SpeechBubbleMessage',
59
- Refresh: 'Reload',
60
- CostOfGoodsSold: 'Boxes',
61
- Expenses: 'PieChart',
62
- Pending: 'SpeechBubblePending',
63
- Help: 'QuestionMark',
64
- HelpCircle: 'QuestionMarkCircle',
65
- CalendarSuccess: 'CalendarCheck',
66
- Comments: 'SpeechBubbles',
67
- OwnersWithdrawal: 'Withdrawal',
68
- Do: 'HappyEmoji',
69
- Emoji: 'HappyEmoji',
70
- Balance: 'BarChart',
71
- Investments: 'BarChart',
72
- Verified: 'Check',
73
- FacebookSquare: 'Facebook',
74
- SoftwareAndWebHosting: 'SoftwareAndHosting',
75
- };
76
-
77
- const CANONICAL_TO_ALIASES: Record<string, string[]> = {};
78
- for (const [alias, canonical] of Object.entries(OLD_ICON_NAMES_MAP)) {
79
- if (!CANONICAL_TO_ALIASES[canonical]) {
80
- CANONICAL_TO_ALIASES[canonical] = [];
81
- }
82
- CANONICAL_TO_ALIASES[canonical].push(alias);
83
- }
84
-
85
- type IconEntry = {
86
- name: string;
87
- component: IconComponent;
88
- aliases: string[];
89
- searchKey: string;
90
- };
91
-
92
- const iconEntries: IconEntry[] = Object.entries(AllIcons as Record<string, IconComponent>)
93
- .filter(([name]) => !OLD_ICON_NAMES_MAP[name])
94
- .map(([name, component]) => {
95
- const aliases = CANONICAL_TO_ALIASES[name] ?? [];
96
- return {
97
- name,
98
- component,
99
- aliases,
100
- searchKey: [name, ...aliases].join(' ').toLowerCase(),
101
- };
102
- })
103
- .sort((a, b) => a.name.localeCompare(b.name));
104
-
105
- const sizeChips = [
106
- { value: 16, label: '16' },
107
- { value: 24, label: '24' },
108
- { value: 32, label: '32' },
109
- ];
110
-
111
- const themeChips = [
112
- { value: 'personal', label: 'Personal' },
113
- { value: 'personal-dark', label: 'Dark' },
114
- { value: 'bright-green', label: 'Bright Green' },
115
- { value: 'forest-green', label: 'Forest Green' },
116
- ];
117
-
118
- type ThemeSelection = {
119
- theme: 'personal' | 'bright-green' | 'forest-green';
120
- screenMode: 'light' | 'dark';
121
- };
122
-
123
- function resolveTheme(value: string): ThemeSelection {
124
- if (value === 'personal-dark') return { theme: 'personal', screenMode: 'dark' };
125
- return { theme: value as ThemeSelection['theme'], screenMode: 'light' };
126
- }
127
-
128
- const IconCell = memo(function IconCell({
129
- name,
130
- component: Icon,
131
- aliases,
132
- iconSize,
133
- onCopy,
134
- }: {
135
- name: string;
136
- component: IconComponent;
137
- aliases: string[];
138
- iconSize: 16 | 24 | 32;
139
- onCopy: (name: string) => void;
140
- }) {
141
- const [hovered, setHovered] = useState(false);
142
-
143
- return (
144
- <div
145
- style={{
146
- display: 'flex',
147
- flexDirection: 'column',
148
- alignItems: 'center',
149
- gap: '4px',
150
- padding: '12px 4px',
151
- borderRadius: '8px',
152
- cursor: 'pointer',
153
- flex: 1,
154
- background: hovered ? 'var(--color-background-neutral)' : 'transparent',
155
- transition: 'background 150ms ease',
156
- }}
157
- role="button"
158
- tabIndex={0}
159
- aria-label={`Copy import for ${name}`}
160
- onClick={() => onCopy(name)}
161
- onMouseEnter={() => setHovered(true)}
162
- onMouseLeave={() => setHovered(false)}
163
- onKeyDown={(e) => {
164
- if (e.key === 'Enter' || e.key === ' ') {
165
- e.preventDefault();
166
- onCopy(name);
167
- }
168
- }}
169
- >
170
- <div style={{ padding: '8px' }}>
171
- <Icon size={iconSize} />
172
- </div>
173
- <span
174
- style={{
175
- textAlign: 'center',
176
- wordBreak: 'break-word',
177
- fontSize: '12px',
178
- lineHeight: '1.3',
179
- }}
180
- >
181
- {name}
182
- </span>
183
- {aliases.length > 0 && (
184
- <span
185
- style={{
186
- textAlign: 'center',
187
- wordBreak: 'break-word',
188
- fontSize: '11px',
189
- lineHeight: '1.3',
190
- color: 'var(--color-content-tertiary)',
191
- }}
192
- >
193
- alias: {aliases.join(', ')}
194
- </span>
195
- )}
196
- </div>
197
- );
198
- });
199
-
200
- function IconGallery() {
201
- const [size, setSize] = useState<ChipValue>(32);
202
- const [theme, setTheme] = useState<ChipValue>('personal');
203
- const resolved = resolveTheme(String(theme));
204
-
205
- return (
206
- <SnackbarProvider timeout={2000}>
207
- <div style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
208
- <Toolbar size={size} theme={theme} onSizeChange={setSize} onThemeChange={setTheme} />
209
- <ThemeProvider theme={resolved.theme} screenMode={resolved.screenMode}>
210
- <IconGrid size={size} screenMode={resolved.screenMode} />
211
- </ThemeProvider>
212
- </div>
213
- </SnackbarProvider>
214
- );
215
- }
216
-
217
- function Toolbar({
218
- size,
219
- onSizeChange,
220
- theme,
221
- onThemeChange,
222
- }: {
223
- size: ChipValue;
224
- onSizeChange: (v: ChipValue) => void;
225
- theme: ChipValue;
226
- onThemeChange: (v: ChipValue) => void;
227
- }) {
228
- return (
229
- <div
230
- style={{
231
- display: 'flex',
232
- flexWrap: 'wrap',
233
- alignItems: 'center',
234
- gap: '12px',
235
- padding: '12px 24px',
236
- borderBottom: '1px solid var(--color-border-neutral)',
237
- background: 'var(--color-background-elevated)',
238
- flexShrink: 0,
239
- }}
240
- >
241
- <div style={{ display: 'flex', alignItems: 'center', gap: '12px', paddingRight: '12px' }}>
242
- <span style={{ fontSize: '13px', fontWeight: 500, whiteSpace: 'nowrap' }}>Size</span>
243
- <Chips
244
- chips={sizeChips}
245
- selected={size}
246
- aria-label="Icon size"
247
- onChange={({ selectedValue }) => onSizeChange(selectedValue)}
248
- />
249
- </div>
250
- <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
251
- <span style={{ fontSize: '13px', fontWeight: 500, whiteSpace: 'nowrap' }}>Theme</span>
252
- <Chips
253
- chips={themeChips}
254
- selected={theme}
255
- aria-label="Theme"
256
- onChange={({ selectedValue }) => onThemeChange(selectedValue)}
257
- />
258
- </div>
259
- </div>
260
- );
261
- }
262
-
263
- function IconGrid({ size, screenMode }: { size: ChipValue; screenMode: 'light' | 'dark' }) {
264
- const [search, setSearch] = useState('');
265
- const gridRef = useRef<HTMLDivElement>(null);
266
- const countRef = useRef<HTMLSpanElement>(null);
267
- const createSnackbar = useSnackbar();
268
-
269
- const iconSize = Number(size) as 16 | 24 | 32;
270
-
271
- const handleCopy = useCallback(
272
- async (name: string) => {
273
- try {
274
- await navigator.clipboard.writeText(`<${name} />`);
275
- createSnackbar({
276
- text: `Copied`,
277
- theme: screenMode,
278
- });
279
- } catch (error) {
280
- console.error('Failed to copy icon import to clipboard', error);
281
- createSnackbar({
282
- text: `Failed to copy`,
283
- theme: screenMode,
284
- });
285
- }
286
- },
287
- [createSnackbar, screenMode],
288
- );
289
-
290
- const applyFilter = useCallback((query: string) => {
291
- const grid = gridRef.current;
292
- if (!grid) return;
293
- const q = query.toLowerCase();
294
- let visible = 0;
295
- const children = grid.children as HTMLCollectionOf<HTMLElement>;
296
- for (let i = 0; i < children.length; i += 1) {
297
- const el = children[i];
298
- const match = !q || (el.dataset.search?.includes(q) ?? false);
299
- el.style.display = match ? '' : 'none';
300
- if (match) visible += 1;
301
- }
302
- if (countRef.current) {
303
- countRef.current.textContent = `${visible} icon${visible !== 1 ? 's' : ''}`;
304
- }
305
- }, []);
306
-
307
- const handleSearchChange = useCallback(
308
- (e: React.ChangeEvent<HTMLInputElement>) => {
309
- const val = e.target.value;
310
- setSearch(val);
311
- applyFilter(val);
312
- },
313
- [applyFilter],
314
- );
315
-
316
- return (
317
- <div
318
- style={{
319
- display: 'flex',
320
- flexDirection: 'column',
321
- gap: '16px',
322
- padding: '24px',
323
- background: 'var(--color-background-screen)',
324
- color: 'var(--color-content-primary)',
325
- flex: 1,
326
- }}
327
- >
328
- <div style={{ display: 'flex', alignItems: 'center', gap: '16px', flexWrap: 'wrap' }}>
329
- <div style={{ maxWidth: '320px', flex: 1 }}>
330
- <SearchInput
331
- placeholder="Search icons..."
332
- value={search}
333
- aria-label="Search icons"
334
- onChange={handleSearchChange}
335
- />
336
- </div>
337
- <span ref={countRef} style={{ fontSize: '13px', color: 'var(--color-content-secondary)' }}>
338
- {iconEntries.length} icons
339
- </span>
340
- <code>@transferwise/icons@{ICONS_VERSION}</code>
341
- </div>
342
-
343
- <div style={{ fontSize: '11px', color: 'var(--color-content-tertiary)', lineHeight: '1.8' }}>
344
- <div>
345
- Icons package must be imported first:{' '}
346
- <code>{`import { Bank } from '@transferwise/icons'`}</code>
347
- </div>
348
- </div>
349
-
350
- <div
351
- ref={gridRef}
352
- style={{
353
- display: 'grid',
354
- gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',
355
- gap: '12px',
356
- gridAutoRows: '1fr',
357
- }}
358
- >
359
- {iconEntries.map(({ name, component, aliases, searchKey }) => (
360
- <div key={name} data-search={searchKey} style={{ display: 'flex' }}>
361
- <IconCell
362
- name={name}
363
- component={component}
364
- aliases={aliases}
365
- iconSize={iconSize}
366
- onCopy={handleCopy}
367
- />
368
- </div>
369
- ))}
370
- </div>
371
- </div>
372
- );
373
- }
374
-
375
- const meta: Meta = {
376
- title: 'Foundations/Icons',
377
- tags: ['!autodocs', '!manifest'],
378
- parameters: {
379
- padding: '0',
380
- },
381
- };
382
-
383
- export default meta;
384
-
385
- type Story = StoryObj;
386
-
387
- export const Gallery: Story = {
388
- render: () => <IconGallery />,
389
- };
@@ -1,22 +0,0 @@
1
- import { render } from '../../test-utils';
2
-
3
- import { LanguageProvider } from '.';
4
-
5
- describe('LanguageProvider', () => {
6
- beforeEach(() => {
7
- document.documentElement.removeAttribute('lang');
8
- });
9
-
10
- it.each([['en'], ['ru'], ['ja']])('store language %s in React Context', (locale: string) => {
11
- const TestComponent = () => {
12
- return <>locale: {locale}</>;
13
- };
14
- const { container } = render(
15
- <LanguageProvider locale={locale}>
16
- <TestComponent />
17
- </LanguageProvider>,
18
- );
19
-
20
- expect(container).toHaveTextContent(`locale: ${locale}`);
21
- });
22
- });
@@ -1,11 +0,0 @@
1
- import { createContext, PropsWithChildren } from 'react';
2
-
3
- import { DEFAULT_LOCALE } from '../../common/Locale';
4
-
5
- export const LanguageContext = createContext<string>(DEFAULT_LOCALE);
6
-
7
- export type LanguageProviderProps = PropsWithChildren<{ locale: string }>;
8
-
9
- export const LanguageProvider = ({ locale, children }: LanguageProviderProps) => {
10
- return <LanguageContext.Provider value={locale}>{children}</LanguageContext.Provider>;
11
- };
@@ -1,2 +0,0 @@
1
- export { LanguageProvider } from './LanguageProvider';
2
- export type { LanguageProviderProps } from './LanguageProvider';