@transferwise/components 45.14.2 → 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.
Files changed (160) hide show
  1. package/build/i18n/en.json +8 -0
  2. package/build/index.esm.js +1001 -367
  3. package/build/index.esm.js.map +1 -1
  4. package/build/index.js +1003 -366
  5. package/build/index.js.map +1 -1
  6. package/build/main.css +1 -1
  7. package/build/styles/common/closeButton/CloseButton.css +1 -1
  8. package/build/styles/dateLookup/DateLookup.css +1 -1
  9. package/build/styles/inputs/Input.css +1 -1
  10. package/build/styles/inputs/InputGroup.css +1 -1
  11. package/build/styles/inputs/SelectInput.css +1 -0
  12. package/build/styles/inputs/TextArea.css +1 -1
  13. package/build/styles/main.css +1 -1
  14. package/build/styles/promoCard/PromoCard.css +1 -1
  15. package/build/styles/stepper/Stepper.css +1 -1
  16. package/build/types/avatarWrapper/AvatarWrapper.d.ts +14 -5
  17. package/build/types/avatarWrapper/AvatarWrapper.d.ts.map +1 -1
  18. package/build/types/common/Option/Option.d.ts.map +1 -1
  19. package/build/types/common/focusBoundary/FocusBoundary.d.ts +2 -2
  20. package/build/types/common/focusBoundary/FocusBoundary.d.ts.map +1 -1
  21. package/build/types/common/hooks/useMedia.d.ts +2 -0
  22. package/build/types/common/hooks/useMedia.d.ts.map +1 -0
  23. package/build/types/common/hooks/useScreenSize.d.ts +3 -0
  24. package/build/types/common/hooks/useScreenSize.d.ts.map +1 -0
  25. package/build/types/common/preventScroll/PreventScroll.d.ts +2 -0
  26. package/build/types/common/preventScroll/PreventScroll.d.ts.map +1 -0
  27. package/build/types/dateInput/DateInput.d.ts +2 -0
  28. package/build/types/dateInput/DateInput.d.ts.map +1 -1
  29. package/build/types/dateLookup/DateLookup.messages.d.ts +65 -0
  30. package/build/types/dateLookup/DateLookup.messages.d.ts.map +1 -0
  31. package/build/types/dateLookup/dateHeader/DateHeader.d.ts +3 -1
  32. package/build/types/dateLookup/dateHeader/DateHeader.d.ts.map +1 -1
  33. package/build/types/dateLookup/dateTrigger/DateTrigger.messages.d.ts +7 -7
  34. package/build/types/dateLookup/dateTrigger/DateTrigger.messages.d.ts.map +1 -1
  35. package/build/types/dateLookup/tableLink/TableLink.d.ts +4 -26
  36. package/build/types/dateLookup/tableLink/TableLink.d.ts.map +1 -1
  37. package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts +4 -29
  38. package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts.map +1 -1
  39. package/build/types/index.d.ts +4 -0
  40. package/build/types/index.d.ts.map +1 -1
  41. package/build/types/inputs/Input.d.ts +1 -0
  42. package/build/types/inputs/Input.d.ts.map +1 -1
  43. package/build/types/inputs/SearchInput.d.ts +10 -0
  44. package/build/types/inputs/SearchInput.d.ts.map +1 -0
  45. package/build/types/inputs/SelectInput.d.ts +41 -0
  46. package/build/types/inputs/SelectInput.d.ts.map +1 -0
  47. package/build/types/inputs/_BottomSheet.d.ts +17 -0
  48. package/build/types/inputs/_BottomSheet.d.ts.map +1 -0
  49. package/build/types/inputs/_ButtonInput.d.ts +6 -0
  50. package/build/types/inputs/_ButtonInput.d.ts.map +1 -0
  51. package/build/types/inputs/_Popover.d.ts +18 -0
  52. package/build/types/inputs/_Popover.d.ts.map +1 -0
  53. package/build/types/inputs/_common.d.ts.map +1 -1
  54. package/build/types/logo/Logo.d.ts.map +1 -1
  55. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  56. package/build/types/snackbar/Snackbar.d.ts.map +1 -1
  57. package/build/types/stepper/Stepper.d.ts.map +1 -1
  58. package/build/types/tabs/Tabs.d.ts.map +1 -1
  59. package/build/types/tile/Tile.d.ts.map +1 -1
  60. package/build/types/upload/steps/completeStep/completeStep.d.ts.map +1 -1
  61. package/build/types/upload/steps/processingStep/processingStep.d.ts.map +1 -1
  62. package/build/types/utilities/wrapInFragment.d.ts +3 -0
  63. package/build/types/utilities/wrapInFragment.d.ts.map +1 -0
  64. package/package.json +27 -20
  65. package/src/accordion/AccordionItem/__snapshots__/AccordionItem.spec.js.snap +6 -6
  66. package/src/avatarWrapper/AvatarWrapper.tsx +20 -8
  67. package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +1 -1
  68. package/src/card/Card.spec.js +2 -2
  69. package/src/common/Option/Option.tsx +1 -7
  70. package/src/common/bottomSheet/__snapshots__/BottomSheet.spec.tsx.snap +8 -1
  71. package/src/common/closeButton/CloseButton.css +1 -1
  72. package/src/common/focusBoundary/FocusBoundary.tsx +9 -32
  73. package/src/common/hooks/useMedia.spec.ts +39 -0
  74. package/src/common/hooks/useMedia.ts +15 -0
  75. package/src/common/hooks/useScreenSize.ts +7 -0
  76. package/src/common/preventScroll/PreventScroll.tsx +6 -0
  77. package/src/dateInput/DateInput.js +6 -0
  78. package/src/dateInput/DateInput.story.tsx +2 -0
  79. package/src/dateLookup/DateLookup.css +1 -1
  80. package/src/dateLookup/DateLookup.keyboardEvents.spec.js +3 -3
  81. package/src/dateLookup/DateLookup.less +4 -0
  82. package/src/dateLookup/DateLookup.messages.js +44 -0
  83. package/src/dateLookup/DateLookup.testingLibrary.spec.js +39 -0
  84. package/src/dateLookup/dateHeader/DateHeader.js +48 -26
  85. package/src/dateLookup/dateHeader/DateHeader.spec.js +37 -0
  86. package/src/dateLookup/dayCalendar/DayCalendar.js +3 -1
  87. package/src/dateLookup/dayCalendar/DayCalendar.spec.js +7 -1
  88. package/src/dateLookup/dayCalendar/table/DayCalendarTable.js +7 -3
  89. package/src/dateLookup/dayCalendar/table/DayCalendarTable.spec.js +1 -0
  90. package/src/dateLookup/monthCalendar/MonthCalendar.js +3 -1
  91. package/src/dateLookup/monthCalendar/MonthCalendar.spec.js +7 -1
  92. package/src/dateLookup/monthCalendar/table/MonthCalendarTable.spec.js +4 -5
  93. package/src/dateLookup/tableLink/TableLink.js +24 -3
  94. package/src/dateLookup/tableLink/TableLink.spec.js +60 -4
  95. package/src/dateLookup/yearCalendar/YearCalendar.js +16 -3
  96. package/src/dateLookup/yearCalendar/YearCalendar.spec.js +14 -1
  97. package/src/dateLookup/yearCalendar/table/YearCalendarTable.spec.js +4 -5
  98. package/src/decision/Decision.story.js +11 -11
  99. package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +12 -12
  100. package/src/i18n/en.json +9 -0
  101. package/src/index.ts +8 -0
  102. package/src/inputs/Input.css +1 -1
  103. package/src/inputs/Input.less +14 -0
  104. package/src/inputs/Input.tsx +6 -2
  105. package/src/inputs/InputGroup.css +1 -1
  106. package/src/inputs/InputGroup.less +5 -0
  107. package/src/inputs/SearchInput.story.tsx +40 -0
  108. package/src/inputs/SearchInput.tsx +35 -0
  109. package/src/inputs/SelectInput.css +1 -0
  110. package/src/inputs/SelectInput.less +183 -0
  111. package/src/inputs/SelectInput.spec.tsx +120 -0
  112. package/src/inputs/SelectInput.story.tsx +264 -0
  113. package/src/inputs/SelectInput.tsx +565 -0
  114. package/src/inputs/TextArea.css +1 -1
  115. package/src/inputs/TextArea.less +5 -0
  116. package/src/inputs/_BottomSheet.less +107 -0
  117. package/src/inputs/_BottomSheet.tsx +128 -0
  118. package/src/inputs/_ButtonInput.less +7 -0
  119. package/src/inputs/_ButtonInput.tsx +27 -0
  120. package/src/inputs/_Popover.less +38 -0
  121. package/src/inputs/_Popover.tsx +118 -0
  122. package/src/inputs/_common.less +0 -4
  123. package/src/inputs/_common.ts +0 -1
  124. package/src/logo/Logo.js +3 -21
  125. package/src/logo/__snapshots__/Logo.spec.js.snap +78 -30
  126. package/src/main.css +1 -1
  127. package/src/main.less +4 -0
  128. package/src/phoneNumberInput/PhoneNumberInput.js +1 -0
  129. package/src/promoCard/PromoCard.css +1 -1
  130. package/src/select/searchBox/__snapshots__/SearchBox.spec.js.snap +1 -1
  131. package/src/snackbar/Snackbar.js +6 -1
  132. package/src/snackbar/Snackbar.spec.js +1 -3
  133. package/src/ssr.spec.js +7 -0
  134. package/src/stepper/Stepper.css +1 -1
  135. package/src/stepper/Stepper.less +1 -9
  136. package/src/stepper/Stepper.spec.js +4 -4
  137. package/src/stepper/Stepper.tsx +2 -5
  138. package/src/tabs/Tabs.js +2 -1
  139. package/src/tile/Tile.js +5 -11
  140. package/src/tile/__snapshots__/Tile.spec.js.snap +7 -9
  141. package/src/upload/Upload.js +1 -1
  142. package/src/upload/steps/completeStep/completeStep.js +4 -1
  143. package/src/upload/steps/processingStep/processingStep.js +1 -0
  144. package/src/uploadInput/uploadItem/UploadItem.tsx +1 -1
  145. package/src/utilities/wrapInFragment.tsx +3 -0
  146. package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts +0 -2
  147. package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts.map +0 -1
  148. package/build/types/common/focusBoundary/utils/index.d.ts +0 -3
  149. package/build/types/common/focusBoundary/utils/index.d.ts.map +0 -1
  150. package/build/types/common/focusBoundary/utils/resetFocus.d.ts +0 -2
  151. package/build/types/common/focusBoundary/utils/resetFocus.d.ts.map +0 -1
  152. package/src/common/focusBoundary/FocusBoundary.spec.tsx +0 -66
  153. package/src/common/focusBoundary/__snapshots__/FocusBoundary.spec.tsx.snap +0 -16
  154. package/src/common/focusBoundary/utils/getFocusableElements.js +0 -25
  155. package/src/common/focusBoundary/utils/getFocusableElements.spec.js +0 -51
  156. package/src/common/focusBoundary/utils/index.js +0 -2
  157. package/src/common/focusBoundary/utils/resetFocus.js +0 -23
  158. package/src/common/focusBoundary/utils/resetFocus.spec.js +0 -103
  159. package/src/snackbar/__snapshots__/Snackbar.spec.js.snap +0 -5
  160. /package/src/dateLookup/dateTrigger/{DateTrigger.messages.js → DateTrigger.messages.ts} +0 -0
