@transferwise/components 0.0.0-experimental-ff4fa52 → 0.0.0-experimental-1413ac0

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 (129) hide show
  1. package/README.md +14 -1
  2. package/build/i18n/zh-HK.json +2 -2
  3. package/build/index.esm.js +182 -273
  4. package/build/index.esm.js.map +1 -1
  5. package/build/index.js +155 -246
  6. package/build/index.js.map +1 -1
  7. package/build/mocks.esm.js +40 -0
  8. package/build/mocks.esm.js.map +1 -0
  9. package/build/mocks.js +43 -0
  10. package/build/mocks.js.map +1 -0
  11. package/build/types/body/Body.d.ts +1 -1
  12. package/build/types/common/commonProps.d.ts +1 -1
  13. package/build/types/common/commonProps.d.ts.map +1 -1
  14. package/build/types/common/dateUtils/getDayNames/getDayNames.d.ts +1 -1
  15. package/build/types/common/dateUtils/getDayNames/getDayNames.d.ts.map +1 -1
  16. package/build/types/common/dateUtils/getDayNames/index.d.ts +2 -0
  17. package/build/types/common/dateUtils/getDayNames/index.d.ts.map +1 -0
  18. package/build/types/common/dateUtils/getMonthNames/getMonthNames.d.ts +1 -1
  19. package/build/types/common/dateUtils/getMonthNames/getMonthNames.d.ts.map +1 -1
  20. package/build/types/common/dateUtils/getMonthNames/index.d.ts +2 -0
  21. package/build/types/common/dateUtils/getMonthNames/index.d.ts.map +1 -0
  22. package/build/types/common/dateUtils/index.d.ts +6 -6
  23. package/build/types/common/dateUtils/index.d.ts.map +1 -1
  24. package/build/types/common/dateUtils/isDateValid/index.d.ts +2 -0
  25. package/build/types/common/dateUtils/isDateValid/index.d.ts.map +1 -0
  26. package/build/types/common/dateUtils/isDateValid/isDateValid.d.ts +2 -2
  27. package/build/types/common/dateUtils/isDateValid/isDateValid.d.ts.map +1 -1
  28. package/build/types/common/dateUtils/isMonthAndYearFormat/index.d.ts +2 -0
  29. package/build/types/common/dateUtils/isMonthAndYearFormat/index.d.ts.map +1 -0
  30. package/build/types/common/dateUtils/isMonthAndYearFormat/isMonthAndYearFormat.d.ts +1 -1
  31. package/build/types/common/dateUtils/isMonthAndYearFormat/isMonthAndYearFormat.d.ts.map +1 -1
  32. package/build/types/common/dateUtils/isWithinRange/index.d.ts +2 -0
  33. package/build/types/common/dateUtils/isWithinRange/index.d.ts.map +1 -0
  34. package/build/types/common/dateUtils/isWithinRange/isWithinRange.d.ts +1 -1
  35. package/build/types/common/dateUtils/isWithinRange/isWithinRange.d.ts.map +1 -1
  36. package/build/types/common/dateUtils/moveToWithinRange/index.d.ts +2 -0
  37. package/build/types/common/dateUtils/moveToWithinRange/index.d.ts.map +1 -0
  38. package/build/types/common/dateUtils/moveToWithinRange/moveToWithinRange.d.ts +1 -1
  39. package/build/types/common/dateUtils/moveToWithinRange/moveToWithinRange.d.ts.map +1 -1
  40. package/build/types/common/panel/Panel.d.ts +1 -1
  41. package/build/types/common/responsivePanel/ResponsivePanel.d.ts +1 -1
  42. package/build/types/dateInput/DateInput.d.ts +41 -35
  43. package/build/types/dateInput/DateInput.d.ts.map +1 -1
  44. package/build/types/dateInput/DateInput.messages.d.ts +33 -24
  45. package/build/types/dateInput/DateInput.messages.d.ts.map +1 -1
  46. package/build/types/dateInput/index.d.ts +1 -1
  47. package/build/types/dateInput/index.d.ts.map +1 -1
  48. package/build/types/dateInput/utils/convertToLocalMidnight/convertToLocalMidnight.d.ts +1 -1
  49. package/build/types/dateInput/utils/convertToLocalMidnight/convertToLocalMidnight.d.ts.map +1 -1
  50. package/build/types/dateInput/utils/convertToLocalMidnight/index.d.ts +1 -1
  51. package/build/types/dateInput/utils/convertToLocalMidnight/index.d.ts.map +1 -1
  52. package/build/types/dateInput/utils/explodeDate/explodeDate.d.ts +5 -2
  53. package/build/types/dateInput/utils/explodeDate/explodeDate.d.ts.map +1 -1
  54. package/build/types/dateInput/utils/explodeDate/index.d.ts +1 -1
  55. package/build/types/dateInput/utils/explodeDate/index.d.ts.map +1 -1
  56. package/build/types/dateInput/utils/index.d.ts +2 -2
  57. package/build/types/dateInput/utils/index.d.ts.map +1 -1
  58. package/build/types/decision/Decision.d.ts +39 -52
  59. package/build/types/decision/Decision.d.ts.map +1 -1
  60. package/build/types/decision/index.d.ts +1 -2
  61. package/build/types/decision/index.d.ts.map +1 -1
  62. package/build/types/dimmer/Dimmer.d.ts +1 -1
  63. package/build/types/index.d.ts +1 -0
  64. package/build/types/index.d.ts.map +1 -1
  65. package/build/types/mocks.d.ts +9 -0
  66. package/build/types/mocks.d.ts.map +1 -0
  67. package/build/types/promoCard/PromoCard.d.ts +1 -2
  68. package/build/types/promoCard/PromoCard.d.ts.map +1 -1
  69. package/build/types/select/searchBox/SearchBox.d.ts +1 -1
  70. package/build/types/test-utils/window-mock.d.ts.map +1 -1
  71. package/package.json +17 -1
  72. package/src/common/commonProps.ts +1 -1
  73. package/src/common/dateUtils/getDayNames/{getDayNames.ts → getDayNames.js} +2 -5
  74. package/src/common/dateUtils/getDayNames/getDayNames.spec.js +1 -1
  75. package/src/common/dateUtils/getDayNames/index.js +1 -0
  76. package/src/common/dateUtils/getMonthNames/{getMonthNames.ts → getMonthNames.js} +3 -5
  77. package/src/common/dateUtils/getMonthNames/getMonthNames.spec.js +8 -9
  78. package/src/common/dateUtils/getMonthNames/index.js +1 -0
  79. package/src/common/dateUtils/index.js +6 -0
  80. package/src/common/dateUtils/isDateValid/index.js +1 -0
  81. package/src/common/dateUtils/isDateValid/isDateValid.js +6 -0
  82. package/src/common/dateUtils/isDateValid/{isDateValid.spec.ts → isDateValid.spec.js} +1 -1
  83. package/src/common/dateUtils/isMonthAndYearFormat/index.js +1 -0
  84. package/src/common/dateUtils/isMonthAndYearFormat/isMonthAndYearFormat.js +4 -0
  85. package/src/common/dateUtils/isMonthAndYearFormat/isMonthAndYearFormat.spec.js +7 -3
  86. package/src/common/dateUtils/isWithinRange/index.js +1 -0
  87. package/src/common/dateUtils/isWithinRange/{isWithinRange.ts → isWithinRange.js} +1 -1
  88. package/src/common/dateUtils/isWithinRange/{isWithinRange.spec.ts → isWithinRange.spec.js} +1 -1
  89. package/src/common/dateUtils/moveToWithinRange/index.js +1 -0
  90. package/src/common/dateUtils/moveToWithinRange/{moveToWithinRange.ts → moveToWithinRange.js} +2 -2
  91. package/src/dateInput/{DateInput.tsx → DateInput.js} +97 -120
  92. package/src/dateInput/DateInput.spec.js +55 -6
  93. package/src/dateInput/DateInput.story.tsx +7 -9
  94. package/src/dateInput/utils/convertToLocalMidnight/{convertToLocalMidnight.ts → convertToLocalMidnight.js} +1 -1
  95. package/src/dateInput/utils/explodeDate/{explodeDate.ts → explodeDate.js} +1 -3
  96. package/src/dateLookup/dayCalendar/table/DayCalendarTable.js +0 -1
  97. package/src/decision/Decision.spec.js +53 -59
  98. package/src/decision/{Decision.story.js → Decision.story.tsx} +5 -5
  99. package/src/decision/Decision.tsx +136 -0
  100. package/src/decision/index.ts +1 -0
  101. package/src/i18n/zh-HK.json +2 -2
  102. package/src/index.ts +1 -0
  103. package/src/mocks.ts +48 -0
  104. package/src/promoCard/PromoCard.tsx +1 -2
  105. package/src/test-utils/window-mock.ts +7 -23
  106. package/src/tile/Tile.js +1 -1
  107. package/build/types/decision/decisionEnums.d.ts +0 -9
  108. package/build/types/decision/decisionEnums.d.ts.map +0 -1
  109. package/build/types/sizeSwapper/SizeSwapper.d.ts +0 -3
  110. package/build/types/sizeSwapper/SizeSwapper.d.ts.map +0 -1
  111. package/build/types/sizeSwapper/index.d.ts +0 -2
  112. package/build/types/sizeSwapper/index.d.ts.map +0 -1
  113. package/src/common/dateUtils/index.ts +0 -6
  114. package/src/common/dateUtils/isDateValid/isDateValid.ts +0 -13
  115. package/src/common/dateUtils/isMonthAndYearFormat/isMonthAndYearFormat.ts +0 -4
  116. package/src/decision/Decision.js +0 -148
  117. package/src/decision/decisionEnums.ts +0 -11
  118. package/src/decision/index.js +0 -2
  119. package/src/sizeSwapper/SizeSwapper.js +0 -69
  120. package/src/sizeSwapper/SizeSwapper.spec.js +0 -100
  121. package/src/sizeSwapper/SizeSwapper.story.js +0 -34
  122. package/src/sizeSwapper/index.js +0 -1
  123. /package/src/dateInput/{DateInput.messages.ts → DateInput.messages.js} +0 -0
  124. /package/src/dateInput/{index.ts → index.js} +0 -0
  125. /package/src/dateInput/utils/convertToLocalMidnight/{convertToLocalMidnight.spec.ts → convertToLocalMidnight.spec.js} +0 -0
  126. /package/src/dateInput/utils/convertToLocalMidnight/{index.ts → index.js} +0 -0
  127. /package/src/dateInput/utils/explodeDate/{explodeDate.spec.ts → explodeDate.spec.js} +0 -0
  128. /package/src/dateInput/utils/explodeDate/{index.ts → index.js} +0 -0
  129. /package/src/dateInput/utils/{index.ts → index.js} +0 -0
