@transferwise/components 46.81.0 → 46.82.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.
Files changed (93) hide show
  1. package/build/alert/Alert.js +2 -9
  2. package/build/alert/Alert.js.map +1 -1
  3. package/build/alert/Alert.mjs +2 -9
  4. package/build/alert/Alert.mjs.map +1 -1
  5. package/build/i18n/en.json +5 -0
  6. package/build/i18n/en.json.js +5 -0
  7. package/build/i18n/en.json.js.map +1 -1
  8. package/build/i18n/en.json.mjs +5 -0
  9. package/build/i18n/en.json.mjs.map +1 -1
  10. package/build/logo/Logo.js +11 -131
  11. package/build/logo/Logo.js.map +1 -1
  12. package/build/logo/Logo.mjs +1 -121
  13. package/build/logo/Logo.mjs.map +1 -1
  14. package/build/logo/logo-assets.js +134 -0
  15. package/build/logo/logo-assets.js.map +1 -0
  16. package/build/logo/logo-assets.mjs +125 -0
  17. package/build/logo/logo-assets.mjs.map +1 -0
  18. package/build/main.css +274 -0
  19. package/build/money/Money.js +5 -2
  20. package/build/money/Money.js.map +1 -1
  21. package/build/money/Money.mjs +5 -2
  22. package/build/money/Money.mjs.map +1 -1
  23. package/build/styles/main.css +274 -0
  24. package/build/styles/table/Table.css +274 -0
  25. package/build/types/alert/Alert.d.ts +1 -5
  26. package/build/types/alert/Alert.d.ts.map +1 -1
  27. package/build/types/logo/Logo.d.ts.map +1 -1
  28. package/build/types/logo/logo-assets.d.ts +10 -0
  29. package/build/types/logo/logo-assets.d.ts.map +1 -0
  30. package/build/types/money/Money.d.ts +2 -1
  31. package/build/types/money/Money.d.ts.map +1 -1
  32. package/build/types/table/Table.d.ts +23 -0
  33. package/build/types/table/Table.d.ts.map +1 -0
  34. package/build/types/table/Table.messages.d.ts +24 -0
  35. package/build/types/table/Table.messages.d.ts.map +1 -0
  36. package/build/types/table/TableCell.d.ts +40 -0
  37. package/build/types/table/TableCell.d.ts.map +1 -0
  38. package/build/types/table/TableHeader.d.ts +13 -0
  39. package/build/types/table/TableHeader.d.ts.map +1 -0
  40. package/build/types/table/TableRow.d.ts +17 -0
  41. package/build/types/table/TableRow.d.ts.map +1 -0
  42. package/build/types/table/TableStatusText.d.ts +10 -0
  43. package/build/types/table/TableStatusText.d.ts.map +1 -0
  44. package/build/types/table/index.d.ts +6 -0
  45. package/build/types/table/index.d.ts.map +1 -0
  46. package/build/types/test-utils/index.d.ts +10 -0
  47. package/build/types/test-utils/index.d.ts.map +1 -1
  48. package/package.json +3 -4
  49. package/src/alert/Alert.spec.story.tsx +0 -82
  50. package/src/alert/Alert.spec.tsx +0 -30
  51. package/src/alert/Alert.tsx +51 -67
  52. package/src/i18n/en.json +5 -0
  53. package/src/logo/Logo.tsx +10 -8
  54. package/src/logo/__snapshots__/Logo.spec.tsx.snap +16 -16
  55. package/src/logo/logo-assets.tsx +137 -0
  56. package/src/main.css +274 -0
  57. package/src/main.less +1 -0
  58. package/src/money/Money.tsx +9 -2
  59. package/src/table/Table.css +274 -0
  60. package/src/table/Table.less +334 -0
  61. package/src/table/Table.messages.ts +24 -0
  62. package/src/table/Table.spec.tsx +82 -0
  63. package/src/table/Table.story.tsx +356 -0
  64. package/src/table/Table.tsx +167 -0
  65. package/src/table/TableCell.spec.tsx +298 -0
  66. package/src/table/TableCell.tsx +149 -0
  67. package/src/table/TableHeader.spec.tsx +50 -0
  68. package/src/table/TableHeader.tsx +74 -0
  69. package/src/table/TableRow.spec.tsx +112 -0
  70. package/src/table/TableRow.tsx +70 -0
  71. package/src/table/TableStatusText.spec.tsx +53 -0
  72. package/src/table/TableStatusText.tsx +40 -0
  73. package/src/table/index.ts +11 -0
  74. package/build/logo/svg/flag-inverse.svg +0 -1
  75. package/build/logo/svg/flag-platform-white.svg +0 -1
  76. package/build/logo/svg/flag-platform.svg +0 -1
  77. package/build/logo/svg/flag.svg +0 -1
  78. package/build/logo/svg/logo-business-inverse.svg +0 -1
  79. package/build/logo/svg/logo-business.svg +0 -1
  80. package/build/logo/svg/logo-inverse.svg +0 -1
  81. package/build/logo/svg/logo-platform-white.svg +0 -1
  82. package/build/logo/svg/logo-platform.svg +0 -1
  83. package/build/logo/svg/logo.svg +0 -1
  84. package/src/logo/svg/flag-inverse.svg +0 -1
  85. package/src/logo/svg/flag-platform-white.svg +0 -1
  86. package/src/logo/svg/flag-platform.svg +0 -1
  87. package/src/logo/svg/flag.svg +0 -1
  88. package/src/logo/svg/logo-business-inverse.svg +0 -1
  89. package/src/logo/svg/logo-business.svg +0 -1
  90. package/src/logo/svg/logo-inverse.svg +0 -1
  91. package/src/logo/svg/logo-platform-white.svg +0 -1
  92. package/src/logo/svg/logo-platform.svg +0 -1
  93. package/src/logo/svg/logo.svg +0 -1
