@transferwise/components 46.73.0 → 46.74.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/common/bottomSheet/BottomSheet.js +3 -1
- package/build/common/bottomSheet/BottomSheet.js.map +1 -1
- package/build/common/bottomSheet/BottomSheet.mjs +3 -1
- package/build/common/bottomSheet/BottomSheet.mjs.map +1 -1
- package/build/common/responsivePanel/ResponsivePanel.js +7 -1
- package/build/common/responsivePanel/ResponsivePanel.js.map +1 -1
- package/build/common/responsivePanel/ResponsivePanel.mjs +7 -1
- package/build/common/responsivePanel/ResponsivePanel.mjs.map +1 -1
- package/build/dimmer/Dimmer.js +3 -1
- package/build/dimmer/Dimmer.js.map +1 -1
- package/build/dimmer/Dimmer.mjs +3 -1
- package/build/dimmer/Dimmer.mjs.map +1 -1
- package/build/drawer/Drawer.js +2 -0
- package/build/drawer/Drawer.js.map +1 -1
- package/build/drawer/Drawer.mjs +2 -0
- package/build/drawer/Drawer.mjs.map +1 -1
- package/build/modal/Modal.js +3 -0
- package/build/modal/Modal.js.map +1 -1
- package/build/modal/Modal.mjs +3 -0
- package/build/modal/Modal.mjs.map +1 -1
- package/build/popover/Popover.js +6 -1
- package/build/popover/Popover.js.map +1 -1
- package/build/popover/Popover.mjs +7 -2
- package/build/popover/Popover.mjs.map +1 -1
- package/build/types/common/bottomSheet/BottomSheet.d.ts +1 -1
- package/build/types/common/bottomSheet/BottomSheet.d.ts.map +1 -1
- package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
- package/build/types/dimmer/Dimmer.d.ts +2 -1
- package/build/types/dimmer/Dimmer.d.ts.map +1 -1
- package/build/types/drawer/Drawer.d.ts +2 -1
- package/build/types/drawer/Drawer.d.ts.map +1 -1
- package/build/types/modal/Modal.d.ts +2 -1
- package/build/types/modal/Modal.d.ts.map +1 -1
- package/build/types/popover/Popover.d.ts +6 -4
- package/build/types/popover/Popover.d.ts.map +1 -1
- package/build/types/uploadInput/UploadInput.d.ts +9 -0
- package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts +16 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItemLink.d.ts.map +1 -1
- package/build/uploadInput/UploadInput.js +71 -66
- package/build/uploadInput/UploadInput.js.map +1 -1
- package/build/uploadInput/UploadInput.mjs +72 -67
- package/build/uploadInput/UploadInput.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.js +13 -4
- package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.mjs +13 -4
- package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js +1 -0
- package/build/uploadInput/uploadItem/UploadItemLink.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs +1 -0
- package/build/uploadInput/uploadItem/UploadItemLink.mjs.map +1 -1
- package/package.json +3 -3
- package/src/common/bottomSheet/BottomSheet.tsx +4 -2
- package/src/common/responsivePanel/ResponsivePanel.tsx +13 -3
- package/src/dimmer/Dimmer.spec.js +8 -0
- package/src/dimmer/Dimmer.tsx +4 -0
- package/src/drawer/Drawer.spec.js +25 -6
- package/src/drawer/Drawer.tsx +3 -1
- package/src/modal/Modal.spec.js +19 -1
- package/src/modal/Modal.tsx +4 -0
- package/src/popover/Popover.spec.tsx +64 -21
- package/src/popover/Popover.story.tsx +54 -42
- package/src/popover/Popover.tsx +12 -5
- package/src/popover/__snapshots__/Popover.spec.tsx.snap +2 -0
- package/src/uploadInput/UploadInput.spec.tsx +121 -9
- package/src/uploadInput/UploadInput.tests.story.tsx +207 -140
- package/src/uploadInput/UploadInput.tsx +110 -77
- package/src/uploadInput/uploadItem/UploadItem.spec.tsx +1 -0
- package/src/uploadInput/uploadItem/UploadItem.tsx +30 -6
- package/src/uploadInput/uploadItem/UploadItemLink.tsx +9 -1
package/src/popover/Popover.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useTheme } from '@wise/components-theming';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
|
-
import { useRef, useState, cloneElement, useEffect, isValidElement } from 'react';
|
|
3
|
+
import { useRef, useState, cloneElement, useEffect, isValidElement, useId } from 'react';
|
|
4
4
|
|
|
5
5
|
import { Position, Typography } from '../common';
|
|
6
6
|
import ResponsivePanel from '../common/responsivePanel';
|
|
@@ -23,11 +23,13 @@ export type PopoverPreferredPlacement =
|
|
|
23
23
|
|
|
24
24
|
export interface PopoverProps {
|
|
25
25
|
children?: React.ReactNode;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
title?: React.ReactNode;
|
|
27
|
+
/** Screen-reader-friendly title. Must be provided if `title` prop is not set. */
|
|
28
|
+
'aria-label'?: string;
|
|
28
29
|
preferredPlacement?: PopoverPreferredPlacement;
|
|
30
|
+
content: React.ReactNode;
|
|
29
31
|
onClose?: () => void;
|
|
30
|
-
|
|
32
|
+
className?: string;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
function resolvePlacement(preferredPlacement: PopoverPreferredPlacement) {
|
|
@@ -50,7 +52,10 @@ export default function Popover({
|
|
|
50
52
|
preferredPlacement = Position.RIGHT,
|
|
51
53
|
title,
|
|
52
54
|
onClose,
|
|
55
|
+
'aria-label': ariaLabel,
|
|
53
56
|
}: PopoverProps) {
|
|
57
|
+
const titleId = useId();
|
|
58
|
+
|
|
54
59
|
const resolvedPlacement = resolvePlacement(preferredPlacement);
|
|
55
60
|
useEffect(() => {
|
|
56
61
|
if (resolvedPlacement !== preferredPlacement) {
|
|
@@ -81,6 +86,8 @@ export default function Popover({
|
|
|
81
86
|
: children}
|
|
82
87
|
</span>
|
|
83
88
|
<ResponsivePanel
|
|
89
|
+
aria-label={ariaLabel}
|
|
90
|
+
aria-labelledby={title && !ariaLabel ? titleId : undefined}
|
|
84
91
|
open={open}
|
|
85
92
|
anchorRef={anchorReference}
|
|
86
93
|
position={resolvedPlacement}
|
|
@@ -90,7 +97,7 @@ export default function Popover({
|
|
|
90
97
|
>
|
|
91
98
|
<div className="np-popover__content np-text-default-body">
|
|
92
99
|
{title && (
|
|
93
|
-
<Title type={Typography.TITLE_BODY} className="m-b-1">
|
|
100
|
+
<Title type={Typography.TITLE_BODY} id={titleId} className="m-b-1">
|
|
94
101
|
{title}
|
|
95
102
|
</Title>
|
|
96
103
|
)}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Popover on desktop renders when is open 1`] = `
|
|
4
4
|
<div
|
|
5
|
+
aria-labelledby=":r0:"
|
|
5
6
|
class="np-panel np-panel--open np-popover__container"
|
|
6
7
|
data-popper-escaped="true"
|
|
7
8
|
data-popper-placement="right"
|
|
@@ -17,6 +18,7 @@ exports[`Popover on desktop renders when is open 1`] = `
|
|
|
17
18
|
>
|
|
18
19
|
<h4
|
|
19
20
|
class="np-text-title-body m-b-1"
|
|
21
|
+
id=":r0:"
|
|
20
22
|
>
|
|
21
23
|
title
|
|
22
24
|
</h4>
|
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
import { within } from '@testing-library/react';
|
|
1
|
+
import { Matcher, within } from '@testing-library/react';
|
|
2
2
|
import { userEvent } from '@testing-library/user-event';
|
|
3
3
|
import { act } from 'react';
|
|
4
4
|
|
|
5
5
|
import { Status } from '../common';
|
|
6
6
|
import { Field } from '../field/Field';
|
|
7
|
-
import { mockMatchMedia, render, screen, waitFor
|
|
7
|
+
import { mockMatchMedia, render, screen, waitFor } from '../test-utils';
|
|
8
8
|
|
|
9
9
|
import UploadInput, { UploadInputProps } from './UploadInput';
|
|
10
10
|
import { TEST_IDS as UPLOAD_BUTTON_TEST_IDS } from './uploadButton/UploadButton';
|
|
11
|
-
import { TEST_IDS as UPLOAD_ITEM_TEST_IDS } from './uploadItem/UploadItem';
|
|
12
11
|
|
|
13
12
|
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTimeAsync });
|
|
14
13
|
|
|
14
|
+
const deleteFileAndWaitForFocus = async (fileToDeleteTestId: Matcher, nextFocusTestId: Matcher) => {
|
|
15
|
+
const fileToDelete = screen.getByTestId(fileToDeleteTestId);
|
|
16
|
+
|
|
17
|
+
await user.click(within(fileToDelete).getByLabelText('Remove file', { exact: false }));
|
|
18
|
+
|
|
19
|
+
const removeButton = screen.queryByText('Remove');
|
|
20
|
+
if (removeButton) {
|
|
21
|
+
await user.click(removeButton);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
await waitFor(() => {
|
|
25
|
+
expect(screen.getByTestId(nextFocusTestId)).toHaveFocus();
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
15
29
|
mockMatchMedia();
|
|
16
30
|
|
|
17
31
|
describe('UploadInput', () => {
|
|
@@ -139,15 +153,21 @@ describe('UploadInput', () => {
|
|
|
139
153
|
onFilesChange,
|
|
140
154
|
});
|
|
141
155
|
|
|
142
|
-
const fileToDelete = screen.
|
|
143
|
-
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
156
|
+
const fileToDelete = screen.getByTestId('1-uploadItem');
|
|
144
157
|
await act(async () => {
|
|
158
|
+
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
145
159
|
await jest.runOnlyPendingTimersAsync();
|
|
146
160
|
});
|
|
147
161
|
|
|
148
|
-
|
|
162
|
+
await act(async () => {
|
|
163
|
+
screen.getByText('Remove').click();
|
|
164
|
+
await jest.runOnlyPendingTimersAsync();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
await waitFor(() => {
|
|
168
|
+
expect(screen.queryByTestId('1-uploadItem')).not.toBeInTheDocument();
|
|
169
|
+
});
|
|
149
170
|
|
|
150
|
-
await waitForElementToBeRemoved(fileToDelete);
|
|
151
171
|
expect(props.onDeleteFile).toHaveBeenCalledWith(files[0].id);
|
|
152
172
|
|
|
153
173
|
expect(onFilesChange).toHaveBeenCalledTimes(2);
|
|
@@ -190,9 +210,9 @@ describe('UploadInput', () => {
|
|
|
190
210
|
onFilesChange,
|
|
191
211
|
});
|
|
192
212
|
|
|
193
|
-
const fileToDelete = screen.
|
|
194
|
-
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
213
|
+
const fileToDelete = screen.getByTestId('1-uploadItem');
|
|
195
214
|
await act(async () => {
|
|
215
|
+
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
196
216
|
await jest.runOnlyPendingTimersAsync();
|
|
197
217
|
});
|
|
198
218
|
|
|
@@ -212,6 +232,98 @@ describe('UploadInput', () => {
|
|
|
212
232
|
|
|
213
233
|
expect(screen.queryByLabelText('Remove file ', { exact: false })).not.toBeInTheDocument();
|
|
214
234
|
});
|
|
235
|
+
|
|
236
|
+
it('should focus the next item after a file is deleted', async () => {
|
|
237
|
+
const files = [
|
|
238
|
+
{ id: 1, filename: 'Sales-2024-invoice.pdf', status: Status.DONE },
|
|
239
|
+
{ id: 2, filename: 'CoWork-0317-invoice.pdf', status: Status.DONE },
|
|
240
|
+
{ id: 3, filename: 'purchase-receipt.pdf', status: Status.DONE },
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
renderComponent({ ...props, files, multiple: true, onFilesChange });
|
|
244
|
+
|
|
245
|
+
// Delete the first file and expect focus to move to the next one
|
|
246
|
+
await deleteFileAndWaitForFocus('1-uploadItem', '2-action');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should focus the previous item after the last file is deleted', async () => {
|
|
250
|
+
const files = [
|
|
251
|
+
{
|
|
252
|
+
id: 1,
|
|
253
|
+
filename: 'Sales-2024-invoice.pdf',
|
|
254
|
+
status: Status.DONE,
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: 2,
|
|
258
|
+
filename: 'CoWork-0317-invoice.pdf',
|
|
259
|
+
status: Status.DONE,
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: 3,
|
|
263
|
+
filename: 'purchase-receipt.pdf',
|
|
264
|
+
status: Status.DONE,
|
|
265
|
+
},
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
renderComponent({
|
|
269
|
+
...props,
|
|
270
|
+
files,
|
|
271
|
+
multiple: true,
|
|
272
|
+
onFilesChange,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
await deleteFileAndWaitForFocus('3-uploadItem', '2-action');
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should focus the upload input after the only file is deleted', async () => {
|
|
279
|
+
const singleFile = [
|
|
280
|
+
{
|
|
281
|
+
id: 3,
|
|
282
|
+
filename: 'purchase-receipt.pdf',
|
|
283
|
+
status: Status.DONE,
|
|
284
|
+
},
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
renderComponent({
|
|
288
|
+
...props,
|
|
289
|
+
files: singleFile,
|
|
290
|
+
multiple: true,
|
|
291
|
+
onFilesChange,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
await deleteFileAndWaitForFocus('3-uploadItem', 'uploadInput');
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('should focus on the next item or upload input after each file is deleted in sequence', async () => {
|
|
298
|
+
const filesWithFailed = [
|
|
299
|
+
{
|
|
300
|
+
id: 1,
|
|
301
|
+
filename: 'Sales-2024-invoice.pdf',
|
|
302
|
+
status: Status.DONE,
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
id: 2,
|
|
306
|
+
filename: 'CoWork-0317-invoice.pdf',
|
|
307
|
+
status: Status.FAILED,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
id: 3,
|
|
311
|
+
filename: 'purchase-receipt.pdf',
|
|
312
|
+
status: Status.DONE,
|
|
313
|
+
},
|
|
314
|
+
];
|
|
315
|
+
|
|
316
|
+
renderComponent({
|
|
317
|
+
...props,
|
|
318
|
+
files: filesWithFailed,
|
|
319
|
+
multiple: true,
|
|
320
|
+
onFilesChange,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
await deleteFileAndWaitForFocus('3-uploadItem', '2-action');
|
|
324
|
+
await deleteFileAndWaitForFocus('1-uploadItem', '2-action');
|
|
325
|
+
await deleteFileAndWaitForFocus('2-uploadItem', 'uploadInput');
|
|
326
|
+
});
|
|
215
327
|
});
|
|
216
328
|
|
|
217
329
|
describe('Max File Upload limit', () => {
|
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
import { action } from '@storybook/addon-actions';
|
|
2
|
-
import {
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
|
|
4
4
|
import { Status } from '../common';
|
|
5
|
-
|
|
6
5
|
import UploadInput, { UploadInputProps } from './UploadInput';
|
|
7
6
|
import { UploadedFile, UploadResponse } from './types';
|
|
7
|
+
import { userEvent, within } from '@storybook/test';
|
|
8
8
|
|
|
9
9
|
const meta: Meta<typeof UploadInput> = {
|
|
10
10
|
title: 'Forms/UploadInput/Tests',
|
|
11
11
|
component: UploadInput,
|
|
12
12
|
};
|
|
13
|
-
|
|
14
13
|
export default meta;
|
|
15
|
-
type Story = StoryFn<UploadInputProps>;
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
type Story = StoryObj<UploadInputProps>;
|
|
16
|
+
|
|
17
|
+
const files: UploadedFile[] = [
|
|
18
18
|
{
|
|
19
|
-
id:
|
|
19
|
+
id: '0hd8hf8',
|
|
20
20
|
filename: 'purchase-receipt-0.pdf',
|
|
21
21
|
url: 'https://wise.com/public-resources/assets/logos/wise/brand_logo_inverse.svg',
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
|
-
id:
|
|
24
|
+
id: '1r7hgc83',
|
|
25
25
|
filename: 'purchase-receipt-1.pdf',
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
id:
|
|
28
|
+
id: '2nhc7387hc8h',
|
|
29
29
|
filename: 'purchase-receipt-2.pdf',
|
|
30
30
|
url: 'https://wise.com/public-resources/assets/logos/wise/brand_logo_inverse.svg',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
id:
|
|
33
|
+
id: '39wd8uc',
|
|
34
34
|
filename: 'receipt failed.png',
|
|
35
35
|
status: Status.FAILED,
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
|
-
id:
|
|
38
|
+
id: '437yyf8hf',
|
|
39
39
|
filename: 'receipt failed With error string.png',
|
|
40
40
|
status: Status.FAILED,
|
|
41
41
|
error: 'Something went wrong',
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
id:
|
|
44
|
+
id: '5biehveifh',
|
|
45
45
|
filename: 'receipt failed With error object.png',
|
|
46
46
|
status: Status.FAILED,
|
|
47
47
|
error: { message: 'Something went wrong' },
|
|
48
48
|
},
|
|
49
|
-
]
|
|
49
|
+
];
|
|
50
50
|
|
|
51
51
|
const createDelayedPromise = async ({
|
|
52
52
|
successful = true,
|
|
@@ -65,163 +65,230 @@ const createDelayedPromise = async ({
|
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
const props = {
|
|
68
|
-
onUploadFile: async (formData: FormData) =>
|
|
69
|
-
|
|
68
|
+
onUploadFile: async (formData: FormData) => createDelayedPromise(),
|
|
69
|
+
onDeleteFile: async (id: string | number) => createDelayedPromise(),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const UploadInputWithDescriptionFromProps: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
...props,
|
|
75
|
+
multiple: true,
|
|
76
|
+
description: 'Custom file description from prop',
|
|
70
77
|
},
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const Disabled: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
...props,
|
|
83
|
+
disabled: true,
|
|
73
84
|
},
|
|
74
85
|
};
|
|
75
86
|
|
|
76
|
-
const
|
|
87
|
+
export const WithAnyFileType: Story = {
|
|
88
|
+
args: {
|
|
89
|
+
...props,
|
|
90
|
+
fileTypes: '*',
|
|
91
|
+
},
|
|
92
|
+
};
|
|
77
93
|
|
|
78
|
-
export const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
export const WithSingleFileType: Story = {
|
|
95
|
+
args: {
|
|
96
|
+
...props,
|
|
97
|
+
fileTypes: '.zip,application/zip',
|
|
98
|
+
},
|
|
83
99
|
};
|
|
84
100
|
|
|
85
|
-
export const
|
|
86
|
-
|
|
101
|
+
export const WithMultipleExistingFiles: Story = {
|
|
102
|
+
args: {
|
|
103
|
+
...props,
|
|
104
|
+
files,
|
|
105
|
+
multiple: true,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
87
108
|
|
|
88
|
-
export const
|
|
89
|
-
|
|
109
|
+
export const WithFileErrors: Story = {
|
|
110
|
+
args: {
|
|
111
|
+
...props,
|
|
112
|
+
files: [
|
|
113
|
+
{ id: 1, filename: 'Error with default message.png', status: Status.FAILED },
|
|
114
|
+
{
|
|
115
|
+
id: 2,
|
|
116
|
+
filename: 'Error with `string` error.png',
|
|
117
|
+
status: Status.FAILED,
|
|
118
|
+
error: 'Single string error',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 3,
|
|
122
|
+
filename: 'Error with `obj` error ({ message : `string` }).png',
|
|
123
|
+
status: Status.FAILED,
|
|
124
|
+
error: { message: 'Single obj error' },
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: 4,
|
|
128
|
+
filename: 'Error with single error passed in `array`.png',
|
|
129
|
+
status: Status.FAILED,
|
|
130
|
+
errors: ['Single error in array'],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 5,
|
|
134
|
+
filename: 'Error with multiple `string` errors passed in `array`.png',
|
|
135
|
+
status: Status.FAILED,
|
|
136
|
+
errors: [
|
|
137
|
+
'Error 1',
|
|
138
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
|
|
139
|
+
'Error 3',
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 6,
|
|
144
|
+
filename: 'Error with multiple `obj` errors passed in `array`.png',
|
|
145
|
+
status: Status.FAILED,
|
|
146
|
+
errors: [
|
|
147
|
+
{ message: 'Error 1' },
|
|
148
|
+
{
|
|
149
|
+
message:
|
|
150
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
|
|
151
|
+
},
|
|
152
|
+
{ message: 'Error 3' },
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
multiple: true,
|
|
157
|
+
},
|
|
158
|
+
};
|
|
90
159
|
|
|
91
|
-
export const
|
|
92
|
-
|
|
160
|
+
export const WithoutDelete: Story = {
|
|
161
|
+
args: {
|
|
162
|
+
...props,
|
|
163
|
+
files,
|
|
164
|
+
onDeleteFile: undefined,
|
|
165
|
+
multiple: true,
|
|
166
|
+
},
|
|
167
|
+
};
|
|
93
168
|
|
|
94
|
-
export const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
169
|
+
export const WithUploadFailed: Story = {
|
|
170
|
+
args: {
|
|
171
|
+
...props,
|
|
172
|
+
files: files.slice(0),
|
|
173
|
+
onUploadFile: async () => createDelayedPromise({ successful: false }),
|
|
174
|
+
multiple: true,
|
|
175
|
+
},
|
|
99
176
|
};
|
|
100
177
|
|
|
101
|
-
export const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
{
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
status: Status.FAILED,
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
id: 2,
|
|
112
|
-
filename: 'Error with `string` error.png',
|
|
113
|
-
status: Status.FAILED,
|
|
114
|
-
error: 'Single string error',
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
id: 3,
|
|
118
|
-
filename: 'Error with `obj` error ({ message : `string` }).png',
|
|
119
|
-
status: Status.FAILED,
|
|
120
|
-
error: { message: 'Single obj error' },
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
id: 4,
|
|
124
|
-
filename: 'Error with single error passed in `array`.png',
|
|
125
|
-
status: Status.FAILED,
|
|
126
|
-
errors: ['Single error in array'],
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
id: 5,
|
|
130
|
-
filename: 'Error with multiple `string` errors passed in `array`.png',
|
|
131
|
-
status: Status.FAILED,
|
|
132
|
-
errors: [
|
|
133
|
-
'Error 1',
|
|
134
|
-
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
|
|
135
|
-
'Error 3',
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
id: 6,
|
|
140
|
-
filename: 'Error with multiple `obj` errors passed in `array`.png',
|
|
141
|
-
status: Status.FAILED,
|
|
142
|
-
errors: [
|
|
143
|
-
{ message: 'Error 1' },
|
|
144
|
-
{
|
|
145
|
-
message:
|
|
146
|
-
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
|
|
147
|
-
},
|
|
148
|
-
{ message: 'Error 3' },
|
|
149
|
-
],
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
multiple: true,
|
|
178
|
+
export const WithDeleteFailed: Story = {
|
|
179
|
+
args: {
|
|
180
|
+
...props,
|
|
181
|
+
files: files.slice(0),
|
|
182
|
+
onDeleteFile: async () => createDelayedPromise({ successful: false }),
|
|
183
|
+
multiple: true,
|
|
184
|
+
},
|
|
153
185
|
};
|
|
154
186
|
|
|
155
|
-
export const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
187
|
+
export const CustomConfirmMessage: Story = {
|
|
188
|
+
args: {
|
|
189
|
+
...props,
|
|
190
|
+
files: files.slice(0),
|
|
191
|
+
deleteConfirm: {
|
|
192
|
+
title: 'Sure you want to remove this invoice?',
|
|
193
|
+
body: (
|
|
194
|
+
<img
|
|
195
|
+
alt="brand logo"
|
|
196
|
+
src="https://wise.com/public-resources/assets/logos/wise/brand_logo.svg"
|
|
197
|
+
/>
|
|
198
|
+
),
|
|
199
|
+
},
|
|
200
|
+
},
|
|
161
201
|
};
|
|
162
202
|
|
|
163
|
-
export const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
203
|
+
export const WithManualDownloadHandler: Story = {
|
|
204
|
+
args: {
|
|
205
|
+
...props,
|
|
206
|
+
files,
|
|
207
|
+
onDownload: action('Manual download handler'),
|
|
208
|
+
},
|
|
169
209
|
};
|
|
170
210
|
|
|
171
|
-
export const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
211
|
+
export const WithFilesChangeHandler: Story = {
|
|
212
|
+
args: {
|
|
213
|
+
...props,
|
|
214
|
+
files,
|
|
215
|
+
onFilesChange: action('Files change handler'),
|
|
216
|
+
},
|
|
177
217
|
};
|
|
178
218
|
|
|
179
|
-
export const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
body: (
|
|
186
|
-
<img
|
|
187
|
-
alt="brand logo"
|
|
188
|
-
src="https://wise.com/public-resources/assets/logos/wise/brand_logo.svg"
|
|
189
|
-
/>
|
|
190
|
-
),
|
|
219
|
+
export const WithMaxFilesToUploadLimit: Story = {
|
|
220
|
+
args: {
|
|
221
|
+
...props,
|
|
222
|
+
multiple: true,
|
|
223
|
+
maxFiles: 5,
|
|
224
|
+
maxFilesErrorMessage: "Can't upload as maximum number of files allowed are already uploaded",
|
|
191
225
|
},
|
|
192
226
|
};
|
|
193
227
|
|
|
194
|
-
export const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
228
|
+
export const WithFileSizeErrorMessage: Story = {
|
|
229
|
+
args: {
|
|
230
|
+
...props,
|
|
231
|
+
sizeLimit: 1,
|
|
232
|
+
sizeLimitErrorMessage: 'The file is oversized',
|
|
233
|
+
},
|
|
199
234
|
};
|
|
200
235
|
|
|
201
|
-
export const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
236
|
+
export const WithCustomUploadButtonTitle: Story = {
|
|
237
|
+
args: {
|
|
238
|
+
...props,
|
|
239
|
+
uploadButtonTitle: 'Upload the VAT receipts for FY 2022-23',
|
|
240
|
+
},
|
|
206
241
|
};
|
|
207
242
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
243
|
+
const triggerModalAndConfirm = async ({ isLink = true } = {}) => {
|
|
244
|
+
if (isLink) {
|
|
245
|
+
await wait();
|
|
246
|
+
await userEvent.tab();
|
|
247
|
+
}
|
|
248
|
+
await wait();
|
|
249
|
+
await userEvent.keyboard('{Enter}');
|
|
250
|
+
await wait();
|
|
251
|
+
await userEvent.tab();
|
|
252
|
+
await wait();
|
|
253
|
+
await userEvent.tab();
|
|
254
|
+
await wait();
|
|
255
|
+
await userEvent.tab();
|
|
256
|
+
await wait();
|
|
257
|
+
await userEvent.keyboard('{Enter}');
|
|
258
|
+
await wait();
|
|
214
259
|
};
|
|
260
|
+
const wait = async (time = 250) =>
|
|
261
|
+
new Promise((resolve) => {
|
|
262
|
+
setTimeout(resolve, time);
|
|
263
|
+
});
|
|
215
264
|
|
|
216
|
-
export const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
265
|
+
export const DeletingTop: Story = {
|
|
266
|
+
args: {
|
|
267
|
+
...props,
|
|
268
|
+
files: [files[0], files[1], files[2]],
|
|
269
|
+
multiple: true,
|
|
270
|
+
},
|
|
271
|
+
play: async ({ canvasElement }) => {
|
|
272
|
+
await userEvent.tab();
|
|
273
|
+
await triggerModalAndConfirm();
|
|
274
|
+
await triggerModalAndConfirm({ isLink: false });
|
|
275
|
+
await triggerModalAndConfirm();
|
|
276
|
+
},
|
|
221
277
|
};
|
|
222
278
|
|
|
223
|
-
export const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
279
|
+
export const DeletingBottom: Story = {
|
|
280
|
+
args: {
|
|
281
|
+
...props,
|
|
282
|
+
files: [files[0], files[1], files[2]],
|
|
283
|
+
multiple: true,
|
|
284
|
+
},
|
|
285
|
+
play: async ({ canvasElement }) => {
|
|
286
|
+
await userEvent.tab();
|
|
287
|
+
await userEvent.tab();
|
|
288
|
+
await userEvent.tab();
|
|
289
|
+
await userEvent.tab();
|
|
290
|
+
await triggerModalAndConfirm();
|
|
291
|
+
await triggerModalAndConfirm({ isLink: false });
|
|
292
|
+
await triggerModalAndConfirm();
|
|
293
|
+
},
|
|
227
294
|
};
|