@@ -1,14 +1,9 @@
1
1
  import classNames from 'classnames';
2
- import React, { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useState } from 'react';
3
4
  import { useIntl } from 'react-intl';
4
5
 
5
- import {
6
- Input,
7
- SelectInput,
8
- SelectInputProps,
9
- SelectInputOptionItem,
10
- SelectInputOptionContent,
11
- } from '..';
6
+ import { Input, SelectInput, SelectInputOptionContent } from '..';
12
7
  import { Size, DateMode, MonthFormat } from '../common';
13
8
  import { getMonthNames, isDateValid, isMonthAndYearFormat } from '../common/dateUtils';
14
9
 
@@ -16,79 +11,44 @@ import messages from './DateInput.messages';
16
11
  import { explodeDate, convertToLocalMidnight } from './utils';
17
12
 
18
13
  const MonthBeforeDay = new Set(['en-US', 'ja-JP']);
19
- const INITIAL_DEFAULT_STATE: ExplodedDate = { year: null, month: null, day: null };
20
-
21
- export interface ExplodedDate {
22
- year: number | null;
23
- month: number | null;
24
- day: number | null;
25
- }
26
-
27
- export interface DateInputProps {
28
- 'aria-label'?: string;
29
- 'aria-labelledby'?: string;
30
- disabled?: boolean;
31
- size?: Size.SMALL | Size.MEDIUM | Size.LARGE;
32
- value?: Date | string | null;
33
- onChange: (value: string | null) => void;
34
- onFocus?: React.FocusEventHandler<HTMLInputElement>;
35
- onBlur?: React.FocusEventHandler<HTMLInputElement>;
36
- dayLabel?: string;
37
- dayAutoComplete?: string;
38
- monthLabel?: string;
39
- yearLabel?: string;
40
- yearAutoComplete?: string;
41
- monthFormat?: MonthFormat;
42
- mode?: DateMode;
43
- placeholders?: {
44
- day?: string;
45
- month?: string;
46
- year?: string;
47
- };
48
- id?: string;
49
- selectProps?: Partial<SelectInputProps<number>>;
50
- }
14
+ const INITIAL_DEFAULT_STATE = { year: null, month: null, day: null };
51
15
 
