@transferwise/components 45.15.0 → 45.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/i18n/en.json +8 -0
- package/build/index.esm.js +322 -318
- package/build/index.esm.js.map +1 -1
- package/build/index.js +321 -317
- package/build/index.js.map +1 -1
- package/build/main.css +1 -1
- package/build/styles/dateLookup/DateLookup.css +1 -1
- package/build/styles/main.css +1 -1
- package/build/types/avatarWrapper/AvatarWrapper.d.ts +14 -5
- package/build/types/avatarWrapper/AvatarWrapper.d.ts.map +1 -1
- package/build/types/common/Option/Option.d.ts.map +1 -1
- package/build/types/common/focusBoundary/FocusBoundary.d.ts +2 -2
- package/build/types/common/focusBoundary/FocusBoundary.d.ts.map +1 -1
- package/build/types/dateInput/DateInput.d.ts +2 -0
- package/build/types/dateInput/DateInput.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.messages.d.ts +65 -0
- package/build/types/dateLookup/DateLookup.messages.d.ts.map +1 -0
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts +3 -1
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts.map +1 -1
- package/build/types/dateLookup/tableLink/TableLink.d.ts +4 -26
- package/build/types/dateLookup/tableLink/TableLink.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts +4 -29
- package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts.map +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
- package/build/types/snackbar/Snackbar.d.ts.map +1 -1
- package/build/types/tabs/Tabs.d.ts.map +1 -1
- package/build/types/upload/steps/completeStep/completeStep.d.ts.map +1 -1
- package/build/types/upload/steps/processingStep/processingStep.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/accordion/AccordionItem/__snapshots__/AccordionItem.spec.js.snap +6 -6
- package/src/avatarWrapper/AvatarWrapper.tsx +20 -8
- package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +1 -1
- package/src/card/Card.spec.js +2 -2
- package/src/common/Option/Option.tsx +1 -7
- package/src/common/bottomSheet/__snapshots__/BottomSheet.spec.tsx.snap +8 -1
- package/src/common/focusBoundary/FocusBoundary.tsx +9 -32
- package/src/dateInput/DateInput.js +6 -0
- package/src/dateInput/DateInput.story.tsx +2 -0
- package/src/dateLookup/DateLookup.css +1 -1
- package/src/dateLookup/DateLookup.keyboardEvents.spec.js +3 -3
- package/src/dateLookup/DateLookup.less +4 -0
- package/src/dateLookup/DateLookup.messages.js +44 -0
- package/src/dateLookup/DateLookup.testingLibrary.spec.js +39 -0
- package/src/dateLookup/dateHeader/DateHeader.js +48 -26
- package/src/dateLookup/dateHeader/DateHeader.spec.js +37 -0
- package/src/dateLookup/dayCalendar/DayCalendar.js +3 -1
- package/src/dateLookup/dayCalendar/DayCalendar.spec.js +7 -1
- package/src/dateLookup/dayCalendar/table/DayCalendarTable.js +7 -3
- package/src/dateLookup/dayCalendar/table/DayCalendarTable.spec.js +1 -0
- package/src/dateLookup/monthCalendar/MonthCalendar.js +3 -1
- package/src/dateLookup/monthCalendar/MonthCalendar.spec.js +7 -1
- package/src/dateLookup/monthCalendar/table/MonthCalendarTable.spec.js +4 -5
- package/src/dateLookup/tableLink/TableLink.js +24 -3
- package/src/dateLookup/tableLink/TableLink.spec.js +60 -4
- package/src/dateLookup/yearCalendar/YearCalendar.js +16 -3
- package/src/dateLookup/yearCalendar/YearCalendar.spec.js +14 -1
- package/src/dateLookup/yearCalendar/table/YearCalendarTable.spec.js +4 -5
- package/src/i18n/en.json +8 -0
- package/src/inputs/SelectInput.story.tsx +14 -9
- package/src/main.css +1 -1
- package/src/phoneNumberInput/PhoneNumberInput.js +1 -0
- package/src/snackbar/Snackbar.js +6 -1
- package/src/snackbar/Snackbar.spec.js +1 -3
- package/src/tabs/Tabs.js +2 -1
- package/src/upload/Upload.js +1 -1
- package/src/upload/steps/completeStep/completeStep.js +4 -1
- package/src/upload/steps/processingStep/processingStep.js +1 -0
- package/src/uploadInput/uploadItem/UploadItem.tsx +1 -1
- package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts +0 -2
- package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts.map +0 -1
- package/build/types/common/focusBoundary/utils/index.d.ts +0 -3
- package/build/types/common/focusBoundary/utils/index.d.ts.map +0 -1
- package/build/types/common/focusBoundary/utils/resetFocus.d.ts +0 -2
- package/build/types/common/focusBoundary/utils/resetFocus.d.ts.map +0 -1
- package/src/common/focusBoundary/FocusBoundary.spec.tsx +0 -66
- package/src/common/focusBoundary/__snapshots__/FocusBoundary.spec.tsx.snap +0 -16
- package/src/common/focusBoundary/utils/getFocusableElements.js +0 -25
- package/src/common/focusBoundary/utils/getFocusableElements.spec.js +0 -51
- package/src/common/focusBoundary/utils/index.js +0 -2
- package/src/common/focusBoundary/utils/resetFocus.js +0 -23
- package/src/common/focusBoundary/utils/resetFocus.spec.js +0 -103
- package/src/snackbar/__snapshots__/Snackbar.spec.js.snap +0 -5
|
@@ -54,6 +54,14 @@ describe('DateLookup (events)', () => {
|
|
|
54
54
|
expect(getActiveYearButton()).toHaveFocus();
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
it('has aria-label for 20 years', () => {
|
|
58
|
+
openDateLookup();
|
|
59
|
+
clickDateButton();
|
|
60
|
+
|
|
61
|
+
expect(getButtonByAriaLabel('next 20 years')).toBeInTheDocument();
|
|
62
|
+
expect(getButtonByAriaLabel('previous 20 years')).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
57
65
|
it('switches to months', () => {
|
|
58
66
|
openDateLookup();
|
|
59
67
|
clickDateButton();
|
|
@@ -62,6 +70,15 @@ describe('DateLookup (events)', () => {
|
|
|
62
70
|
expect(getActiveMonthButton()).toHaveFocus();
|
|
63
71
|
});
|
|
64
72
|
|
|
73
|
+
it('has aria label for year', () => {
|
|
74
|
+
openDateLookup();
|
|
75
|
+
clickDateButton();
|
|
76
|
+
user.click(getActiveYearButton());
|
|
77
|
+
|
|
78
|
+
expect(getButtonByAriaLabel('next year')).toBeInTheDocument();
|
|
79
|
+
expect(getButtonByAriaLabel('previous year')).toBeInTheDocument();
|
|
80
|
+
});
|
|
81
|
+
|
|
65
82
|
it('switches to days', () => {
|
|
66
83
|
openDateLookup();
|
|
67
84
|
clickDateButton();
|
|
@@ -71,6 +88,16 @@ describe('DateLookup (events)', () => {
|
|
|
71
88
|
expect(getActiveDayButton()).toHaveFocus();
|
|
72
89
|
});
|
|
73
90
|
|
|
91
|
+
it('has aria label for month', () => {
|
|
92
|
+
openDateLookup();
|
|
93
|
+
clickDateButton();
|
|
94
|
+
user.click(getActiveYearButton());
|
|
95
|
+
user.click(getActiveMonthButton());
|
|
96
|
+
|
|
97
|
+
expect(getButtonByAriaLabel('next month')).toBeInTheDocument();
|
|
98
|
+
expect(getButtonByAriaLabel('previous month')).toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
|
|
74
101
|
it('updates selected date and closes', () => {
|
|
75
102
|
openDateLookup();
|
|
76
103
|
const d = new Date(2018, 11, 28);
|
|
@@ -81,6 +108,15 @@ describe('DateLookup (events)', () => {
|
|
|
81
108
|
expect(getOpenButton()).toHaveFocus();
|
|
82
109
|
});
|
|
83
110
|
|
|
111
|
+
it('has aria label on selected date', () => {
|
|
112
|
+
openDateLookup();
|
|
113
|
+
const d = new Date(2018, 11, 28);
|
|
114
|
+
const newDay = screen.getByText(`${d.getDate()}`);
|
|
115
|
+
user.click(newDay);
|
|
116
|
+
openDateLookup();
|
|
117
|
+
expect(screen.getByRole('button', { name: /selected day/i })).toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
|
|
84
120
|
describe('at extra small breakpoints', () => {
|
|
85
121
|
it('opens dateLookup using slider on small + 1 width', () => {
|
|
86
122
|
winWidth(Breakpoint.SMALL + 1);
|
|
@@ -148,6 +184,9 @@ describe('DateLookup (events)', () => {
|
|
|
148
184
|
return container.querySelector('button.tw-date-lookup-day-option.active');
|
|
149
185
|
};
|
|
150
186
|
|
|
187
|
+
const getButtonByAriaLabel = (ariaLabel) => {
|
|
188
|
+
return screen.getByRole('button', { name: ariaLabel });
|
|
189
|
+
};
|
|
151
190
|
const getClearButton = () => container.querySelector('.clear-btn');
|
|
152
191
|
const getOpenButton = () => container.querySelector('button.np-date-trigger');
|
|
153
192
|
const getDateButton = () => container.querySelector('button.tw-date-lookup-header-current');
|
|
@@ -1,43 +1,65 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
2
3
|
|
|
3
4
|
import Chevron from '../../chevron';
|
|
4
5
|
import { Position, Size } from '../../common';
|
|
6
|
+
import messages from '../DateLookup.messages';
|
|
5
7
|
|
|
6
8
|
const buttonClasses = 'btn-link p-a-0 text-no-decoration np-text-body-large-bold rounded-sm';
|
|
7
9
|
|
|
8
|
-
const DateHeader = ({ label, onLabelClick, onPreviousClick, onNextClick }) =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
10
|
+
const DateHeader = ({ label, onLabelClick, onPreviousClick, onNextClick, dateMode }) => {
|
|
11
|
+
const intl = useIntl();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div className="text-xs-center p-t-1 p-b-2 clearfix">
|
|
15
|
+
<div className="pull-left-single-direction">
|
|
16
|
+
<button
|
|
17
|
+
type="button"
|
|
18
|
+
className={`d-inline-flex ${buttonClasses}`}
|
|
19
|
+
aria-label={`${intl.formatMessage(messages.previous)} ${dateMode}`}
|
|
20
|
+
onClick={onPreviousClick}
|
|
21
|
+
>
|
|
22
|
+
<Chevron
|
|
23
|
+
orientation={Position.LEFT}
|
|
24
|
+
className="left-single-direction"
|
|
25
|
+
size={Size.MEDIUM}
|
|
26
|
+
/>
|
|
27
|
+
</button>
|
|
28
|
+
</div>
|
|
29
|
+
{label && (
|
|
30
|
+
<button
|
|
31
|
+
type="button"
|
|
32
|
+
className={`tw-date-lookup-header-current ${buttonClasses}`}
|
|
33
|
+
aria-label={intl.formatMessage(messages.goTo20YearView)}
|
|
34
|
+
onClick={onLabelClick}
|
|
35
|
+
>
|
|
36
|
+
{label}
|
|
37
|
+
</button>
|
|
38
|
+
)}
|
|
39
|
+
<div className="pull-right-single-direction">
|
|
40
|
+
<button
|
|
41
|
+
type="button"
|
|
42
|
+
className={`d-inline-flex ${buttonClasses}`}
|
|
43
|
+
aria-label={`${useIntl().formatMessage(messages.next)} ${dateMode}`}
|
|
44
|
+
onClick={onNextClick}
|
|
45
|
+
>
|
|
46
|
+
<Chevron
|
|
47
|
+
orientation={Position.RIGHT}
|
|
48
|
+
className="right-single-direction"
|
|
49
|
+
size={Size.MEDIUM}
|
|
50
|
+
/>
|
|
51
|
+
</button>
|
|
52
|
+
</div>
|
|
32
53
|
</div>
|
|
33
|
-
|
|
34
|
-
|
|
54
|
+
);
|
|
55
|
+
};
|
|
35
56
|
|
|
36
57
|
DateHeader.propTypes = {
|
|
37
58
|
label: PropTypes.string,
|
|
38
59
|
onLabelClick: PropTypes.func,
|
|
39
60
|
onPreviousClick: PropTypes.func.isRequired,
|
|
40
61
|
onNextClick: PropTypes.func.isRequired,
|
|
62
|
+
dateMode: PropTypes.string,
|
|
41
63
|
};
|
|
42
64
|
|
|
43
65
|
DateHeader.defaultProps = {
|
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
import { shallow } from 'enzyme';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
2
3
|
|
|
3
4
|
import Chevron from '../../chevron';
|
|
4
5
|
|
|
5
6
|
import DateHeader from '.';
|
|
6
7
|
|
|
8
|
+
jest.mock('react-intl');
|
|
9
|
+
jest.mock('../DateLookup.messages', () => ({
|
|
10
|
+
previous: {
|
|
11
|
+
id: 'neptune.DateLookup.previous',
|
|
12
|
+
defaultMessage: 'previous',
|
|
13
|
+
},
|
|
14
|
+
next: {
|
|
15
|
+
id: 'neptune.DateLookup.next',
|
|
16
|
+
defaultMessage: 'next',
|
|
17
|
+
},
|
|
18
|
+
goTo20YearView: {
|
|
19
|
+
id: 'neptune.DateLookup.goTo20YearView',
|
|
20
|
+
defaultMessage: 'go to 20 year view',
|
|
21
|
+
},
|
|
22
|
+
}));
|
|
7
23
|
describe('DateHeader', () => {
|
|
8
24
|
let component;
|
|
9
25
|
let props;
|
|
10
26
|
|
|
11
27
|
beforeEach(() => {
|
|
28
|
+
useIntl.mockReturnValue({
|
|
29
|
+
locale: 'en-GB',
|
|
30
|
+
formatMessage: (message) => message.defaultMessage,
|
|
31
|
+
defineMessages: (translations) => translations,
|
|
32
|
+
});
|
|
12
33
|
props = {
|
|
13
34
|
onPreviousClick: jest.fn(),
|
|
14
35
|
onNextClick: jest.fn(),
|
|
36
|
+
dateMode: 'year',
|
|
15
37
|
};
|
|
16
38
|
component = shallow(<DateHeader {...props} />);
|
|
17
39
|
});
|
|
@@ -36,9 +58,24 @@ describe('DateHeader', () => {
|
|
|
36
58
|
expect(props.onNextClick).toHaveBeenCalledTimes(1);
|
|
37
59
|
});
|
|
38
60
|
|
|
61
|
+
it('has aria-label on previous button', () => {
|
|
62
|
+
let previous = component.find('button').at(0);
|
|
63
|
+
expect(previous.prop('aria-label')).toBe('previous year');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('has aria-label on next button', () => {
|
|
67
|
+
let previous = component.find('button').at(1);
|
|
68
|
+
expect(previous.prop('aria-label')).toBe('next year');
|
|
69
|
+
});
|
|
70
|
+
|
|
39
71
|
describe('when label is provided', () => {
|
|
40
72
|
beforeEach(() => {
|
|
41
73
|
component.setProps({ label: 'trolo' });
|
|
74
|
+
useIntl.mockReturnValue({
|
|
75
|
+
locale: 'en-GB',
|
|
76
|
+
formatMessage: (message) => message,
|
|
77
|
+
defineMessages: (translations) => translations,
|
|
78
|
+
});
|
|
42
79
|
});
|
|
43
80
|
|
|
44
81
|
it('shows the label', () => {
|
|
@@ -4,6 +4,7 @@ import { PureComponent } from 'react';
|
|
|
4
4
|
import { injectIntl } from 'react-intl';
|
|
5
5
|
|
|
6
6
|
import { MonthFormat } from '../../common';
|
|
7
|
+
import messages from '../DateLookup.messages';
|
|
7
8
|
import DateHeader from '../dateHeader';
|
|
8
9
|
|
|
9
10
|
import DayCalendarTable from './table';
|
|
@@ -32,7 +33,7 @@ class DayCalendar extends PureComponent {
|
|
|
32
33
|
max,
|
|
33
34
|
viewMonth,
|
|
34
35
|
viewYear,
|
|
35
|
-
intl: { locale },
|
|
36
|
+
intl: { locale, formatMessage },
|
|
36
37
|
monthFormat,
|
|
37
38
|
onLabelClick,
|
|
38
39
|
onSelect,
|
|
@@ -44,6 +45,7 @@ class DayCalendar extends PureComponent {
|
|
|
44
45
|
month: monthFormat,
|
|
45
46
|
year: 'numeric',
|
|
46
47
|
})}
|
|
48
|
+
dateMode={formatMessage(messages.month)}
|
|
47
49
|
onLabelClick={onLabelClick}
|
|
48
50
|
onPreviousClick={this.selectPreviousMonth}
|
|
49
51
|
onNextClick={this.selectNextMonth}
|
|
@@ -8,11 +8,13 @@ import DayCalendarTable from './table';
|
|
|
8
8
|
import DayCalendar from '.';
|
|
9
9
|
|
|
10
10
|
const locale = 'en-GB';
|
|
11
|
+
const formatMessage = (id) => `${id}`;
|
|
11
12
|
jest.mock('react-intl', () => ({
|
|
12
13
|
injectIntl: (Component) =>
|
|
13
14
|
function (props) {
|
|
14
|
-
return <Component {...props} intl={{ locale }} />;
|
|
15
|
+
return <Component {...props} intl={{ locale, formatMessage }} />;
|
|
15
16
|
},
|
|
17
|
+
defineMessages: (translations) => translations,
|
|
16
18
|
}));
|
|
17
19
|
jest.mock('@transferwise/formatting', () => ({
|
|
18
20
|
formatDate: jest.fn().mockReturnValue('MonthName XXXX'),
|
|
@@ -73,6 +75,10 @@ describe('DayCalendar', () => {
|
|
|
73
75
|
expect(header().prop('onNextClick')).toBe(component.instance().selectNextMonth);
|
|
74
76
|
});
|
|
75
77
|
|
|
78
|
+
it('passes dateMode header component', () => {
|
|
79
|
+
expect(header().prop('dateMode')).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
76
82
|
it('calls onViewDateUpdate on previous month select', () => {
|
|
77
83
|
component.instance().selectPreviousMonth();
|
|
78
84
|
expect(props.onViewDateUpdate).toHaveBeenCalledWith({ year: 2018, month: 9 });
|
|
@@ -46,8 +46,8 @@ class DayCalendarTable extends PureComponent {
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
days = getDayNames(this.props.intl.locale, 'short');
|
|
49
|
-
|
|
50
49
|
daysShort = getDayNames(this.props.intl.locale, 'narrow');
|
|
50
|
+
daysLong = getDayNames(this.props.intl.locale, 'long');
|
|
51
51
|
|
|
52
52
|
selectDay = (day) => {
|
|
53
53
|
const { viewMonth, viewYear, onSelect } = this.props;
|
|
@@ -78,8 +78,12 @@ class DayCalendarTable extends PureComponent {
|
|
|
78
78
|
<tr>
|
|
79
79
|
{this.days.map((day, index) => (
|
|
80
80
|
<th key={day} className="text-xs-center np-text-body-default-bold">
|
|
81
|
-
<span className="hidden-xs">
|
|
82
|
-
|
|
81
|
+
<span className="hidden-xs">
|
|
82
|
+
<abbr title={this.daysLong[index]}>{day.slice(0, 3)}</abbr>
|
|
83
|
+
</span>
|
|
84
|
+
<span className="visible-xs-inline-block">
|
|
85
|
+
<abbr title={this.daysLong[index]}>{this.daysShort[index].slice(0, 2)}</abbr>
|
|
86
|
+
</span>
|
|
83
87
|
</th>
|
|
84
88
|
))}
|
|
85
89
|
</tr>
|
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { PureComponent } from 'react';
|
|
4
4
|
import { injectIntl } from 'react-intl';
|
|
5
5
|
|
|
6
|
+
import messages from '../DateLookup.messages';
|
|
6
7
|
import DateHeader from '../dateHeader';
|
|
7
8
|
|
|
8
9
|
import MonthCalendarTable from './table';
|
|
@@ -27,13 +28,14 @@ class MonthCalendar extends PureComponent {
|
|
|
27
28
|
min,
|
|
28
29
|
max,
|
|
29
30
|
viewYear,
|
|
30
|
-
intl: { locale },
|
|
31
|
+
intl: { locale, formatMessage },
|
|
31
32
|
placeholder,
|
|
32
33
|
onLabelClick,
|
|
33
34
|
} = this.props;
|
|
34
35
|
return (
|
|
35
36
|
<>
|
|
36
37
|
<DateHeader
|
|
38
|
+
dateMode={formatMessage(messages.year)}
|
|
37
39
|
label={formatDate(new Date(viewYear, 0), locale, { year: 'numeric' })}
|
|
38
40
|
onLabelClick={onLabelClick}
|
|
39
41
|
onPreviousClick={this.selectPreviousYear}
|
|
@@ -8,11 +8,13 @@ import MonthCalendarTable from './table';
|
|
|
8
8
|
import MonthCalendar from '.';
|
|
9
9
|
|
|
10
10
|
const defaultLocale = 'en-GB';
|
|
11
|
+
const formatMessage = (id) => `${id}`;
|
|
11
12
|
jest.mock('react-intl', () => ({
|
|
12
13
|
injectIntl: (Component) =>
|
|
13
14
|
function (props) {
|
|
14
|
-
return <Component {...props} intl={{ locale: defaultLocale }} />;
|
|
15
|
+
return <Component {...props} intl={{ locale: defaultLocale, formatMessage }} />;
|
|
15
16
|
},
|
|
17
|
+
defineMessages: (translations) => translations,
|
|
16
18
|
}));
|
|
17
19
|
jest.mock('@transferwise/formatting', () => ({
|
|
18
20
|
formatDate: jest.fn().mockReturnValue('XXXX'),
|
|
@@ -62,6 +64,10 @@ describe('MonthCalendar', () => {
|
|
|
62
64
|
expect(header().prop('onNextClick')).toBe(component.instance().selectNextYear);
|
|
63
65
|
});
|
|
64
66
|
|
|
67
|
+
it('passes dateMode header component', () => {
|
|
68
|
+
expect(header().prop('dateMode')).toBeDefined();
|
|
69
|
+
});
|
|
70
|
+
|
|
65
71
|
it('calls onViewDateUpdate on previous year select', () => {
|
|
66
72
|
component.instance().selectPreviousYear();
|
|
67
73
|
expect(props.onViewDateUpdate).toHaveBeenCalledWith({ year: 2017 });
|
|
@@ -2,8 +2,6 @@ import * as formatting from '@transferwise/formatting';
|
|
|
2
2
|
import { shallow } from 'enzyme';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
4
|
|
|
5
|
-
import TableLink from '../../tableLink';
|
|
6
|
-
|
|
7
5
|
import MonthCalendarTable from '.';
|
|
8
6
|
|
|
9
7
|
jest.mock('react-intl');
|
|
@@ -29,7 +27,7 @@ describe('MonthCalendarTable', () => {
|
|
|
29
27
|
it('generates 3x4 table', () => {
|
|
30
28
|
expect(component.find('tbody tr')).toHaveLength(3);
|
|
31
29
|
expect(component.find('tbody td')).toHaveLength(12);
|
|
32
|
-
expect(
|
|
30
|
+
expect(getTableLink()).toHaveLength(12);
|
|
33
31
|
});
|
|
34
32
|
|
|
35
33
|
it('starts with month 0 and end with 11', () => {
|
|
@@ -73,7 +71,7 @@ describe('MonthCalendarTable', () => {
|
|
|
73
71
|
selectedDate: today,
|
|
74
72
|
viewYear: today.getFullYear(),
|
|
75
73
|
});
|
|
76
|
-
expect(
|
|
74
|
+
expect(getTableLink().find({ today: true }).prop('item')).toBe(today.getMonth());
|
|
77
75
|
});
|
|
78
76
|
|
|
79
77
|
it('passes onSelect to TableLink', () => {
|
|
@@ -84,5 +82,6 @@ describe('MonthCalendarTable', () => {
|
|
|
84
82
|
expect(component.find('.sr-only').text()).toBe('Enter date..');
|
|
85
83
|
});
|
|
86
84
|
|
|
87
|
-
const getTableLinkAt = (i) => component.find(
|
|
85
|
+
const getTableLinkAt = (i) => component.find('[title="MonthName"]').at(i);
|
|
86
|
+
const getTableLink = () => component.find('[title="MonthName"]');
|
|
88
87
|
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import { PureComponent } from 'react';
|
|
3
|
+
import { injectIntl } from 'react-intl';
|
|
4
|
+
|
|
5
|
+
import messages from '../DateLookup.messages';
|
|
3
6
|
|
|
4
7
|
class TableLink extends PureComponent {
|
|
5
8
|
onClick = (event) => {
|
|
@@ -9,8 +12,26 @@ class TableLink extends PureComponent {
|
|
|
9
12
|
}
|
|
10
13
|
};
|
|
11
14
|
|
|
15
|
+
calculateAriaLabel = (longTitle, title, active, type, formatMessage) => {
|
|
16
|
+
if (active) {
|
|
17
|
+
return `${longTitle || title}, ${formatMessage(messages.selected)} ${formatMessage(
|
|
18
|
+
messages[type],
|
|
19
|
+
)}`;
|
|
20
|
+
}
|
|
21
|
+
return longTitle || title;
|
|
22
|
+
};
|
|
23
|
+
|
|
12
24
|
render() {
|
|
13
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
item,
|
|
27
|
+
type,
|
|
28
|
+
title,
|
|
29
|
+
longTitle,
|
|
30
|
+
active,
|
|
31
|
+
disabled,
|
|
32
|
+
today,
|
|
33
|
+
intl: { formatMessage },
|
|
34
|
+
} = this.props;
|
|
14
35
|
return (
|
|
15
36
|
<>
|
|
16
37
|
<button
|
|
@@ -19,7 +40,7 @@ class TableLink extends PureComponent {
|
|
|
19
40
|
today ? 'today' : ''
|
|
20
41
|
} np-text-body-default-bold`}
|
|
21
42
|
disabled={disabled}
|
|
22
|
-
aria-label={longTitle}
|
|
43
|
+
aria-label={this.calculateAriaLabel(longTitle, title, active, type, formatMessage)}
|
|
23
44
|
onClick={this.onClick}
|
|
24
45
|
>
|
|
25
46
|
{title || item}
|
|
@@ -45,4 +66,4 @@ TableLink.defaultProps = {
|
|
|
45
66
|
longTitle: null,
|
|
46
67
|
};
|
|
47
68
|
|
|
48
|
-
export default TableLink;
|
|
69
|
+
export default injectIntl(TableLink);
|
|
@@ -2,24 +2,60 @@ import { shallow } from 'enzyme';
|
|
|
2
2
|
|
|
3
3
|
import TableLink from '.';
|
|
4
4
|
|
|
5
|
+
const formatMessage = (id) => id.defaultMessage;
|
|
6
|
+
jest.mock('react-intl', () => ({
|
|
7
|
+
injectIntl: (Component) =>
|
|
8
|
+
function (props) {
|
|
9
|
+
return <Component {...props} intl={{ formatMessage }} />;
|
|
10
|
+
},
|
|
11
|
+
defineMessages: (translations) => translations,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
jest.mock('../DateLookup.messages', () => ({
|
|
15
|
+
selected: {
|
|
16
|
+
id: 'neptune.DateLookup.selected',
|
|
17
|
+
defaultMessage: 'selected',
|
|
18
|
+
},
|
|
19
|
+
day: {
|
|
20
|
+
id: 'neptune.DateLookup.day',
|
|
21
|
+
defaultMessage: 'day',
|
|
22
|
+
},
|
|
23
|
+
month: {
|
|
24
|
+
id: 'neptune.DateLookup.month',
|
|
25
|
+
defaultMessage: 'month',
|
|
26
|
+
},
|
|
27
|
+
year: {
|
|
28
|
+
id: 'neptune.DateLookup.year',
|
|
29
|
+
defaultMessage: 'year',
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
jest.mock('react-intl', () => ({
|
|
33
|
+
injectIntl: (Component) =>
|
|
34
|
+
function (props) {
|
|
35
|
+
return <Component {...props} intl={{ formatMessage }} />;
|
|
36
|
+
},
|
|
37
|
+
}));
|
|
38
|
+
|
|
5
39
|
describe('TableLink', () => {
|
|
6
40
|
let component;
|
|
7
41
|
let props;
|
|
8
42
|
|
|
9
43
|
beforeEach(() => {
|
|
10
44
|
props = {
|
|
11
|
-
item:
|
|
45
|
+
item: 12,
|
|
12
46
|
type: 'day',
|
|
13
47
|
active: false,
|
|
14
48
|
disabled: false,
|
|
15
49
|
today: false,
|
|
16
50
|
onClick: jest.fn(),
|
|
51
|
+
title: '12',
|
|
52
|
+
longTitle: '12/12/1212',
|
|
17
53
|
};
|
|
18
|
-
component = shallow(<TableLink {...props} />);
|
|
54
|
+
component = shallow(<TableLink {...props} />).dive();
|
|
19
55
|
});
|
|
20
56
|
|
|
21
57
|
it('shows item value', () => {
|
|
22
|
-
expect(button().text()).toBe('
|
|
58
|
+
expect(button().text()).toBe('12');
|
|
23
59
|
});
|
|
24
60
|
|
|
25
61
|
it('shows title when provided (instead of item value)', () => {
|
|
@@ -49,7 +85,27 @@ describe('TableLink', () => {
|
|
|
49
85
|
|
|
50
86
|
it('calls click handler on click', () => {
|
|
51
87
|
button().simulate('click', { preventDefault: () => {} });
|
|
52
|
-
expect(props.onClick).toHaveBeenCalledWith(
|
|
88
|
+
expect(props.onClick).toHaveBeenCalledWith(12);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('adds aria label to selected day', () => {
|
|
92
|
+
expect(button().hasClass('active')).toBe(false);
|
|
93
|
+
component.setProps({ active: true });
|
|
94
|
+
expect(button().prop('aria-label')).toBe('12/12/1212, selected day');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('adds aria label to selected month', () => {
|
|
98
|
+
component.setProps({ type: 'month' });
|
|
99
|
+
expect(button().hasClass('active')).toBe(false);
|
|
100
|
+
component.setProps({ active: true });
|
|
101
|
+
expect(button().prop('aria-label')).toBe('12/12/1212, selected month');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('adds aria label to selected year', () => {
|
|
105
|
+
component.setProps({ type: 'year' });
|
|
106
|
+
expect(button().hasClass('active')).toBe(false);
|
|
107
|
+
component.setProps({ active: true });
|
|
108
|
+
expect(button().prop('aria-label')).toBe('12/12/1212, selected year');
|
|
53
109
|
});
|
|
54
110
|
|
|
55
111
|
const button = () => component.find('button');
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import { PureComponent } from 'react';
|
|
3
|
+
import { injectIntl } from 'react-intl';
|
|
3
4
|
|
|
5
|
+
import messages from '../DateLookup.messages';
|
|
4
6
|
import DateHeader from '../dateHeader';
|
|
5
7
|
|
|
6
8
|
import YearCalendarTable from './table';
|
|
@@ -20,10 +22,21 @@ class YearCalendar extends PureComponent {
|
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
render() {
|
|
23
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
selectedDate,
|
|
27
|
+
min,
|
|
28
|
+
max,
|
|
29
|
+
viewYear,
|
|
30
|
+
placeholder,
|
|
31
|
+
intl: { formatMessage },
|
|
32
|
+
} = this.props;
|
|
24
33
|
return (
|
|
25
34
|
<>
|
|
26
|
-
<DateHeader
|
|
35
|
+
<DateHeader
|
|
36
|
+
dateMode={formatMessage(messages.twentyYears)}
|
|
37
|
+
onPreviousClick={this.selectPreviousYears}
|
|
38
|
+
onNextClick={this.selectNextYears}
|
|
39
|
+
/>
|
|
27
40
|
<YearCalendarTable
|
|
28
41
|
{...{ selectedDate, min, max, viewYear, placeholder }}
|
|
29
42
|
onSelect={this.onYearSelect}
|
|
@@ -49,4 +62,4 @@ YearCalendar.defaultProps = {
|
|
|
49
62
|
max: null,
|
|
50
63
|
};
|
|
51
64
|
|
|
52
|
-
export default YearCalendar;
|
|
65
|
+
export default injectIntl(YearCalendar);
|
|
@@ -6,6 +6,15 @@ import YearCalendarTable from './table';
|
|
|
6
6
|
|
|
7
7
|
import YearCalendar from '.';
|
|
8
8
|
|
|
9
|
+
const formatMessage = (id) => `${id}`;
|
|
10
|
+
jest.mock('react-intl', () => ({
|
|
11
|
+
injectIntl: (Component) =>
|
|
12
|
+
function (props) {
|
|
13
|
+
return <Component {...props} intl={{ formatMessage }} />;
|
|
14
|
+
},
|
|
15
|
+
defineMessages: (translations) => translations,
|
|
16
|
+
}));
|
|
17
|
+
|
|
9
18
|
describe('YearCalendar', () => {
|
|
10
19
|
const selectedDate = new Date(2018, 11, 27);
|
|
11
20
|
const min = new Date(1990, 11, 27);
|
|
@@ -23,7 +32,7 @@ describe('YearCalendar', () => {
|
|
|
23
32
|
onSelect: jest.fn(),
|
|
24
33
|
onViewDateUpdate: jest.fn(),
|
|
25
34
|
};
|
|
26
|
-
component = shallow(<YearCalendar {...props} />);
|
|
35
|
+
component = shallow(<YearCalendar {...props} />).dive();
|
|
27
36
|
});
|
|
28
37
|
|
|
29
38
|
it('shows the header', () => {
|
|
@@ -38,6 +47,10 @@ describe('YearCalendar', () => {
|
|
|
38
47
|
expect(header().prop('onNextClick')).toBe(component.instance().selectNextYears);
|
|
39
48
|
});
|
|
40
49
|
|
|
50
|
+
it('passes dateMode header component', () => {
|
|
51
|
+
expect(header().prop('dateMode')).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
41
54
|
it('calls onViewDateUpdate on previous years select', () => {
|
|
42
55
|
component.instance().selectPreviousYears();
|
|
43
56
|
expect(props.onViewDateUpdate).toHaveBeenCalledWith({ year: 1998 });
|
|
@@ -2,8 +2,6 @@ import * as formatting from '@transferwise/formatting';
|
|
|
2
2
|
import { shallow } from 'enzyme';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
4
|
|
|
5
|
-
import TableLink from '../../tableLink';
|
|
6
|
-
|
|
7
5
|
import YearCalendarTable from '.';
|
|
8
6
|
|
|
9
7
|
jest.mock('react-intl');
|
|
@@ -29,7 +27,7 @@ describe('YearCalendarTable', () => {
|
|
|
29
27
|
it('generates 5x4 table', () => {
|
|
30
28
|
expect(component.find('tbody tr')).toHaveLength(5);
|
|
31
29
|
expect(component.find('tbody td')).toHaveLength(20);
|
|
32
|
-
expect(
|
|
30
|
+
expect(getTableLink()).toHaveLength(20);
|
|
33
31
|
});
|
|
34
32
|
|
|
35
33
|
it('starts with year 2000, 2020, 2040 etc', () => {
|
|
@@ -81,7 +79,7 @@ describe('YearCalendarTable', () => {
|
|
|
81
79
|
selectedDate: today,
|
|
82
80
|
viewYear: today.getFullYear(),
|
|
83
81
|
});
|
|
84
|
-
expect(
|
|
82
|
+
expect(getTableLink().find({ today: true }).prop('item')).toBe(today.getFullYear());
|
|
85
83
|
});
|
|
86
84
|
|
|
87
85
|
it('passes onSelect to TableLink', () => {
|
|
@@ -92,5 +90,6 @@ describe('YearCalendarTable', () => {
|
|
|
92
90
|
expect(component.find('.sr-only').text()).toBe('Enter date..');
|
|
93
91
|
});
|
|
94
92
|
|
|
95
|
-
const getTableLinkAt = (i) => component.find(
|
|
93
|
+
const getTableLinkAt = (i) => component.find('[type="year"]').at(i);
|
|
94
|
+
const getTableLink = () => component.find('[type="year"]');
|
|
96
95
|
});
|
package/src/i18n/en.json
CHANGED
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
"neptune.DateInput.day.label": "Day",
|
|
6
6
|
"neptune.DateInput.month.label": "Month",
|
|
7
7
|
"neptune.DateInput.year.label": "Year",
|
|
8
|
+
"neptune.DateLookup.day": "day",
|
|
9
|
+
"neptune.DateLookup.goTo20YearView": "Go to 20 year view",
|
|
10
|
+
"neptune.DateLookup.month": "month",
|
|
11
|
+
"neptune.DateLookup.next": "next",
|
|
12
|
+
"neptune.DateLookup.previous": "previous",
|
|
13
|
+
"neptune.DateLookup.selected": "selected",
|
|
14
|
+
"neptune.DateLookup.twentyYears": "20 years",
|
|
15
|
+
"neptune.DateLookup.year": "year",
|
|
8
16
|
"neptune.Link.opensInNewTab": "(opens in new tab)",
|
|
9
17
|
"neptune.MoneyInput.Select.placeholder": "Select an option...",
|
|
10
18
|
"neptune.Select.searchPlaceholder": "Search...",
|