@@ -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
- <div className="text-xs-center p-t-1 p-b-2 clearfix">
10
- <div className="pull-left-single-direction">
11
- <button type="button" className={`d-inline-flex ${buttonClasses}`} onClick={onPreviousClick}>
12
- <Chevron orientation={Position.LEFT} className="left-single-direction" size={Size.MEDIUM} />
13
- </button>
14
- </div>
15
- {label && (
16
- <button
17
- type="button"
18
- className={`tw-date-lookup-header-current ${buttonClasses}`}
19
- onClick={onLabelClick}
20
- >
21
- {label}
22
- </button>
23
- )}
24
- <div className="pull-right-single-direction">
25
- <button type="button" className={`d-inline-flex ${buttonClasses}`} onClick={onNextClick}>
26
- <Chevron
27
- orientation={Position.RIGHT}
28
- className="right-single-direction"
29
- size={Size.MEDIUM}
30
- />
31
- </button>
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
- </div>
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">{day.slice(0, 3)}</span>
82
- <span className="visible-xs-inline-block">{this.daysShort[index].slice(0, 2)}</span>
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>
@@ -12,6 +12,7 @@ jest.mock('react-intl', () => ({
12
12
  function (props) {
13
13
  return <Component {...props} intl={{ locale }} />;
14
14
  },
15
+ defineMessages: (translations) => translations,
15
16
  }));