52
16
  const DateInput = ({
53
17
  'aria-labelledby': ariaLabelledBy,
54
18
  'aria-label': ariaLabel,
55
- disabled = false,
56
- size = Size.MEDIUM,
57
- value = null,
19
+ disabled,
20
+ size,
21
+ value,
58
22
  dayLabel,
59
23
  dayAutoComplete,
60
24
  monthLabel,
61
25
  yearLabel,
62
26
  yearAutoComplete,
63
- monthFormat = MonthFormat.LONG,
64
- mode = DateMode.DAY_MONTH_YEAR,
27
+ monthFormat,
28
+ mode,
65
29
  onChange,
66
30
  onFocus,
67
- onBlur = undefined,
31
+ onBlur,
68
32
  placeholders,
69
- id = '',
33
+ id,
70
34
  selectProps,
71
- }: DateInputProps) => {
35
+ }) => {
72
36
  const { locale, formatMessage } = useIntl();
73
-
74
- const getDateObject = (): Date | null => {
37
+ const getDateObject = () => {
75
38
  if (value && isDateValid(value)) {
76
39
  return typeof value === 'string' ? convertToLocalMidnight(value) : value;
77
40
  }
78
41
  return null;
79
42
  };
80
43
 
81
- const getExplodedDate = (unit: 'year' | 'month' | 'day'): number | null => {
82
- let explodedDate: ExplodedDate = INITIAL_DEFAULT_STATE;
44
+ const getExplodedDate = (unit) => {
45
+ let explodedDate = INITIAL_DEFAULT_STATE;
83
46
 
84
47
  if (value && isDateValid(value)) {
85
48
  const dateObject = getDateObject();
49
+ explodedDate = explodeDate(dateObject);
86
50
 
87
- if (dateObject !== null) {
88
- explodedDate = explodeDate(dateObject);
89
- }
90
-
91
- if (typeof value === 'string' && isMonthAndYearFormat(value)) {
51
+ if (isMonthAndYearFormat(value)) {
92
52
  explodedDate.day = null;
93
53
  }
94
54
  }
@@ -96,11 +56,9 @@ const DateInput = ({
96
56
  };
97
57
 
98
58
  const [day, setDay] = useState(() => getExplodedDate('day'));
99
- const [month, setMonth] = useState<number | null>(() => getExplodedDate('month'));
59
+ const [month, setMonth] = useState(() => getExplodedDate('month'));
100
60
  const [year, setYear] = useState(() => getExplodedDate('year'));
101
- const [lastBroadcastedValue, setLastBroadcastedValue] = useState<Date | ExplodedDate | null>(
102
- getDateObject,
103
- );
61
+ const [lastBroadcastedValue, setLastBroadcastedValue] = useState(getDateObject);
104
62
 
105
63
  dayLabel = dayLabel || formatMessage(messages.dayLabel);
106
64
  monthLabel = monthLabel || formatMessage(messages.monthLabel);
@@ -111,8 +69,8 @@ const DateInput = ({
111
69
  year: placeholders?.year || formatMessage(messages.yearPlaceholder),
112
70
  };
113
71
 
114
- const getDateAsString = (date: Date | null) => {
115
- if (date === null || !isDateValid(date)) {
72
+ const getDateAsString = (date) => {
73
+ if (!isDateValid(date)) {
116
74
  return '';
117
75
  }
118
76
  switch (mode) {
@@ -137,13 +95,11 @@ const DateInput = ({
137
95
  <SelectInput
138
96
  name="month"
139
97
  disabled={disabled}
140
- placeholder={placeholders?.month}
98
+ placeholder={placeholders.month}
141
99
  items={monthOptions}
142
100
  size={size}
143
- value={monthOptions.find((item) => item.value === month)?.value}
144
- renderValue={(selectedValue) => (
145
- <SelectInputOptionContent title={getMonthNames(locale, monthFormat)[selectedValue]} />
146
- )}
101
+ value={monthOptions.find((item) => item.value.value === month)?.value}
102
+ renderValue={({ label }) => <SelectInputOptionContent title={label} />}
147
103
  onChange={(selectedValue) => handleMonthChange(selectedValue)}
148
104
  {...selectProps}
149
105
  />
@@ -152,19 +108,16 @@ const DateInput = ({
152
108
  };
153
109
 
154
110
  const getMonthsOptions = () => {
155
- const options: SelectInputOptionItem<number>[] = [];
111
+ const options = [];
112
+ const months = getMonthNames(locale, monthFormat);
156
113
 
157
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].forEach((index) => {
158
- options.push({ type: 'option', value: index });
114
+ months.forEach((label, index) => {
115
+ options.push({ type: 'option', value: { label, value: index } });
159
116
  });
160
117
  return options;
161
118
  };
162
119
 
163
- const handleInternalValue = (
164
- newDay: number | null = day,
165
- newMonth: number | null = month,
166
- newYear: number | null = year,
167
- ) => {
120
+ const handleInternalValue = (newDay = day, newMonth = month, newYear = year) => {
168
121
  const dateValue =
169
122
  newDay != null && newMonth != null && newYear != null
170
123
  ? new Date(newYear, newMonth, newDay)
@@ -177,12 +130,11 @@ const DateInput = ({
177
130
  }
178
131
 
179
132
  if (mode === DateMode.MONTH_YEAR) {
180
- if (newMonth && newMonth >= 0 && newYear && (newMonth !== month || newYear !== year)) {
133
+ if (newMonth >= 0 && newYear && (newMonth !== month || newYear !== year)) {
181
134
  broadcastNewValue(newValue);
182
135
  }
183
136
  } else if (
184
137
  newDay &&
185
- newMonth !== null &&
186
138
  newMonth >= 0 &&
187
139
  newYear &&
188
140
  (newDay !== day || newMonth !== month || newYear !== year)
@@ -191,75 +143,70 @@ const DateInput = ({
191
143
  }
192
144
  };
193
145
 
194
- const handleDayChange = (event: React.ChangeEvent<HTMLInputElement>) => {
195
- const { checkedDay } = checkDate(parseInt(event.target.value), month, year);
146
+ const handleDayChange = (event) => {
147
+ const { checkedDay } = checkDate(event.target.value, month, year);
196
148
  setDay(checkedDay);
197
149
  handleInternalValue(checkedDay, month, year);
198
150
  };
199
151
 
200
- const handleMonthChange = (selectedValue: number) => {
201
- if (selectedValue === null) {
152
+ const handleMonthChange = (selectedValue) => {
153
+ if (!selectedValue) {
202
154
  setMonth(null);
203
155
  handleInternalValue(day, null, year);
204
156
  return;
205
157
  }
206
- const selectedMonth = selectedValue ? selectedValue : 0;
158
+ const selectedMonth = selectedValue ? selectedValue.value : 0;
207
159
  const { checkedDay } = checkDate(day, selectedMonth, year);
208
160
  setMonth(selectedMonth);
209
- if (day && checkedDay !== day) {
210
- setDay(checkedDay);
161
+ if (day) {
162
+ if (checkedDay !== day) {
163
+ setDay(checkedDay);
164
+ }
211
165
  }
212
166
  handleInternalValue(checkedDay, selectedMonth, year);
213
167
  };
214
168
 
215
- const handleYearChange = (event: React.ChangeEvent<HTMLInputElement>) => {
169
+ const handleYearChange = (event) => {
216
170
  const newValue = event.target.value;
217
171
  const slicedYear = newValue.length > 4 ? newValue.slice(0, 4) : newValue;
218
172
 
219
173
  if (slicedYear.toString().length === 4) {
220
174
  // Correct day based on year and month.
221
- const { checkedDay } = checkDate(day, month, parseInt(newValue));
175
+ const { checkedDay } = checkDate(day, month, newValue);
222
176
 
223
- if (day && checkedDay !== day) {
224
- setDay(checkedDay);
177
+ if (day) {
178
+ if (checkedDay !== day) {
179
+ setDay(checkedDay);
180
+ }
225
181
  }
226
-
227
- setYear(parseInt(slicedYear));
228
- handleInternalValue(checkedDay, month, parseInt(slicedYear));
182
+ setYear(slicedYear);
183
+ handleInternalValue(checkedDay, month, slicedYear);
229
184
  } else {
230
- setYear(parseInt(slicedYear));
185
+ setYear(slicedYear);
231
186
  handleInternalValue(day, month, null);
232
187
  }
233
188
  };
234
189
 
235
- const broadcastNewValue = (newValue: Date | ExplodedDate | null) => {
190
+ const broadcastNewValue = (newValue) => {
236
191
  if (newValue !== lastBroadcastedValue) {
237
192
  setLastBroadcastedValue(newValue);
238
- if (newValue === INITIAL_DEFAULT_STATE) {
239
- onChange(null);
240
- } else {
241
- onChange(getDateAsString(newValue as Date) || null);
242
- }
193
+ onChange(getDateAsString(newValue) || null);
243
194
  }
244
195
  };
245
196
 
246
- const checkDate = (
247
- newDay: number | null = null,
248
- newMonth: number | null = 0,
249
- newYear: number | null = null,
250
- ) => {
197
+ const checkDate = (newDay = null, newMonth = 0, newYear = null) => {
251
198
  let checkedDay = newDay;
252
- const maxDay = new Date(newYear || 2000, newMonth ? newMonth + 1 : 1, 0).getDate();
199
+ const maxDay = new Date(newYear || 2000, newMonth + 1, 0).getDate();
253
200
 
254
201
  if (!newDay) {
255
202
  checkedDay = null;
256
203
  }
257
204
 
258
- if (newDay && newDay < 0) {
205
+ if ((newDay && newDay < 0) || newDay === '00') {
259
206
  checkedDay = 1;
260
207
  }
261
208
 
262
- if ((newDay && newMonth) || (newDay && newDay > 31)) {
209
+ if ((newDay && newMonth) || newDay > 31) {
263
210
  checkedDay = newDay > maxDay ? maxDay : newDay;
264
211
  }
265
212
 
@@ -281,12 +228,11 @@ const DateInput = ({
281
228
  id={id}
282
229
  aria-labelledby={ariaLabelledBy}
283
230
  aria-label={ariaLabel}
284
- role="group" // Add role attribute to indicate container for interactive elements
285
- onFocus={(event: React.FocusEvent<HTMLInputElement>) =>
286
- shouldPropagateOnFocus(event) ? onFocus && onFocus(event) : event.stopPropagation()
231
+ onFocus={(event) =>
232
+ shouldPropagateOnFocus(event) ? onFocus && onFocus() : event.stopPropagation()
287
233
  }
288
- onBlur={(event: React.FocusEvent<HTMLInputElement>) =>
289
- shouldPropagateOnBlur(event) ? onBlur && onBlur(event) : event.stopPropagation()
234
+ onBlur={(event) =>
235
+ shouldPropagateOnBlur(event) ? onBlur && onBlur() : event.stopPropagation()
290
236
  }
291
237
  >
292
238
  <div className="row">
@@ -336,20 +282,14 @@ const DateInput = ({
336
282
  };
337
283
 
338
284
  // Should only propagate if the relatedTarget is not part of this DateInput component.
339
- function shouldPropagateOnFocus({
340
- target,
341
- relatedTarget,
342
- }: Pick<React.FocusEvent, 'target' | 'relatedTarget'>) {
285
+ function shouldPropagateOnFocus({ target, relatedTarget }) {
343
286
  const targetParent = target.closest('.tw-date');
344
287
  const relatedParent = relatedTarget && relatedTarget.closest('.tw-date');
345
288
  return targetParent !== relatedParent;
346
289
  }
347
290
 
348
291
  // Should only propagate if the relatedTarget or the activeElement is not part of this DateInput component.
349
- function shouldPropagateOnBlur({
350
- target,
351
- relatedTarget,
352
- }: Pick<React.FocusEvent, 'target' | 'relatedTarget'>) {
292
+ function shouldPropagateOnBlur({ target, relatedTarget }) {
353
293
  const blurElementParent = target.closest('.tw-date');
354
294
  // Even though FocusEvent.relatedTarget is supported by IE
355
295
  // (https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget)
@@ -363,4 +303,41 @@ function shouldPropagateOnBlur({
363
303
  return blurElementParent !== focusElementParent;
364
304
  }
365
305
 
306
+ DateInput.propTypes = {
307
+ 'aria-label': PropTypes.string,
308
+ 'aria-labelledby': PropTypes.string,
309
+ disabled: PropTypes.bool,
310
+ size: PropTypes.oneOf(['sm', 'md', 'lg']),
311
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
312
+ onChange: PropTypes.func.isRequired,
313
+ onFocus: PropTypes.func,
314
+ onBlur: PropTypes.func,
315
+ dayLabel: PropTypes.string,
316
+ dayAutoComplete: PropTypes.string,
317
+ monthLabel: PropTypes.string,
318
+ yearLabel: PropTypes.string,
319
+ yearAutoComplete: PropTypes.string,
320
+ monthFormat: PropTypes.oneOf(['long', 'short']),
321
+ mode: PropTypes.oneOf(['day-month-year', 'month-year']),
322
+ placeholders: PropTypes.shape({
323
+ day: PropTypes.node,
324
+ month: PropTypes.node,
325
+ year: PropTypes.node,
326
+ }),
327
+ id: PropTypes.string,
328
+ selectProps: PropTypes.object,
329
+ };
330
+
331
+ DateInput.defaultProps = {
332
+ disabled: false,
333
+ size: Size.MEDIUM,
334
+ value: null,
335
+ onFocus: null,
336
+ onBlur: null,
337
+ monthFormat: MonthFormat.LONG,
338
+ mode: DateMode.DAY_MONTH_YEAR,
339
+ id: '',
340
+ selectProps: {},
341
+ };
342
+
366
343
  export default DateInput;
@@ -4,12 +4,44 @@ import { useIntl } from 'react-intl';
4
4
  import { DateInput, Input } from '..';
5
5
  import { mockMatchMedia, mockResizeObserver } from '../test-utils';
6
6
 
7
+ const MONTHS_FR = [
8
+ 'janvier',
9
+ 'février',
10
+ 'mars',
11
+ 'avril',
12
+ 'mai',
13
+ 'juin',
14
+ 'juillet',
15
+ 'août',
16
+ 'septembre',
17
+ 'octobre',
18
+ 'novembre',
19
+ 'décembre',
20
+ ];
21
+
22
+ const MONTHS_EN = [
23
+ 'January',
24
+ 'February',
25
+ 'March',
26
+ 'April',
27
+ 'May',
28
+ 'June',
29
+ 'July',
30
+ 'August',
31
+ 'September',
32
+ 'October',
33
+ 'November',
34
+ 'December',
35
+ ];
36
+
7
37
  const LOCALES = {
38
+ fr: 'fr-FR',
8
39
  jp: 'ja-JP',
9
40
  };
41
+
10
42
  const DEFAULT_LOCALE = 'en-GB';
11
- const FEBRUARY_INDEX = 1;
12
- const AUGUST_INDEX = 7;
43
+
44
+ const FEBRUARY_OPTION = { value: MONTHS_EN[1] };
13
45
 
14
46
  const DAY_SELECTOR = 'ForwardRef(Input)[name="day"]';
15
47
  const MONTH_SELECTOR = 'SelectInput';
@@ -41,6 +73,12 @@ jest.mock('./DateInput.messages', () => ({
41
73
  }));
42
74
 
43
75
  jest.mock('react-intl');
76
+ jest.mock('@transferwise/formatting', () => {
77
+ return {
78
+ formatDate: (month, locale) =>
79
+ locale === LOCALES.fr ? MONTHS_FR[month.getMonth()] : MONTHS_EN[month.getMonth()],
80
+ };
81
+ });
44
82
 
45
83
  describe('Date Input Component', () => {
46
84
  let selectMonth;
@@ -105,7 +143,7 @@ describe('Date Input Component', () => {
105
143
  inputYear = component.find(YEAR_SELECTOR);
106
144
 
107
145
  expect(inputDay.prop('value')).toBe(1);
108
- expect(selectMonth.prop('value')).toBe(FEBRUARY_INDEX);
146
+ expect(selectMonth.prop('value').label).toBe(FEBRUARY_OPTION.value);
109
147
  expect(inputYear.prop('value')).toBe(1971);
110
148
  });
111
149
  });
@@ -119,7 +157,7 @@ describe('Date Input Component', () => {
119
157
  inputYear = component.find(YEAR_SELECTOR);
120
158
 
121
159
  expect(inputDay.prop('value')).toBe(22);
122
- expect(selectMonth.prop('value')).toBe(AUGUST_INDEX);
160
+ expect(selectMonth.prop('value').label).toBe(MONTHS_EN[7]);
123
161
  expect(inputYear.prop('value')).toBe(1990);
124
162
  });
125
163
  });
@@ -133,7 +171,7 @@ describe('Date Input Component', () => {
133
171
  inputYear = component.find(YEAR_SELECTOR);
134
172
 
135
173
  expect(inputDay.prop('value')).toBe('');
136
- expect(selectMonth.prop('value')).toBe(AUGUST_INDEX);
174
+ expect(selectMonth.prop('value').label).toBe(MONTHS_EN[7]);
137
175
  expect(inputYear.prop('value')).toBe(1990);
138
176
  });
139
177
  });
@@ -147,7 +185,7 @@ describe('Date Input Component', () => {
147
185
  inputYear = component.find(YEAR_SELECTOR);
148
186
 
149
187
  expect(inputDay.prop('value')).toBe(28);
150
- expect(selectMonth.prop('value')).toBe(FEBRUARY_INDEX);
188
+ expect(selectMonth.prop('value').label).toBe(FEBRUARY_OPTION.value);
151
189
  expect(inputYear.prop('value')).toBe(1990);
152
190
  });
153
191
  });
@@ -182,6 +220,17 @@ describe('Date Input Component', () => {
182
220
  });
183
221
 
184
222
  describe('when locale is provided', () => {
223
+ it('updates selectMonth based on locale', () => {
224
+ useIntl.mockReturnValue({
225
+ locale: LOCALES.fr,
226
+ formatMessage: (message) => message.defaultMessage,
227
+ });
228
+ component = shallow(<DateInput {...props} />);
229
+ selectMonth = component.find(MONTH_SELECTOR);
230
+
231
+ expect(selectMonth.props().items[0].value.label).toStrictEqual(MONTHS_FR[0]);
232
+ });
233
+
185
234
  it('shows day before month if locale not US', () => {
186
235
  component = shallow(<DateInput {...props} />);
187
236
 
@@ -1,32 +1,30 @@
1
1
  import { Meta, StoryObj } from '@storybook/react';
2
2
  import { userEvent, within } from '@storybook/test';
3
- import React from 'react';
4
3
 
5
- import { DateInput, DateMode, Info, InlineAlert, Title, Typography } from '..';
4
+ import { DateInput, Info, InlineAlert, Title, Typography } from '..';
6
5
  import { lorem10, storyConfig } from '../test-utils';
7
6
 
8
- import { DateInputProps } from './DateInput';
9
-
10
7
  export default {
11
8
  component: DateInput,
12
9
  title: 'Forms/DateInput',
13
10
  args: {
14
11
  dayLabel: 'Day input',
15
12
  dayAutoComplete: 'bday-day',
16
- value: null,
17
13
  monthLabel: 'Month select',
18
14
  yearLabel: 'Year input',
19
15
  yearAutoComplete: 'bday-year',
20
16
  selectProps: {
21
- placeholder: 'Month',
17
+ buttonProps: {
18
+ 'aria-label': 'Select month',
19
+ },
22
20
  },
23
21
  },
24
22
  tags: ['autodocs'],
25
23
  } satisfies Meta<typeof DateInput>;
26
24
 
27
- type Story = StoryObj<DateInputProps>;
25
+ type Story = StoryObj<typeof DateInput>;
28
26
 
29
- export const Basic: StoryObj = {};
27
+ export const Basic: Story = {};
30
28
 
31
29
  Basic.play = async ({ canvasElement }) => {
32
30
  const canvas = within(canvasElement);
@@ -58,7 +56,7 @@ export const WithLabel: Story = {
58
56
  {label}{' '}
59
57
  <Info aria-label="Fast transfer hint" title="Fast transfer hint" content={lorem10} />
60
58
  </div>
61
- <DateInput {...args} mode={DateMode.MONTH_YEAR} aria-label={label} />
59
+ <DateInput {...args} aria-label={label} />
62
60
 
63
61
  <br />
64
62
 
@@ -1,4 +1,4 @@
1
- export const convertToLocalMidnight = (date: string) => {
1
+ export const convertToLocalMidnight = (date) => {
2
2
  const utcDate = new Date(date.split('T')[0]); // using YYYY-MM-DD creates UTC date
3
3
 
4
4
  return new Date(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate());
@@ -1,6 +1,4 @@
1
- import { ExplodedDate } from '../../DateInput';
2
-
3
- export const explodeDate = (date: Date): ExplodedDate => {
1
+ export const explodeDate = (date) => {
4
2
  const year = date.getFullYear();
5
3
  const month = date.getMonth();
6
4
  const day = date.getDate();
@@ -58,7 +58,6 @@ class DayCalendarTable extends PureComponent {
58
58
  isDisabled = (day) => {
59
59
  const { min, max, viewMonth, viewYear } = this.props;
60
60
  const date = new Date(viewYear, viewMonth, day);
61
-
62
61
  return !isWithinRange(date, min, max);
63
62
  };
64
63