@transferwise/components 46.97.5 → 46.98.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/alert/Alert.js +8 -0
- package/build/alert/Alert.js.map +1 -1
- package/build/alert/Alert.mjs +8 -0
- package/build/alert/Alert.mjs.map +1 -1
- package/build/common/closeButton/CloseButton.js +3 -1
- package/build/common/closeButton/CloseButton.js.map +1 -1
- package/build/common/closeButton/CloseButton.mjs +3 -1
- package/build/common/closeButton/CloseButton.mjs.map +1 -1
- package/build/dateInput/DateInput.js +4 -4
- package/build/dateInput/DateInput.js.map +1 -1
- package/build/dateInput/DateInput.mjs +4 -4
- package/build/dateInput/DateInput.mjs.map +1 -1
- package/build/dateLookup/DateLookup.js +4 -4
- package/build/dateLookup/DateLookup.js.map +1 -1
- package/build/dateLookup/DateLookup.mjs +4 -4
- package/build/dateLookup/DateLookup.mjs.map +1 -1
- package/build/dateLookup/dayCalendar/table/DayCalendarTable.js +3 -3
- package/build/dateLookup/dayCalendar/table/DayCalendarTable.js.map +1 -1
- package/build/dateLookup/dayCalendar/table/DayCalendarTable.mjs +3 -3
- package/build/dateLookup/dayCalendar/table/DayCalendarTable.mjs.map +1 -1
- package/build/i18n/cs.json +3 -2
- package/build/i18n/cs.json.js +3 -2
- package/build/i18n/cs.json.js.map +1 -1
- package/build/i18n/cs.json.mjs +3 -2
- package/build/i18n/cs.json.mjs.map +1 -1
- package/build/i18n/de.json +3 -2
- package/build/i18n/de.json.js +3 -2
- package/build/i18n/de.json.js.map +1 -1
- package/build/i18n/de.json.mjs +3 -2
- package/build/i18n/de.json.mjs.map +1 -1
- package/build/i18n/en.json +3 -2
- package/build/i18n/en.json.js +3 -2
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +3 -2
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/i18n/es.json +3 -2
- package/build/i18n/es.json.js +3 -2
- package/build/i18n/es.json.js.map +1 -1
- package/build/i18n/es.json.mjs +3 -2
- package/build/i18n/es.json.mjs.map +1 -1
- package/build/i18n/fr.json +3 -2
- package/build/i18n/fr.json.js +3 -2
- package/build/i18n/fr.json.js.map +1 -1
- package/build/i18n/fr.json.mjs +3 -2
- package/build/i18n/fr.json.mjs.map +1 -1
- package/build/i18n/hu.json +3 -2
- package/build/i18n/hu.json.js +3 -2
- package/build/i18n/hu.json.js.map +1 -1
- package/build/i18n/hu.json.mjs +3 -2
- package/build/i18n/hu.json.mjs.map +1 -1
- package/build/i18n/id.json +3 -2
- package/build/i18n/id.json.js +3 -2
- package/build/i18n/id.json.js.map +1 -1
- package/build/i18n/id.json.mjs +3 -2
- package/build/i18n/id.json.mjs.map +1 -1
- package/build/i18n/it.json +3 -2
- package/build/i18n/it.json.js +3 -2
- package/build/i18n/it.json.js.map +1 -1
- package/build/i18n/it.json.mjs +3 -2
- package/build/i18n/it.json.mjs.map +1 -1
- package/build/i18n/ja.json +3 -2
- package/build/i18n/ja.json.js +3 -2
- package/build/i18n/ja.json.js.map +1 -1
- package/build/i18n/ja.json.mjs +3 -2
- package/build/i18n/ja.json.mjs.map +1 -1
- package/build/i18n/nl.json +6 -5
- package/build/i18n/pl.json +3 -2
- package/build/i18n/pl.json.js +3 -2
- package/build/i18n/pl.json.js.map +1 -1
- package/build/i18n/pl.json.mjs +3 -2
- package/build/i18n/pl.json.mjs.map +1 -1
- package/build/i18n/pt.json +3 -2
- package/build/i18n/pt.json.js +3 -2
- package/build/i18n/pt.json.js.map +1 -1
- package/build/i18n/pt.json.mjs +3 -2
- package/build/i18n/pt.json.mjs.map +1 -1
- package/build/i18n/ro.json +3 -2
- package/build/i18n/ro.json.js +3 -2
- package/build/i18n/ro.json.js.map +1 -1
- package/build/i18n/ro.json.mjs +3 -2
- package/build/i18n/ro.json.mjs.map +1 -1
- package/build/i18n/ru.json +3 -2
- package/build/i18n/ru.json.js +3 -2
- package/build/i18n/ru.json.js.map +1 -1
- package/build/i18n/ru.json.mjs +3 -2
- package/build/i18n/ru.json.mjs.map +1 -1
- package/build/i18n/th.json +3 -2
- package/build/i18n/th.json.js +3 -2
- package/build/i18n/th.json.js.map +1 -1
- package/build/i18n/th.json.mjs +3 -2
- package/build/i18n/th.json.mjs.map +1 -1
- package/build/i18n/tr.json +3 -2
- package/build/i18n/tr.json.js +3 -2
- package/build/i18n/tr.json.js.map +1 -1
- package/build/i18n/tr.json.mjs +3 -2
- package/build/i18n/tr.json.mjs.map +1 -1
- package/build/i18n/zh-CN.json +3 -2
- package/build/i18n/zh-CN.json.js +3 -2
- package/build/i18n/zh-CN.json.js.map +1 -1
- package/build/i18n/zh-CN.json.mjs +3 -2
- package/build/i18n/zh-CN.json.mjs.map +1 -1
- package/build/i18n/zh-HK.json +3 -2
- package/build/i18n/zh-HK.json.js +3 -2
- package/build/i18n/zh-HK.json.js.map +1 -1
- package/build/i18n/zh-HK.json.mjs +3 -2
- package/build/i18n/zh-HK.json.mjs.map +1 -1
- package/build/image/Image.js +9 -10
- package/build/image/Image.js.map +1 -1
- package/build/image/Image.mjs +11 -11
- package/build/image/Image.mjs.map +1 -1
- package/build/index.js +0 -2
- package/build/index.js.map +1 -1
- package/build/index.mjs +0 -1
- package/build/index.mjs.map +1 -1
- package/build/main.css +16 -45
- package/build/moneyInput/MoneyInput.js +4 -8
- package/build/moneyInput/MoneyInput.js.map +1 -1
- package/build/moneyInput/MoneyInput.messages.js +3 -0
- package/build/moneyInput/MoneyInput.messages.js.map +1 -1
- package/build/moneyInput/MoneyInput.messages.mjs +3 -0
- package/build/moneyInput/MoneyInput.messages.mjs.map +1 -1
- package/build/moneyInput/MoneyInput.mjs +4 -8
- package/build/moneyInput/MoneyInput.mjs.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.js +36 -2
- package/build/phoneNumberInput/PhoneNumberInput.js.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.messages.js +6 -0
- package/build/phoneNumberInput/PhoneNumberInput.messages.js.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.messages.mjs +6 -0
- package/build/phoneNumberInput/PhoneNumberInput.messages.mjs.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.mjs +36 -2
- package/build/phoneNumberInput/PhoneNumberInput.mjs.map +1 -1
- package/build/snackbar/Snackbar.js +1 -1
- package/build/snackbar/Snackbar.js.map +1 -1
- package/build/snackbar/Snackbar.mjs +1 -1
- package/build/snackbar/Snackbar.mjs.map +1 -1
- package/build/styles/circularButton/CircularButton.css +1 -0
- package/build/styles/dateInput/DateInput.css +13 -0
- package/build/styles/main.css +16 -45
- package/build/styles/uploadInput/uploadItem/UploadItem.css +2 -1
- package/build/tabs/Tabs.js +3 -3
- package/build/tabs/Tabs.js.map +1 -1
- package/build/tabs/Tabs.mjs +3 -3
- package/build/tabs/Tabs.mjs.map +1 -1
- package/build/test-utils/assets/apple-pay-logo.svg +84 -0
- package/build/typeahead/Typeahead.js +2 -2
- package/build/typeahead/Typeahead.js.map +1 -1
- package/build/typeahead/Typeahead.mjs +2 -2
- package/build/typeahead/Typeahead.mjs.map +1 -1
- package/build/typeahead/typeaheadInput/TypeaheadInput.js +2 -2
- package/build/typeahead/typeaheadInput/TypeaheadInput.js.map +1 -1
- package/build/typeahead/typeaheadInput/TypeaheadInput.mjs +2 -2
- package/build/typeahead/typeaheadInput/TypeaheadInput.mjs.map +1 -1
- package/build/types/alert/Alert.d.ts.map +1 -1
- package/build/types/common/closeButton/CloseButton.d.ts +2 -0
- package/build/types/common/closeButton/CloseButton.d.ts.map +1 -1
- package/build/types/image/Image.d.ts +0 -1
- package/build/types/image/Image.d.ts.map +1 -1
- package/build/types/index.d.ts +0 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.messages.d.ts +5 -0
- package/build/types/moneyInput/MoneyInput.messages.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 -1
- package/build/types/test-utils/fake-data.d.ts +2 -0
- package/build/types/test-utils/fake-data.d.ts.map +1 -1
- package/build/types/test-utils/index.d.ts +6 -4
- package/build/types/test-utils/index.d.ts.map +1 -1
- package/build/types/upload/Upload.d.ts +1 -2
- package/build/types/upload/Upload.d.ts.map +1 -1
- package/build/types/upload/steps/processingStep/processingStep.d.ts +1 -3
- package/build/types/upload/steps/processingStep/processingStep.d.ts.map +1 -1
- package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
- package/build/upload/Upload.js +29 -45
- package/build/upload/Upload.js.map +1 -1
- package/build/upload/Upload.mjs +29 -45
- package/build/upload/Upload.mjs.map +1 -1
- package/build/upload/steps/processingStep/processingStep.js +1 -3
- package/build/upload/steps/processingStep/processingStep.js.map +1 -1
- package/build/upload/steps/processingStep/processingStep.mjs +1 -3
- package/build/upload/steps/processingStep/processingStep.mjs.map +1 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.js +1 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.js.map +1 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.mjs +1 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.mjs.map +1 -1
- package/build/uploadInput/UploadInput.js +54 -6
- package/build/uploadInput/UploadInput.js.map +1 -1
- package/build/uploadInput/UploadInput.mjs +54 -6
- package/build/uploadInput/UploadInput.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.js +12 -6
- package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.mjs +12 -6
- package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
- package/build/withDisplayFormat/WithDisplayFormat.js +3 -2
- package/build/withDisplayFormat/WithDisplayFormat.js.map +1 -1
- package/build/withDisplayFormat/WithDisplayFormat.mjs +3 -2
- package/build/withDisplayFormat/WithDisplayFormat.mjs.map +1 -1
- package/package.json +14 -17
- package/src/alert/Alert.spec.tsx +11 -0
- package/src/alert/Alert.story.tsx +23 -9
- package/src/alert/Alert.tsx +14 -1
- package/src/circularButton/CircularButton.css +1 -0
- package/src/circularButton/CircularButton.less +1 -0
- package/src/circularButton/CircularButton.tests.story.tsx +23 -0
- package/src/common/closeButton/CloseButton.spec.tsx +13 -1
- package/src/common/closeButton/CloseButton.tsx +3 -0
- package/src/dateInput/DateInput.css +13 -0
- package/src/dateInput/DateInput.less +20 -0
- package/src/dateInput/DateInput.tests.story.tsx +14 -3
- package/src/dateInput/DateInput.tsx +4 -4
- package/src/i18n/cs.json +3 -2
- package/src/i18n/de.json +3 -2
- package/src/i18n/en.json +3 -2
- package/src/i18n/es.json +3 -2
- package/src/i18n/fr.json +3 -2
- package/src/i18n/hu.json +3 -2
- package/src/i18n/id.json +3 -2
- package/src/i18n/it.json +3 -2
- package/src/i18n/ja.json +3 -2
- package/src/i18n/nl.json +6 -5
- package/src/i18n/pl.json +3 -2
- package/src/i18n/pt.json +3 -2
- package/src/i18n/ro.json +3 -2
- package/src/i18n/ru.json +3 -2
- package/src/i18n/th.json +3 -2
- package/src/i18n/tr.json +3 -2
- package/src/i18n/zh-CN.json +3 -2
- package/src/i18n/zh-HK.json +3 -2
- package/src/image/Image.spec.tsx +3 -3
- package/src/image/Image.tsx +10 -12
- package/src/index.ts +0 -2
- package/src/legacylistItem/LegacyListItem.story.tsx +5 -5
- package/src/legacylistItem/LegacyListItem.tests.story.tsx +6 -6
- package/src/main.css +16 -45
- package/src/main.less +0 -1
- package/src/moneyInput/MoneyInput.messages.ts +5 -0
- package/src/moneyInput/MoneyInput.spec.tsx +42 -5
- package/src/moneyInput/MoneyInput.story.tsx +11 -2
- package/src/moneyInput/MoneyInput.tsx +5 -7
- package/src/phoneNumberInput/PhoneNumberInput.messages.ts +8 -0
- package/src/phoneNumberInput/PhoneNumberInput.spec.tsx +77 -43
- package/src/phoneNumberInput/PhoneNumberInput.tsx +34 -2
- package/src/promoCard/__snapshots__/PromoCard.spec.tsx.snap +1 -0
- package/src/promoCard/__snapshots__/PromoCardGroup.spec.tsx.snap +2 -0
- package/src/ssr.spec.tsx +0 -1
- package/src/test-utils/assets/apple-pay-logo.svg +84 -0
- package/src/test-utils/fake-data.ts +5 -0
- package/src/test-utils/jest.setup.ts +0 -4
- package/src/typeahead/Typeahead.spec.tsx +182 -0
- package/src/typeahead/typeaheadInput/TypeaheadInput.spec.tsx +103 -0
- package/src/typeahead/util/highlight.spec.tsx +43 -0
- package/src/upload/Upload.spec.tsx +63 -0
- package/src/upload/Upload.story.tsx +0 -51
- package/src/upload/Upload.tests.story.tsx +93 -0
- package/src/upload/Upload.tsx +28 -49
- package/src/upload/steps/processingStep/processingStep.tsx +2 -7
- package/src/uploadInput/UploadInput.tsx +74 -10
- package/src/uploadInput/uploadItem/UploadItem.css +2 -1
- package/src/uploadInput/uploadItem/UploadItem.less +1 -1
- package/src/uploadInput/uploadItem/UploadItem.tsx +11 -6
- package/src/withDisplayFormat/WithDisplayFormat.spec.js +11 -15
- package/src/withDisplayFormat/WithDisplayFormat.tsx +3 -2
- package/build/selectOption/SelectOption.js +0 -131
- package/build/selectOption/SelectOption.js.map +0 -1
- package/build/selectOption/SelectOption.messages.js +0 -17
- package/build/selectOption/SelectOption.messages.js.map +0 -1
- package/build/selectOption/SelectOption.messages.mjs +0 -13
- package/build/selectOption/SelectOption.messages.mjs.map +0 -1
- package/build/selectOption/SelectOption.mjs +0 -127
- package/build/selectOption/SelectOption.mjs.map +0 -1
- package/build/styles/selectOption/SelectOption.css +0 -44
- package/build/types/selectOption/SelectOption.d.ts +0 -21
- package/build/types/selectOption/SelectOption.d.ts.map +0 -1
- package/build/types/selectOption/SelectOption.messages.d.ts +0 -12
- package/build/types/selectOption/SelectOption.messages.d.ts.map +0 -1
- package/build/types/selectOption/index.d.ts +0 -3
- package/build/types/selectOption/index.d.ts.map +0 -1
- package/src/selectOption/SelectOption.css +0 -44
- package/src/selectOption/SelectOption.less +0 -40
- package/src/selectOption/SelectOption.messages.ts +0 -12
- package/src/selectOption/SelectOption.spec.tsx +0 -83
- package/src/selectOption/SelectOption.story.tsx +0 -277
- package/src/selectOption/SelectOption.tsx +0 -151
- package/src/selectOption/index.ts +0 -2
- package/src/typeahead/Typeahead.rtl.spec.tsx +0 -54
- package/src/typeahead/Typeahead.spec.js +0 -404
- package/src/typeahead/typeaheadInput/TypeaheadInput.spec.js +0 -74
- package/src/typeahead/typeaheadOption/TypeaheadOption.spec.js +0 -75
- package/src/typeahead/util/highlight.spec.js +0 -34
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Field } from '../field/Field';
|
|
2
|
+
import { mockMatchMedia, render, screen, fireEvent } from '../test-utils';
|
|
3
|
+
import { wait } from '../test-utils/wait';
|
|
4
|
+
import Typeahead from './Typeahead';
|
|
5
|
+
|
|
6
|
+
mockMatchMedia();
|
|
7
|
+
|
|
8
|
+
describe('Typeahead', () => {
|
|
9
|
+
it('supports `Field` for labeling', () => {
|
|
10
|
+
render(
|
|
11
|
+
<Field id="test" label="Tags">
|
|
12
|
+
<Typeahead id="test" name="test" options={[{ label: 'Test' }]} onChange={() => {}} />
|
|
13
|
+
</Field>,
|
|
14
|
+
);
|
|
15
|
+
expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Tags/);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('when no options are provided', () => {
|
|
19
|
+
it('does not render a dropdown when no options and no footer are provided', () => {
|
|
20
|
+
render(
|
|
21
|
+
<Field id="test" label="Tags">
|
|
22
|
+
<Typeahead id="test" name="test" options={[]} onChange={() => {}} />
|
|
23
|
+
</Field>,
|
|
24
|
+
);
|
|
25
|
+
expect(screen.queryByRole('menu')).not.toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
it('does render a dropdown when only a footer is provided', () => {
|
|
28
|
+
render(
|
|
29
|
+
<Field id="test" label="Tags">
|
|
30
|
+
<Typeahead id="test" name="test" options={[]} footer={<p>hello</p>} onChange={() => {}} />
|
|
31
|
+
</Field>,
|
|
32
|
+
);
|
|
33
|
+
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('renders input with placeholder', () => {
|
|
38
|
+
render(
|
|
39
|
+
<Typeahead id="test" name="test" options={[]} placeholder="Type here" onChange={() => {}} />,
|
|
40
|
+
);
|
|
41
|
+
expect(screen.getByPlaceholderText('Type here')).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('renders chips when multiple is true and selected has items', () => {
|
|
45
|
+
const initialValue = [{ label: 'Chip 1' }, { label: 'Chip 2' }];
|
|
46
|
+
render(
|
|
47
|
+
<Typeahead
|
|
48
|
+
id="test"
|
|
49
|
+
name="test"
|
|
50
|
+
options={[]}
|
|
51
|
+
multiple
|
|
52
|
+
initialValue={initialValue}
|
|
53
|
+
onChange={() => {}}
|
|
54
|
+
/>,
|
|
55
|
+
);
|
|
56
|
+
expect(screen.getByText('Chip 1')).toBeInTheDocument();
|
|
57
|
+
expect(screen.getByText('Chip 2')).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('calls onChange when selecting an option', () => {
|
|
61
|
+
const onChange = jest.fn();
|
|
62
|
+
render(
|
|
63
|
+
<Typeahead
|
|
64
|
+
id="test"
|
|
65
|
+
name="test"
|
|
66
|
+
options={[{ label: 'Option 1' }, { label: 'Option 2' }]}
|
|
67
|
+
minQueryLength={0}
|
|
68
|
+
onChange={onChange}
|
|
69
|
+
/>,
|
|
70
|
+
);
|
|
71
|
+
const input = screen.getByRole('combobox');
|
|
72
|
+
fireEvent.change(input, { target: { value: 'Option 1' } });
|
|
73
|
+
fireEvent.click(screen.getByText('Option 1'));
|
|
74
|
+
expect(onChange).toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('shows clear button when there is a value', () => {
|
|
78
|
+
render(
|
|
79
|
+
<Typeahead
|
|
80
|
+
id="test"
|
|
81
|
+
name="test"
|
|
82
|
+
options={[]}
|
|
83
|
+
initialValue={[{ label: 'Chip' }]}
|
|
84
|
+
onChange={() => {}}
|
|
85
|
+
/>,
|
|
86
|
+
);
|
|
87
|
+
expect(screen.getByRole('button', { name: /clear/i })).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('clears value when clear button is clicked', () => {
|
|
91
|
+
const onChange = jest.fn();
|
|
92
|
+
render(
|
|
93
|
+
<Typeahead
|
|
94
|
+
id="test"
|
|
95
|
+
name="test"
|
|
96
|
+
options={[]}
|
|
97
|
+
initialValue={[{ label: 'Chip' }]}
|
|
98
|
+
onChange={onChange}
|
|
99
|
+
/>,
|
|
100
|
+
);
|
|
101
|
+
fireEvent.click(screen.getByRole('button', { name: /clear/i }));
|
|
102
|
+
expect(onChange).toHaveBeenCalledWith([]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('shows InlineAlert when alert prop is provided', () => {
|
|
106
|
+
render(
|
|
107
|
+
<Typeahead
|
|
108
|
+
id="test"
|
|
109
|
+
name="test"
|
|
110
|
+
options={[]}
|
|
111
|
+
alert={{ message: 'Something went wrong', type: 'error' }}
|
|
112
|
+
onChange={() => {}}
|
|
113
|
+
/>,
|
|
114
|
+
);
|
|
115
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('calls onFocus when input is focused', () => {
|
|
119
|
+
const onFocus = jest.fn();
|
|
120
|
+
render(<Typeahead id="test" name="test" options={[]} onChange={() => {}} onFocus={onFocus} />);
|
|
121
|
+
fireEvent.focus(screen.getByRole('combobox'));
|
|
122
|
+
expect(onFocus).toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('calls onInputChange when input value changes', () => {
|
|
126
|
+
const onInputChange = jest.fn();
|
|
127
|
+
render(
|
|
128
|
+
<Typeahead
|
|
129
|
+
id="test"
|
|
130
|
+
name="test"
|
|
131
|
+
options={[]}
|
|
132
|
+
minQueryLength={0}
|
|
133
|
+
onChange={() => {}}
|
|
134
|
+
onInputChange={onInputChange}
|
|
135
|
+
/>,
|
|
136
|
+
);
|
|
137
|
+
fireEvent.change(screen.getByRole('combobox'), { target: { value: 'abc' } });
|
|
138
|
+
expect(onInputChange).toHaveBeenCalledWith('abc');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('calls onSearch when input value changes', async () => {
|
|
142
|
+
const onSearch = jest.fn();
|
|
143
|
+
render(
|
|
144
|
+
<Typeahead
|
|
145
|
+
id="test"
|
|
146
|
+
name="test"
|
|
147
|
+
options={[]}
|
|
148
|
+
minQueryLength={0}
|
|
149
|
+
onChange={() => {}}
|
|
150
|
+
onSearch={onSearch}
|
|
151
|
+
/>,
|
|
152
|
+
);
|
|
153
|
+
fireEvent.change(screen.getByRole('combobox'), { target: { value: 'abc' } });
|
|
154
|
+
// wait for debounce
|
|
155
|
+
await wait(500);
|
|
156
|
+
expect(onSearch).toHaveBeenCalledWith('abc');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('adds a new chip when allowNew and multiple are true and separator is pasted', () => {
|
|
160
|
+
const onChange = jest.fn();
|
|
161
|
+
render(
|
|
162
|
+
<Typeahead
|
|
163
|
+
id="test"
|
|
164
|
+
name="test"
|
|
165
|
+
options={[]}
|
|
166
|
+
allowNew
|
|
167
|
+
multiple
|
|
168
|
+
chipSeparators={[',']}
|
|
169
|
+
onChange={onChange}
|
|
170
|
+
/>,
|
|
171
|
+
);
|
|
172
|
+
const input = screen.getByRole('combobox');
|
|
173
|
+
fireEvent.paste(input, {
|
|
174
|
+
clipboardData: {
|
|
175
|
+
getData: () => 'foo,bar',
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
expect(onChange).toHaveBeenCalledWith(
|
|
179
|
+
expect.arrayContaining([{ label: 'foo' }, { label: 'bar' }]),
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { render, fireEvent, screen } from '../../test-utils';
|
|
2
|
+
import TypeaheadInput, { TypeaheadInputProps } from './TypeaheadInput';
|
|
3
|
+
import { TypeaheadOption } from '../Typeahead';
|
|
4
|
+
|
|
5
|
+
const defaultProps: TypeaheadInputProps<number> = {
|
|
6
|
+
id: 'test-id',
|
|
7
|
+
name: 'test-name',
|
|
8
|
+
typeaheadId: 'test-id',
|
|
9
|
+
value: '',
|
|
10
|
+
selected: [],
|
|
11
|
+
onChange: jest.fn(),
|
|
12
|
+
onKeyDown: jest.fn(),
|
|
13
|
+
onFocus: jest.fn(),
|
|
14
|
+
onPaste: jest.fn(),
|
|
15
|
+
autoComplete: 'off',
|
|
16
|
+
placeholder: 'Search...',
|
|
17
|
+
renderChip: jest.fn(),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe('TypeaheadInput', () => {
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
jest.clearAllMocks();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('renders input with placeholder', () => {
|
|
26
|
+
render(<TypeaheadInput {...defaultProps} />);
|
|
27
|
+
expect(screen.getByPlaceholderText('Search...')).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('renders with given value', () => {
|
|
31
|
+
render(<TypeaheadInput {...defaultProps} value="hello" />);
|
|
32
|
+
expect(screen.getByDisplayValue('hello')).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('calls onChange when input value changes', () => {
|
|
36
|
+
const onChange = jest.fn();
|
|
37
|
+
render(<TypeaheadInput {...defaultProps} onChange={onChange} />);
|
|
38
|
+
const input = screen.getByPlaceholderText('Search...');
|
|
39
|
+
fireEvent.change(input, { target: { value: 'test' } });
|
|
40
|
+
expect(onChange).toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('calls onFocus when input is focused', () => {
|
|
44
|
+
const onFocus = jest.fn();
|
|
45
|
+
render(<TypeaheadInput {...defaultProps} onFocus={onFocus} />);
|
|
46
|
+
const input = screen.getByPlaceholderText('Search...');
|
|
47
|
+
fireEvent.focus(input);
|
|
48
|
+
expect(onFocus).toHaveBeenCalled();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('calls onPaste when input is pasted into', () => {
|
|
52
|
+
const onPaste = jest.fn();
|
|
53
|
+
render(<TypeaheadInput {...defaultProps} onPaste={onPaste} />);
|
|
54
|
+
const input = screen.getByPlaceholderText('Search...');
|
|
55
|
+
fireEvent.paste(input, { clipboardData: { getData: () => 'pasted' } });
|
|
56
|
+
expect(onPaste).toHaveBeenCalled();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('calls onKeyDown when key is pressed', () => {
|
|
60
|
+
const onKeyDown = jest.fn();
|
|
61
|
+
render(<TypeaheadInput {...defaultProps} onKeyDown={onKeyDown} />);
|
|
62
|
+
const input = screen.getByPlaceholderText('Search...');
|
|
63
|
+
fireEvent.keyDown(input, { key: 'ArrowDown', code: 'ArrowDown' });
|
|
64
|
+
expect(onKeyDown).toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('renders chips when multiple is true and selected has items', () => {
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
69
|
+
const renderChip = jest.fn((chip, idx) => <span key={idx}>{chip.label}</span>);
|
|
70
|
+
const selected = [
|
|
71
|
+
{ label: 'Chip 1', value: 1 },
|
|
72
|
+
{ label: 'Chip 2', value: 2 },
|
|
73
|
+
];
|
|
74
|
+
render(
|
|
75
|
+
<TypeaheadInput {...defaultProps} multiple selected={selected} renderChip={renderChip} />,
|
|
76
|
+
);
|
|
77
|
+
expect(screen.getByText('Chip 1')).toBeInTheDocument();
|
|
78
|
+
expect(screen.getByText('Chip 2')).toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('does not show placeholder if multiple is true and selected has items', () => {
|
|
82
|
+
const selected: TypeaheadOption<number>[] = [{ label: 'Chip', value: 1 }];
|
|
83
|
+
render(<TypeaheadInput<number> {...defaultProps} multiple selected={selected} />);
|
|
84
|
+
expect(screen.queryByPlaceholderText('Search...')).not.toBeInTheDocument();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('applies input width style when multiple and selected has items', () => {
|
|
88
|
+
const selected = [{ label: 'Chip', value: 1 }];
|
|
89
|
+
const { container } = render(
|
|
90
|
+
<TypeaheadInput {...defaultProps} multiple selected={selected} value="test" />,
|
|
91
|
+
);
|
|
92
|
+
const input = container.querySelector('input');
|
|
93
|
+
expect(input?.style.width).not.toBe('');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('sets aria attributes correctly', () => {
|
|
97
|
+
render(<TypeaheadInput {...defaultProps} dropdownOpen ariaActivedescendant="option-1" />);
|
|
98
|
+
const input = screen.getByRole('combobox');
|
|
99
|
+
expect(input).toHaveAttribute('aria-expanded', 'true');
|
|
100
|
+
expect(input).toHaveAttribute('aria-haspopup', 'listbox');
|
|
101
|
+
expect(input).toHaveAttribute('aria-activedescendant', expect.stringContaining('option-1'));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { render, screen } from '../../test-utils';
|
|
2
|
+
import Highlight from './highlight';
|
|
3
|
+
|
|
4
|
+
describe('Highlight', () => {
|
|
5
|
+
it('renders value with highlighted query (case-insensitive)', () => {
|
|
6
|
+
render(<Highlight value="Hello World" query="world" />);
|
|
7
|
+
expect(screen.getByText('World')).toBeInTheDocument();
|
|
8
|
+
expect(screen.getByText('World').tagName).toBe('STRONG');
|
|
9
|
+
expect(screen.getByText('Hello', { exact: false })).toBeInTheDocument();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('renders value with highlighted query (case-sensitive in output)', () => {
|
|
13
|
+
render(<Highlight value="Hello World" query="HELLO" />);
|
|
14
|
+
expect(screen.getByText('Hello').tagName).toBe('STRONG');
|
|
15
|
+
expect(screen.getByText('World', { exact: false })).toBeInTheDocument();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('renders value without highlight if query not found', () => {
|
|
19
|
+
render(<Highlight value="Hello World" query="foo" />);
|
|
20
|
+
expect(screen.getByText('Hello World')).toBeInTheDocument();
|
|
21
|
+
expect(screen.queryByRole('strong')).not.toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('renders value as is if query is empty', () => {
|
|
25
|
+
render(<Highlight value="Hello World" query="" />);
|
|
26
|
+
expect(screen.getByText('Hello World')).toBeInTheDocument();
|
|
27
|
+
expect(screen.queryByRole('strong')).not.toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('renders value as is if value is empty', () => {
|
|
31
|
+
render(<Highlight value="" query="test" />);
|
|
32
|
+
expect(screen.queryByText(/./)).not.toBeInTheDocument();
|
|
33
|
+
expect(screen.queryByRole('strong')).not.toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('wraps content in span if className is provided', () => {
|
|
37
|
+
const { container } = render(
|
|
38
|
+
<Highlight value="Hello World" query="world" className="highlighted" />,
|
|
39
|
+
);
|
|
40
|
+
expect(container.querySelector('span.highlighted')).toBeInTheDocument();
|
|
41
|
+
expect(container.querySelector('strong')).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -6,6 +6,14 @@ import { postData } from './utils/postData';
|
|
|
6
6
|
|
|
7
7
|
jest.mock('./utils/asyncFileRead');
|
|
8
8
|
jest.mock('./utils/postData');
|
|
9
|
+
jest.mock('commonmark', () => ({
|
|
10
|
+
Parser: jest.fn().mockImplementation(() => ({
|
|
11
|
+
parse: jest.fn(() => ({})),
|
|
12
|
+
})),
|
|
13
|
+
HtmlRenderer: jest.fn().mockImplementation(() => ({
|
|
14
|
+
render: jest.fn(() => ''),
|
|
15
|
+
})),
|
|
16
|
+
}));
|
|
9
17
|
|
|
10
18
|
const TEST_FILE = new File(['test content'], 'test.png', { type: 'image/png' });
|
|
11
19
|
const INVALID_FILE = new File(['invalid content'], 'invalid.txt', { type: 'text/plain' });
|
|
@@ -76,6 +84,11 @@ describe('Upload Component', () => {
|
|
|
76
84
|
dispatchEvent: jest.fn(),
|
|
77
85
|
})),
|
|
78
86
|
});
|
|
87
|
+
props.onStart.mockReset();
|
|
88
|
+
props.onSuccess.mockReset();
|
|
89
|
+
props.onFailure.mockReset();
|
|
90
|
+
props.onCancel.mockReset();
|
|
91
|
+
props.onChange.mockReset();
|
|
79
92
|
});
|
|
80
93
|
|
|
81
94
|
afterEach(async () => {
|
|
@@ -292,4 +305,54 @@ describe('Upload Component', () => {
|
|
|
292
305
|
const errorIcon = await screen.findByLabelText(/Custom error label/i);
|
|
293
306
|
expect(errorIcon).toBeInTheDocument();
|
|
294
307
|
});
|
|
308
|
+
|
|
309
|
+
function runAnimationDelayTest(label: string, delay: number) {
|
|
310
|
+
test(`should respect a ${label} animationDelay`, async () => {
|
|
311
|
+
(asyncFileRead as jest.Mock).mockResolvedValue('mockBase64Image');
|
|
312
|
+
(postData as jest.Mock).mockResolvedValue('mockSuccessResponse');
|
|
313
|
+
|
|
314
|
+
const { container, unmount } = render(<Upload {...props} animationDelay={delay} />);
|
|
315
|
+
|
|
316
|
+
await act(async () => {
|
|
317
|
+
const droppableElement = await waitFor(() => container.querySelector('.droppable-area'));
|
|
318
|
+
const dataTransfer = new DataTransfer();
|
|
319
|
+
dataTransfer.items.add(TEST_FILE);
|
|
320
|
+
fireEvent.drop(droppableElement!, { dataTransfer });
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Advance half the delay, should still be processing
|
|
324
|
+
await act(async () => {
|
|
325
|
+
jest.advanceTimersByTime(delay / 2);
|
|
326
|
+
});
|
|
327
|
+
expect(container.querySelector('.droppable-processing')).toBeInTheDocument();
|
|
328
|
+
expect(container.querySelector('.droppable-complete')).not.toBeInTheDocument();
|
|
329
|
+
|
|
330
|
+
// Advance the rest of the delay
|
|
331
|
+
await act(async () => {
|
|
332
|
+
jest.advanceTimersByTime(delay / 2 + 10);
|
|
333
|
+
});
|
|
334
|
+
expect(container.querySelector('.droppable-complete')).toBeInTheDocument();
|
|
335
|
+
expect(container.querySelector('.droppable-processing')).not.toBeInTheDocument();
|
|
336
|
+
|
|
337
|
+
unmount();
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
runAnimationDelayTest('short', 50);
|
|
342
|
+
runAnimationDelayTest('long', 500);
|
|
343
|
+
|
|
344
|
+
test('should handle disabled state correctly', async () => {
|
|
345
|
+
const { container } = render(<Upload {...props} usDisabled />);
|
|
346
|
+
const droppableElement = await waitFor(() => container.querySelector('.droppable-area'));
|
|
347
|
+
|
|
348
|
+
const dataTransfer = new DataTransfer();
|
|
349
|
+
dataTransfer.items.add(TEST_FILE);
|
|
350
|
+
|
|
351
|
+
await act(async () => {
|
|
352
|
+
fireEvent.drop(droppableElement!, { dataTransfer });
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
expect(container.querySelector('.droppable-processing')).not.toBeInTheDocument();
|
|
356
|
+
expect(props.onStart).not.toHaveBeenCalled();
|
|
357
|
+
});
|
|
295
358
|
});
|
|
@@ -38,54 +38,3 @@ export const Basic: Story = {
|
|
|
38
38
|
onCancel: fn(),
|
|
39
39
|
},
|
|
40
40
|
} satisfies Story;
|
|
41
|
-
|
|
42
|
-
export const MaxSizes = () => {
|
|
43
|
-
const bKB = 1024;
|
|
44
|
-
const bMB = 1024 * bKB;
|
|
45
|
-
|
|
46
|
-
const dKB = 1000;
|
|
47
|
-
const dMB = 1000 * dKB;
|
|
48
|
-
|
|
49
|
-
const binarySizes = [
|
|
50
|
-
10 * bMB,
|
|
51
|
-
5 * bMB,
|
|
52
|
-
1 * bMB,
|
|
53
|
-
500 * bKB,
|
|
54
|
-
100 * bKB,
|
|
55
|
-
50 * bKB,
|
|
56
|
-
10 * bKB,
|
|
57
|
-
5 * bKB,
|
|
58
|
-
1 * bKB,
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
const decimalSizes = [
|
|
62
|
-
10 * dMB,
|
|
63
|
-
5 * dMB,
|
|
64
|
-
1 * dMB,
|
|
65
|
-
500 * dKB,
|
|
66
|
-
100 * dKB,
|
|
67
|
-
50 * dKB,
|
|
68
|
-
10 * dKB,
|
|
69
|
-
5 * dKB,
|
|
70
|
-
1 * dKB,
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<div style={{ display: 'flex', gap: '1rem' }}>
|
|
75
|
-
<div style={{ flex: 1 }}>
|
|
76
|
-
{binarySizes.map((maxSize) => (
|
|
77
|
-
<Field key={maxSize} label={`Max size: ${maxSize} bytes`}>
|
|
78
|
-
<Upload usLabel="Pick a file, any file" maxSize={maxSize} />
|
|
79
|
-
</Field>
|
|
80
|
-
))}
|
|
81
|
-
</div>
|
|
82
|
-
<div style={{ flex: 1 }}>
|
|
83
|
-
{decimalSizes.map((maxSize) => (
|
|
84
|
-
<Field key={maxSize} label={`Max size: ${maxSize} bytes`}>
|
|
85
|
-
<Upload usLabel="Pick a file, any file" maxSize={maxSize} />
|
|
86
|
-
</Field>
|
|
87
|
-
))}
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { fn } from '@storybook/test';
|
|
3
|
+
|
|
4
|
+
import Upload from '.';
|
|
5
|
+
import { MAX_SIZE_DEFAULT } from './Upload';
|
|
6
|
+
import { Field } from '../field/Field';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
component: Upload,
|
|
10
|
+
title: 'Forms/Upload/Tests',
|
|
11
|
+
argTypes: {
|
|
12
|
+
maxSize: {
|
|
13
|
+
control: {
|
|
14
|
+
type: 'number',
|
|
15
|
+
min: 0,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
} satisfies Meta<typeof Upload>;
|
|
20
|
+
|
|
21
|
+
export default meta;
|
|
22
|
+
|
|
23
|
+
export const MaxSizes = () => {
|
|
24
|
+
const bKB = 1024;
|
|
25
|
+
const bMB = 1024 * bKB;
|
|
26
|
+
|
|
27
|
+
const dKB = 1000;
|
|
28
|
+
const dMB = 1000 * dKB;
|
|
29
|
+
|
|
30
|
+
const binarySizes = [
|
|
31
|
+
10 * bMB,
|
|
32
|
+
5 * bMB,
|
|
33
|
+
1 * bMB,
|
|
34
|
+
500 * bKB,
|
|
35
|
+
100 * bKB,
|
|
36
|
+
50 * bKB,
|
|
37
|
+
10 * bKB,
|
|
38
|
+
5 * bKB,
|
|
39
|
+
1 * bKB,
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const decimalSizes = [
|
|
43
|
+
10 * dMB,
|
|
44
|
+
5 * dMB,
|
|
45
|
+
1 * dMB,
|
|
46
|
+
500 * dKB,
|
|
47
|
+
100 * dKB,
|
|
48
|
+
50 * dKB,
|
|
49
|
+
10 * dKB,
|
|
50
|
+
5 * dKB,
|
|
51
|
+
1 * dKB,
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div style={{ display: 'flex', gap: '1rem' }}>
|
|
56
|
+
<div style={{ flex: 1 }}>
|
|
57
|
+
{binarySizes.map((maxSize) => (
|
|
58
|
+
<Field key={maxSize} label={`Max size: ${maxSize} bytes`}>
|
|
59
|
+
<Upload usLabel="Pick a file, any file" maxSize={maxSize} />
|
|
60
|
+
</Field>
|
|
61
|
+
))}
|
|
62
|
+
</div>
|
|
63
|
+
<div style={{ flex: 1 }}>
|
|
64
|
+
{decimalSizes.map((maxSize) => (
|
|
65
|
+
<Field key={maxSize} label={`Max size: ${maxSize} bytes`}>
|
|
66
|
+
<Upload usLabel="Pick a file, any file" maxSize={maxSize} />
|
|
67
|
+
</Field>
|
|
68
|
+
))}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const AllVariants = () => {
|
|
75
|
+
return (
|
|
76
|
+
<div style={{ display: 'flex', gap: '1rem' }}>
|
|
77
|
+
<div style={{ flex: 1 }}>
|
|
78
|
+
<Field key="small" label="Small Upload">
|
|
79
|
+
<Upload usLabel="Pick a file, any file" size="sm" />
|
|
80
|
+
</Field>
|
|
81
|
+
<Field key="medium" label="Medium Upload">
|
|
82
|
+
<Upload usLabel="Pick a file, any file" size="md" />
|
|
83
|
+
</Field>
|
|
84
|
+
<Field key="large" label="Large Upload">
|
|
85
|
+
<Upload usLabel="Pick a file, any file" size="lg" />
|
|
86
|
+
</Field>
|
|
87
|
+
<Field key="disabled" label="Disabled Upload">
|
|
88
|
+
<Upload usLabel="Pick a file, any file" usDisabled />
|
|
89
|
+
</Field>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
};
|
package/src/upload/Upload.tsx
CHANGED
|
@@ -12,11 +12,6 @@ import { postData, asyncFileRead, isSizeValid, isTypeValid, getFileType } from '
|
|
|
12
12
|
import { PostDataFetcher, PostDataHTTPOptions, ResponseError } from './utils/postData/postData';
|
|
13
13
|
import { ProcessIndicatorStatus } from '../processIndicator';
|
|
14
14
|
|
|
15
|
-
/*
|
|
16
|
-
* This delay is required for the isError/isSuccess to be fired after isProcessing so the processIndicator, will be
|
|
17
|
-
* rendered first and then updated with the right status.
|
|
18
|
-
*/
|
|
19
|
-
const ANIMATION_FIX = 10;
|
|
20
15
|
export const MAX_SIZE_DEFAULT = 5000000;
|
|
21
16
|
|
|
22
17
|
export enum UploadStep {
|
|
@@ -85,7 +80,7 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
85
80
|
declare props: UploadProps & Required<Pick<UploadProps, keyof typeof Upload.defaultProps>>;
|
|
86
81
|
|
|
87
82
|
static defaultProps = {
|
|
88
|
-
animationDelay:
|
|
83
|
+
animationDelay: 300,
|
|
89
84
|
maxSize: MAX_SIZE_DEFAULT,
|
|
90
85
|
psButtonDisabled: false,
|
|
91
86
|
size: 'md',
|
|
@@ -160,41 +155,6 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
160
155
|
}
|
|
161
156
|
}
|
|
162
157
|
|
|
163
|
-
onAnimationCompleted = async (status: ProcessIndicatorStatus) => {
|
|
164
|
-
const { response, isProcessing, fileName } = this.state;
|
|
165
|
-
const { animationDelay } = this.props;
|
|
166
|
-
|
|
167
|
-
if (isProcessing && status === 'succeeded') {
|
|
168
|
-
const { onSuccess } = this.props;
|
|
169
|
-
this.timeouts = window.setTimeout(() => {
|
|
170
|
-
this.setState(
|
|
171
|
-
{
|
|
172
|
-
isProcessing: false,
|
|
173
|
-
isComplete: true,
|
|
174
|
-
},
|
|
175
|
-
onSuccess
|
|
176
|
-
? () => {
|
|
177
|
-
onSuccess(response as string | Response, fileName);
|
|
178
|
-
}
|
|
179
|
-
: undefined,
|
|
180
|
-
);
|
|
181
|
-
}, animationDelay);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (isProcessing && status === 'failed') {
|
|
185
|
-
const { onFailure } = this.props;
|
|
186
|
-
this.timeouts = window.setTimeout(() => {
|
|
187
|
-
this.setState(
|
|
188
|
-
{
|
|
189
|
-
isProcessing: false,
|
|
190
|
-
isComplete: true,
|
|
191
|
-
},
|
|
192
|
-
onFailure ? () => onFailure(response) : undefined,
|
|
193
|
-
);
|
|
194
|
-
}, animationDelay);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
158
|
asyncPost = async (file: File) => {
|
|
199
159
|
const { httpOptions, fetcher } = this.props;
|
|
200
160
|
if (httpOptions == null) {
|
|
@@ -209,15 +169,37 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
209
169
|
return postData(httpOptions, formData, fetcher);
|
|
210
170
|
};
|
|
211
171
|
|
|
212
|
-
|
|
213
|
-
|
|
172
|
+
handleUploadComplete = (type: 'success' | 'error', response: unknown) => {
|
|
173
|
+
const { animationDelay, onSuccess, onFailure } = this.props;
|
|
174
|
+
const { fileName } = this.state;
|
|
175
|
+
|
|
176
|
+
window.clearTimeout(this.timeouts);
|
|
214
177
|
this.timeouts = window.setTimeout(() => {
|
|
215
|
-
this.setState(
|
|
178
|
+
this.setState(
|
|
179
|
+
{
|
|
180
|
+
isProcessing: false,
|
|
181
|
+
isComplete: true,
|
|
182
|
+
},
|
|
183
|
+
() => {
|
|
184
|
+
if (type === 'success') {
|
|
185
|
+
onSuccess?.(response as string | Response, fileName);
|
|
186
|
+
} else {
|
|
187
|
+
onFailure?.(response);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
);
|
|
191
|
+
}, animationDelay);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
asyncResponse = (response: unknown, type: 'success' | 'error') => {
|
|
195
|
+
this.setState(
|
|
196
|
+
{
|
|
216
197
|
response,
|
|
217
198
|
isError: type === 'error',
|
|
218
199
|
isSuccess: type === 'success',
|
|
219
|
-
}
|
|
220
|
-
|
|
200
|
+
},
|
|
201
|
+
() => this.handleUploadComplete(type, response),
|
|
202
|
+
);
|
|
221
203
|
};
|
|
222
204
|
|
|
223
205
|
handleOnClear: React.MouseEventHandler<HTMLButtonElement> = (event) => {
|
|
@@ -395,8 +377,6 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
395
377
|
/>
|
|
396
378
|
)}
|
|
397
379
|
|
|
398
|
-
{/* Starts render the step when isSuccess is true so markup is there when css transition kicks in
|
|
399
|
-
css transition to work properly */}
|
|
400
380
|
{(isSuccess || isComplete) && !isError && (
|
|
401
381
|
<CompleteStep
|
|
402
382
|
fileName={fileName}
|
|
@@ -443,7 +423,6 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
443
423
|
psButtonText={psButtonText || intl.formatMessage(messages.psButtonText)}
|
|
444
424
|
psProcessingText={psProcessingText || intl.formatMessage(messages.psProcessingText)}
|
|
445
425
|
psButtonDisabled={psButtonDisabled}
|
|
446
|
-
onAnimationCompleted={async (status) => this.onAnimationCompleted(status)}
|
|
447
426
|
onClear={(event) => this.handleOnClear(event)}
|
|
448
427
|
/>
|
|
449
428
|
)}
|