16
17
 
17
18
  jest.mock('@transferwise/formatting', () => ({
@@ -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(component.find(TableLink)).toHaveLength(12);
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(component.find(TableLink).find({ today: true }).prop('item')).toBe(today.getMonth());
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(TableLink).at(i);
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 { item, type, title, longTitle, active, disabled, today } = this.props;
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: 5,
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('5');
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(5);
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 { selectedDate, min, max, viewYear, placeholder } = this.props;
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 onPreviousClick={this.selectPreviousYears} onNextClick={this.selectNextYears} />
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(component.find(TableLink)).toHaveLength(20);
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(component.find(TableLink).find({ today: true }).prop('item')).toBe(today.getFullYear());
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(TableLink).at(i);
93
+ const getTableLinkAt = (i) => component.find('[type="year"]').at(i);
94
+ const getTableLink = () => component.find('[type="year"]');
96
95
  });
@@ -33,7 +33,7 @@ export const Basic = () => {
33
33
  href: '#href1',
34
34
  disabled,
35
35
  media: {
36
- block: <Illustration name="globe" alt="Image of globe" disableMargin />,
36
+ block: <Illustration name="globe" alt="" disableMargin />,
37
37
  list: (
38
38
  <Avatar size="md" type="initials">
39
39
  HM
@@ -49,7 +49,7 @@ export const Basic = () => {
49
49
  disabled,
50
50
  href: '#href2',
51
51
  media: {
52
- block: <Illustration name="confetti" alt="Beautiful confetti" disableMargin />,
52
+ block: <Illustration name="confetti" alt="" disableMargin />,
53
53
  list: (
54
54
  <Avatar size="md" type="initials">
55
55
  HM
@@ -61,11 +61,11 @@ export const Basic = () => {
61
61
  {
62
62
  description: "I'm disabled and don't require an onClick or href.",
63
63
  media: {
64
- block: <Illustration name="briefcase" alt="Cool briefcase" disableMargin />,
64
+ block: <Illustration name="briefcase" alt="" disableMargin />,
65
65
  list: (
66
66
  <img
67
67
  src="https://wise.com/public-resources/assets/illustrations/business_account_web_small.svg"
68
- alt="alt"
68
+ alt=""
69
69
  width="100"
70
70
  />
71
71
  ),
@@ -106,7 +106,7 @@ export const grid = () => {
106
106
  block: (
107
107
  <img
108
108
  src="https://wise.com/public-resources/assets/bank-details/bank-details-flow/finish.svg"
109
- alt="alt"
109
+ alt=""
110
110
  />
111
111
  ),
112
112
  list: (
@@ -127,7 +127,7 @@ export const grid = () => {
127
127
  block: (
128
128
  <img
129
129
  src="https://wise.com/public-resources/assets/bank-details/bank-details-flow/finish.svg"
130
- alt="alt"
130
+ alt=""
131
131
  />
132
132
  ),
133
133
  list: (
@@ -147,7 +147,7 @@ export const grid = () => {
147
147
  block: (
148
148
  <img
149
149
  src="https://wise.com/public-resources/assets/bank-details/bank-details-flow/finish.svg"
150
- alt="alt"
150
+ alt=""
151
151
  />
152
152
  ),
153
153
  list: (
@@ -169,7 +169,7 @@ export const grid = () => {
169
169
  block: (
170
170
  <img
171
171
  src="https://wise.com/public-resources/assets/bank-details/bank-details-flow/finish.svg"
172
- alt="alt"
172
+ alt=""
173
173
  />
174
174
  ),
175
175
  list: (
@@ -190,7 +190,7 @@ export const grid = () => {
190
190
  block: (
191
191
  <img
192
192
  src="https://wise.com/public-resources/assets/bank-details/bank-details-flow/finish.svg"
193
- alt="alt"
193
+ alt=""
194
194
  />
195
195
  ),
196
196
  list: (
@@ -211,7 +211,7 @@ export const grid = () => {
211
211
  block: (
212
212
  <img
213
213
  src="https://wise.com/public-resources/assets/bank-details/bank-details-flow/finish.svg"
214
- alt="alt"
214
+ alt=""
215
215
  />
216
216
  ),
217
217
  list: (
@@ -232,7 +232,7 @@ export const grid = () => {
232
232
  block: (
233
233
  <img
234
234
  src="https://wise.com/public-resources/assets/bank-details/bank-details-flow/finish.svg"
235
- alt="alt"
235
+ alt=""
236
236
  />
237
237
  ),
238
238
  list: (