@@ -0,0 +1,356 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import Table from './Table';
3
+ import { TableHeaderType } from './TableHeader';
4
+ import { TableRowType, TableRowClickableType } from './TableRow';
5
+
6
+ export default {
7
+ component: Table,
8
+ title: 'Option/Table',
9
+ tags: ['autodocs'],
10
+ } satisfies Meta<typeof Table>;
11
+
12
+ type Story = StoryObj<typeof Table>;
13
+
14
+ const tableData = {
15
+ headers: [
16
+ {
17
+ header: 'Employee',
18
+ width: '230px',
19
+ },
20
+ {
21
+ header: 'Location',
22
+ },
23
+ {
24
+ header: 'Emplpyment Date',
25
+ className: 'np-table-header--custom-class',
26
+ },
27
+ {
28
+ header: 'Payment',
29
+ alignment: 'right',
30
+ },
31
+ {
32
+ header: 'Status',
33
+ status: 'error',
34
+ },
35
+ ] satisfies TableHeaderType[],
36
+ rows: [
37
+ {
38
+ id: 0,
39
+ cells: [
40
+ {
41
+ cell: {
42
+ type: 'leading',
43
+ primaryText: 'Bob Brown',
44
+ secondaryText: 'Software Engineer',
45
+ avatar: {
46
+ profileName: 'Bob Brown',
47
+ },
48
+ },
49
+ },
50
+ {
51
+ cell: {
52
+ type: 'text',
53
+ text: 'FR, Paris',
54
+ },
55
+ },
56
+ {
57
+ cell: {
58
+ type: 'text',
59
+ text: '11 Oct 2022',
60
+ },
61
+ },
62
+ {
63
+ cell: {
64
+ type: 'currency',
65
+ primaryCurrency: {
66
+ amount: 12345.67,
67
+ currency: 'eur',
68
+ },
69
+ secondaryCurrency: {
70
+ amount: 11000.0,
71
+ currency: 'gbp',
72
+ },
73
+ },
74
+ alignment: 'right',
75
+ },
76
+ {
77
+ cell: {
78
+ type: 'status',
79
+ primaryText: 'Cancelled',
80
+ secondaryText: '1 day ago',
81
+ sentiment: 'negative',
82
+ },
83
+ },
84
+ ],
85
+ },
86
+ {
87
+ id: 1,
88
+ cells: [
89
+ {
90
+ cell: {
91
+ type: 'leading',
92
+ primaryText: 'Jan Kowalski',
93
+ secondaryText: 'Product Manager',
94
+ avatar: {
95
+ profileName: 'Jan Kowalski',
96
+ },
97
+ },
98
+ },
99
+ {
100
+ cell: {
101
+ type: 'text',
102
+ text: 'US, New York',
103
+ },
104
+ },
105
+ {
106
+ cell: {
107
+ type: 'text',
108
+ text: '24 Jan 2024',
109
+ },
110
+ },
111
+ {
112
+ cell: {
113
+ type: 'currency',
114
+ primaryCurrency: {
115
+ amount: 23456.78,
116
+ currency: 'usd',
117
+ },
118
+ secondaryCurrency: {
119
+ amount: 21000.0,
120
+ currency: 'gbp',
121
+ },
122
+ },
123
+ alignment: 'right',
124
+ },
125
+ {
126
+ cell: {
127
+ type: 'status',
128
+ primaryText: 'Scheduled',
129
+ secondaryText: 'Tomorrow',
130
+ sentiment: 'neutral',
131
+ },
132
+ },
133
+ ],
134
+ },
135
+ {
136
+ id: 2,
137
+ cells: [
138
+ {
139
+ cell: {
140
+ type: 'leading',
141
+ primaryText: 'William Davis',
142
+ secondaryText: 'Data Scientist',
143
+ avatar: {
144
+ profileName: 'William Davis',
145
+ },
146
+ },
147
+ },
148
+ {
149
+ cell: {
150
+ type: 'text',
151
+ text: 'UK, London',
152
+ },
153
+ },
154
+ {
155
+ cell: {
156
+ type: 'text',
157
+ text: '9 Sept 2023',
158
+ },
159
+ },
160
+ {
161
+ cell: {
162
+ type: 'currency',
163
+ primaryCurrency: {
164
+ amount: 34567.89,
165
+ currency: 'gbp',
166
+ },
167
+ secondaryCurrency: {
168
+ amount: 31000.0,
169
+ currency: 'eur',
170
+ },
171
+ },
172
+ alignment: 'right',
173
+ },
174
+ {
175
+ cell: {
176
+ type: 'status',
177
+ primaryText: 'Paid',
178
+ secondaryText: 'Yesterday',
179
+ sentiment: 'positive',
180
+ },
181
+ },
182
+ ],
183
+ },
184
+ {
185
+ id: 3,
186
+ cells: [
187
+ {
188
+ cell: {
189
+ type: 'leading',
190
+ primaryText: 'Jane Smith',
191
+ secondaryText: 'IT Support Specialist',
192
+ status: 'success',
193
+ avatar: {
194
+ src: 'avatar-square-dude.webp',
195
+ },
196
+ },
197
+ },
198
+ {
199
+ cell: {
200
+ type: 'text',
201
+ text: 'NO, Oslo',
202
+ },
203
+ },
204
+ {
205
+ cell: {
206
+ type: 'text',
207
+ text: '12 Apr 2024',
208
+ status: 'success',
209
+ },
210
+ },
211
+ {
212
+ cell: {
213
+ type: 'currency',
214
+ primaryCurrency: {
215
+ amount: 45678.9,
216
+ currency: 'nok',
217
+ },
218
+ secondaryCurrency: {
219
+ amount: 41000.0,
220
+ currency: 'gbp',
221
+ },
222
+ status: 'success',
223
+ },
224
+ alignment: 'right',
225
+ },
226
+ {
227
+ cell: {
228
+ type: 'status',
229
+ primaryText: 'Overdue',
230
+ secondaryText: '3 days ago',
231
+ sentiment: 'warning',
232
+ },
233
+ },
234
+ ],
235
+ },
236
+ {
237
+ id: 4,
238
+ cells: [
239
+ {
240
+ cell: {
241
+ type: 'leading',
242
+ primaryText: 'Alice Johnson',
243
+ secondaryText: 'Frontend Developer',
244
+ status: 'error',
245
+ avatar: {
246
+ src: 'avatar-square-dude.webp',
247
+ },
248
+ },
249
+ },
250
+ {
251
+ cell: {
252
+ type: 'text',
253
+ text: 'JP, Tokyo',
254
+ },
255
+ },
256
+ {
257
+ cell: {
258
+ type: 'text',
259
+ text: '27 Nov 2023',
260
+ status: 'error',
261
+ },
262
+ },
263
+ {
264
+ cell: {
265
+ type: 'currency',
266
+ primaryCurrency: {
267
+ amount: 56789.01, // JPY currency's value is always cropped to zero decimals, you'll see `56789` instead of `56789.01` in screen/tests
268
+ currency: 'jpy',
269
+ },
270
+ secondaryCurrency: {
271
+ amount: 51000.0,
272
+ currency: 'gbp',
273
+ },
274
+ status: 'error',
275
+ },
276
+ alignment: 'right',
277
+ },
278
+ {
279
+ cell: {
280
+ type: 'status',
281
+ primaryText: 'Overdue',
282
+ secondaryText: '6 days ago',
283
+ sentiment: 'pending',
284
+ },
285
+ },
286
+ ],
287
+ },
288
+ ] satisfies TableRowType[] | TableRowClickableType[],
289
+ };
290
+
291
+ export const Basic: Story = {
292
+ args: {
293
+ data: tableData,
294
+ },
295
+ render: (args) => {
296
+ return <Table {...args} />;
297
+ },
298
+ };
299
+
300
+ export const WithClickableRow: Story = {
301
+ args: {
302
+ data: {
303
+ ...tableData,
304
+ onRowClick: (rowData: TableRowType | TableRowClickableType) => {
305
+ // eslint-disable-next-line no-console
306
+ console.log(`Row clicked, data:`, rowData);
307
+ },
308
+ },
309
+ },
310
+ render: (args) => {
311
+ return <Table {...args} />;
312
+ },
313
+ };
314
+
315
+ export const WithLoading: Story = {
316
+ args: {
317
+ loading: true,
318
+ },
319
+ };
320
+
321
+ export const WithEmptyData: Story = {
322
+ args: {
323
+ data: {
324
+ headers: tableData.headers,
325
+ rows: [],
326
+ },
327
+ },
328
+ };
329
+
330
+ export const WithError: Story = {
331
+ args: {
332
+ error: {
333
+ message: 'Something went wrong during data fetching',
334
+ action: {
335
+ href: '/?path=/story/option-table--with-error',
336
+ text: 'To Refresh page, click here',
337
+ },
338
+ },
339
+ },
340
+ };
341
+
342
+ export const WithAFewColums: Story = {
343
+ args: {
344
+ data: {
345
+ headers: tableData.headers
346
+ .slice(0, 1)
347
+ .concat(tableData.headers[3])
348
+ .concat(tableData.headers[4]),
349
+ rows: tableData.rows.map((row) => ({
350
+ id: row.id,
351
+ cells: row.cells.slice(0, 1).concat(row.cells[3]).concat(row.cells[4]),
352
+ })),
353
+ },
354
+ fullWidth: false,
355
+ },
356
+ };
@@ -0,0 +1,167 @@
1
+ import { useIntl } from 'react-intl';
2
+ import TableCell from './TableCell';
3
+ import TableHeader, { TableHeaderType } from './TableHeader';
4
+ import TableRow, { TableRowClickableType, TableRowType } from './TableRow';
5
+ import Alert from '../alert';
6
+
7
+ import messages from './Table.messages';
8
+ import Loader from '../loader';
9
+ import { Sentiment, Size } from '../common';
10
+ import StatusIcon from '../statusIcon';
11
+ import { clsx } from 'clsx';
12
+ import { useTheme } from '@wise/components-theming';
13
+ import Body from '../body';
14
+
15
+ export interface TableProps {
16
+ 'aria-labelledby'?: string;
17
+ data: {
18
+ headers?: TableHeaderType[];
19
+ rows?: TableRowType[] | TableRowClickableType[];
20
+ onRowClick?: (rowData: TableRowType | TableRowClickableType) => void;
21
+ };
22
+ loading?: boolean;
23
+ className?: string | undefined;
24
+ fullWidth?: boolean;
25
+ error?: {
26
+ message?: string;
27
+ action?: {
28
+ href?: string;
29
+ text?: string;
30
+ };
31
+ };
32
+ }
33
+
34
+ const Table = ({
35
+ 'aria-labelledby': ariaLabelledBy,
36
+ data,
37
+ loading,
38
+ className,
39
+ fullWidth = true,
40
+ error,
41
+ }: TableProps) => {
42
+ const { formatMessage } = useIntl();
43
+ const { theme } = useTheme();
44
+
45
+ const getRowLength = () => {
46
+ const columnsLength = data?.headers?.length ?? 0;
47
+ return data?.onRowClick ? columnsLength + 1 : columnsLength;
48
+ };
49
+
50
+ const getTableContent = () => {
51
+ if (loading) {
52
+ return (
53
+ <TableRow>
54
+ <TableCell>
55
+ <Loader data-testid="np-table-loader" />
56
+ </TableCell>
57
+ </TableRow>
58
+ );
59
+ }
60
+
61
+ // Shows the `emptyData` message when there is no data to display
62
+ if (!data?.rows?.length) {
63
+ return (
64
+ <TableRow>
65
+ <TableCell colSpan={data?.headers?.length}>
66
+ <div className="np-table-empty-data" data-testid="np-table-empty-data">
67
+ <StatusIcon sentiment={Sentiment.WARNING} size={Size.MEDIUM} />
68
+ <Body type="body-default-bold">{formatMessage(messages.emptyData)}</Body>
69
+ </div>
70
+ </TableCell>
71
+ </TableRow>
72
+ );
73
+ }
74
+
75
+ return data?.rows?.map((rowData, rowIndex) => {
76
+ return (
77
+ <TableRow
78
+ key={'table-row-'.concat(rowIndex.toString())}
79
+ rowData={rowData}
80
+ hasSeparator={data?.rows?.length ? data.rows.length - 1 !== rowIndex : false}
81
+ onRowClick={data?.onRowClick}
82
+ />
83
+ );
84
+ });
85
+ };
86
+
87
+ if (error) {
88
+ return (
89
+ <Alert
90
+ className="np-table-error"
91
+ message={error.message}
92
+ type={Sentiment.NEGATIVE}
93
+ action={{
94
+ href: error?.action?.href ?? '/',
95
+ text: error?.action?.text ?? formatMessage(messages.refreshPage),
96
+ }}
97
+ data-testid="np-table-error"
98
+ />
99
+ );
100
+ }
101
+
102
+ return (
103
+ <>
104
+ <div aria-live="polite" className="sr-only">
105
+ {formatMessage(messages[loading ? 'loading' : 'loaded'])}
106
+ </div>
107
+ <div
108
+ role={loading ? 'presentation' : 'region'}
109
+ aria-labelledby={ariaLabelledBy}
110
+ className={clsx('np-table-outer-container', className, {
111
+ 'np-theme-personal': theme === 'bright-green',
112
+ 'np-table-outer-container--center': !fullWidth,
113
+ 'np-table-outer-container--full-width': fullWidth,
114
+ })}
115
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
116
+ tabIndex={0}
117
+ data-testid="np-table-outer-container"
118
+ >
119
+ <div
120
+ className={clsx('np-table-container', {
121
+ 'np-table-container--loading': loading,
122
+ })}
123
+ data-testid="np-table-container"
124
+ >
125
+ <div className="np-table-inner-container">
126
+ <table className="np-table">
127
+ <thead role={loading ? 'presentation' : undefined}>
128
+ <tr>
129
+ {(loading ?? (data?.headers && !data?.headers.length)) ? (
130
+ <TableHeader />
131
+ ) : (
132
+ data?.headers?.map((headerItem: TableHeaderType, index) => (
133
+ <TableHeader
134
+ key={headerItem.header?.concat(index.toString())}
135
+ {...headerItem}
136
+ />
137
+ ))
138
+ )}
139
+ {data?.onRowClick && <TableHeader isActionHeader />}
140
+ </tr>
141
+ </thead>
142
+ <tbody>
143
+ <tr
144
+ key="first-np-table-row--cosmetic"
145
+ aria-hidden="true"
146
+ className="np-table-row np-table-row--cosmetic"
147
+ >
148
+ <td className="np-table-cell" colSpan={getRowLength()} />
149
+ </tr>
150
+ {getTableContent()}
151
+ <tr
152
+ key="last-np-table-row--cosmetic"
153
+ aria-hidden="true"
154
+ className="np-table-row np-table-row--cosmetic"
155
+ >
156
+ <td className="np-table-cell" colSpan={getRowLength()} />
157
+ </tr>
158
+ </tbody>
159
+ </table>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </>
164
+ );
165
+ };
166
+
167
+ export default Table;