@transferwise/components 46.26.2 → 46.28.0
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/th.json +2 -2
- package/build/i18n/zh-CN.json +5 -5
- package/build/index.js +410 -645
- package/build/index.js.map +1 -1
- package/build/index.mjs +411 -646
- package/build/index.mjs.map +1 -1
- package/build/logo/svg/flag-platform-white.svg +1 -0
- package/build/logo/svg/flag-platform.svg +1 -0
- package/build/logo/svg/logo-platform-white.svg +1 -0
- package/build/logo/svg/logo-platform.svg +1 -0
- package/build/main.css +0 -16
- package/build/styles/logo/Logo.css +0 -16
- package/build/styles/main.css +0 -16
- package/build/types/alert/Alert.d.ts +47 -58
- package/build/types/alert/Alert.d.ts.map +1 -1
- package/build/types/alert/index.d.ts +2 -1
- package/build/types/alert/index.d.ts.map +1 -1
- package/build/types/button/Button.d.ts +7 -9
- package/build/types/button/Button.d.ts.map +1 -1
- package/build/types/common/dateUtils/isWithinRange/isWithinRange.d.ts +1 -1
- package/build/types/common/dateUtils/isWithinRange/isWithinRange.d.ts.map +1 -1
- package/build/types/common/dateUtils/moveToWithinRange/moveToWithinRange.d.ts +1 -1
- package/build/types/common/dateUtils/moveToWithinRange/moveToWithinRange.d.ts.map +1 -1
- package/build/types/common/propsValues/sentiment.d.ts +0 -1
- package/build/types/common/propsValues/sentiment.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.d.ts +75 -28
- package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.messages.d.ts +42 -63
- package/build/types/dateLookup/DateLookup.messages.d.ts.map +1 -1
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts +9 -22
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts.map +1 -1
- package/build/types/dateLookup/dateHeader/index.d.ts +1 -1
- package/build/types/dateLookup/dateHeader/index.d.ts.map +1 -1
- package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts +13 -31
- package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts.map +1 -1
- package/build/types/dateLookup/dateTrigger/index.d.ts +1 -1
- package/build/types/dateLookup/dateTrigger/index.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/DayCalendar.d.ts +19 -2
- package/build/types/dateLookup/dayCalendar/DayCalendar.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/index.d.ts +1 -1
- package/build/types/dateLookup/dayCalendar/index.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/table/DayCalendarTable.d.ts +12 -2
- package/build/types/dateLookup/dayCalendar/table/DayCalendarTable.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/table/index.d.ts +1 -1
- package/build/types/dateLookup/dayCalendar/table/index.d.ts.map +1 -1
- package/build/types/dateLookup/getStartOfDay/getStartOfDay.d.ts +1 -1
- package/build/types/dateLookup/getStartOfDay/getStartOfDay.d.ts.map +1 -1
- package/build/types/dateLookup/getStartOfDay/index.d.ts +1 -1
- package/build/types/dateLookup/getStartOfDay/index.d.ts.map +1 -1
- package/build/types/dateLookup/index.d.ts +2 -1
- package/build/types/dateLookup/index.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/MonthCalendar.d.ts +17 -2
- package/build/types/dateLookup/monthCalendar/MonthCalendar.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/index.d.ts +1 -1
- package/build/types/dateLookup/monthCalendar/index.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts +10 -26
- package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/table/index.d.ts +1 -1
- package/build/types/dateLookup/monthCalendar/table/index.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts +15 -2
- package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/index.d.ts +1 -1
- package/build/types/dateLookup/yearCalendar/index.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/table/YearCalendarTable.d.ts +10 -26
- package/build/types/dateLookup/yearCalendar/table/YearCalendarTable.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/table/index.d.ts +1 -1
- package/build/types/dateLookup/yearCalendar/table/index.d.ts.map +1 -1
- package/build/types/index.d.ts +2 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/inlineAlert/InlineAlert.d.ts +2 -4
- package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/inputs/_BottomSheet.d.ts.map +1 -1
- package/build/types/inputs/_Popover.d.ts.map +1 -1
- package/build/types/instructionsList/InstructionsList.d.ts +1 -1
- package/build/types/instructionsList/InstructionsList.d.ts.map +1 -1
- package/build/types/logo/Logo.d.ts +1 -1
- package/build/types/logo/Logo.d.ts.map +1 -1
- package/build/types/logo/logoTypes.d.ts +2 -1
- package/build/types/logo/logoTypes.d.ts.map +1 -1
- package/build/types/markdown/Markdown.d.ts +1 -0
- package/build/types/markdown/Markdown.d.ts.map +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/alert/{Alert.spec.js → Alert.spec.tsx} +43 -40
- package/src/alert/Alert.story.tsx +1 -2
- package/src/alert/Alert.tsx +218 -0
- package/src/alert/index.ts +2 -0
- package/src/button/Button.tsx +6 -10
- package/src/common/dateUtils/isWithinRange/isWithinRange.spec.ts +21 -0
- package/src/common/dateUtils/isWithinRange/isWithinRange.ts +2 -2
- package/src/common/dateUtils/moveToWithinRange/moveToWithinRange.ts +8 -4
- package/src/common/propsValues/sentiment.ts +0 -10
- package/src/dateLookup/DateLookup.state.spec.js +7 -0
- package/src/dateLookup/{DateLookup.story.js → DateLookup.story.tsx} +13 -14
- package/src/dateLookup/DateLookup.tests.story.tsx +70 -0
- package/src/dateLookup/{DateLookup.js → DateLookup.tsx} +115 -81
- package/src/dateLookup/dateHeader/{DateHeader.js → DateHeader.tsx} +15 -15
- package/src/dateLookup/dateTrigger/DateTrigger.spec.js +0 -22
- package/src/dateLookup/dateTrigger/{DateTrigger.js → DateTrigger.tsx} +15 -32
- package/src/dateLookup/dayCalendar/{DayCalendar.js → DayCalendar.tsx} +14 -21
- package/src/dateLookup/dayCalendar/table/{DayCalendarTable.js → DayCalendarTable.tsx} +26 -37
- package/src/dateLookup/getStartOfDay/{getStartOfDay.js → getStartOfDay.tsx} +1 -1
- package/src/dateLookup/index.ts +2 -0
- package/src/dateLookup/monthCalendar/{MonthCalendar.js → MonthCalendar.tsx} +19 -22
- package/src/dateLookup/monthCalendar/table/{MonthCalendarTable.js → MonthCalendarTable.tsx} +31 -30
- package/src/dateLookup/yearCalendar/{YearCalendar.js → YearCalendar.tsx} +18 -21
- package/src/dateLookup/yearCalendar/table/{YearCalendarTable.js → YearCalendarTable.tsx} +26 -28
- package/src/i18n/th.json +2 -2
- package/src/i18n/zh-CN.json +5 -5
- package/src/index.ts +2 -1
- package/src/inlineAlert/InlineAlert.spec.tsx +0 -7
- package/src/inlineAlert/InlineAlert.tsx +19 -47
- package/src/inputs/InputGroup.tsx +3 -3
- package/src/inputs/SelectInput.tsx +1 -0
- package/src/inputs/_BottomSheet.tsx +44 -54
- package/src/inputs/_Popover.tsx +20 -23
- package/src/instructionsList/InstructionsList.spec.tsx +5 -0
- package/src/instructionsList/InstructionsList.story.tsx +1 -0
- package/src/instructionsList/InstructionsList.tsx +3 -2
- package/src/logo/Logo.css +0 -16
- package/src/logo/Logo.js +27 -5
- package/src/logo/Logo.less +0 -16
- package/src/logo/Logo.spec.js +15 -1
- package/src/logo/__snapshots__/Logo.spec.js.snap +45 -71
- package/src/logo/logoTypes.ts +1 -0
- package/src/logo/svg/flag-platform-white.svg +1 -0
- package/src/logo/svg/flag-platform.svg +1 -0
- package/src/logo/svg/logo-platform-white.svg +1 -0
- package/src/logo/svg/logo-platform.svg +1 -0
- package/src/main.css +0 -16
- package/src/markdown/Markdown.spec.tsx +16 -0
- package/src/markdown/Markdown.tsx +6 -1
- package/src/statusIcon/StatusIcon.tsx +14 -14
- package/build/types/alert/withArrow/alertArrowPositions.d.ts +0 -9
- package/build/types/alert/withArrow/alertArrowPositions.d.ts.map +0 -1
- package/build/types/alert/withArrow/index.d.ts +0 -3
- package/build/types/alert/withArrow/index.d.ts.map +0 -1
- package/build/types/alert/withArrow/withArrow.d.ts +0 -11
- package/build/types/alert/withArrow/withArrow.d.ts.map +0 -1
- package/src/alert/Alert.js +0 -196
- package/src/alert/index.js +0 -1
- package/src/alert/withArrow/alertArrowPositions.ts +0 -9
- package/src/alert/withArrow/index.js +0 -2
- package/src/alert/withArrow/withArrow.js +0 -50
- package/src/alert/withArrow/withArrow.spec.js +0 -51
- package/src/dateLookup/index.js +0 -1
- /package/src/dateLookup/{DateLookup.messages.js → DateLookup.messages.ts} +0 -0
- /package/src/dateLookup/dateHeader/{index.js → index.ts} +0 -0
- /package/src/dateLookup/dateTrigger/{index.js → index.ts} +0 -0
- /package/src/dateLookup/dayCalendar/{index.js → index.ts} +0 -0
- /package/src/dateLookup/dayCalendar/table/{index.js → index.ts} +0 -0
- /package/src/dateLookup/getStartOfDay/{index.js → index.ts} +0 -0
- /package/src/dateLookup/monthCalendar/{index.js → index.ts} +0 -0
- /package/src/dateLookup/monthCalendar/table/{index.js → index.ts} +0 -0
- /package/src/dateLookup/yearCalendar/{index.js → index.ts} +0 -0
- /package/src/dateLookup/yearCalendar/table/{index.js → index.ts} +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ReactRenderer, Story } from '@storybook/react';
|
|
2
|
+
import { expect, userEvent, within } from '@storybook/test';
|
|
3
|
+
import { PlayFunctionContext } from '@storybook/types';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import DateLookup from './DateLookup';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
component: DateLookup,
|
|
10
|
+
title: 'Forms/DateLookup/Tests',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const Template: Story<DateLookup> = () => {
|
|
14
|
+
const [value, setValue] = useState<Date | null>(new Date(1987, 0, 10, 12, 0, 0));
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<DateLookup
|
|
18
|
+
value={value}
|
|
19
|
+
clearable
|
|
20
|
+
placeholder="placeholder"
|
|
21
|
+
onChange={(v) => {
|
|
22
|
+
setValue(v);
|
|
23
|
+
}}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const ClearSpace = Template.bind({});
|
|
29
|
+
|
|
30
|
+
ClearSpace.play = async ({
|
|
31
|
+
canvasElement,
|
|
32
|
+
step,
|
|
33
|
+
}: PlayFunctionContext<ReactRenderer, DateLookup>) => {
|
|
34
|
+
const canvas = within(canvasElement);
|
|
35
|
+
|
|
36
|
+
await step('space can activate clear button', async () => {
|
|
37
|
+
// focus on clear button
|
|
38
|
+
const date = await canvas.findByText('January 10, 1987');
|
|
39
|
+
await expect(date).toBeInTheDocument();
|
|
40
|
+
await userEvent.tab();
|
|
41
|
+
await userEvent.tab();
|
|
42
|
+
|
|
43
|
+
// clear with space
|
|
44
|
+
await userEvent.keyboard(' ');
|
|
45
|
+
const placeholder = canvas.getByText('placeholder');
|
|
46
|
+
await expect(placeholder).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const ClearEnter = Template.bind({});
|
|
51
|
+
|
|
52
|
+
ClearEnter.play = async ({
|
|
53
|
+
canvasElement,
|
|
54
|
+
step,
|
|
55
|
+
}: PlayFunctionContext<ReactRenderer, DateLookup>) => {
|
|
56
|
+
const canvas = within(canvasElement);
|
|
57
|
+
|
|
58
|
+
await step('enter can activate clear button', async () => {
|
|
59
|
+
// focus on clear button
|
|
60
|
+
const date = await canvas.findByText('January 10, 1987');
|
|
61
|
+
await expect(date).toBeInTheDocument();
|
|
62
|
+
await userEvent.tab();
|
|
63
|
+
await userEvent.tab();
|
|
64
|
+
|
|
65
|
+
// clear with space
|
|
66
|
+
await userEvent.keyboard('{enter}');
|
|
67
|
+
const placeholder = canvas.getByText('placeholder');
|
|
68
|
+
await expect(placeholder).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
};
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import
|
|
3
|
-
import { createRef, PureComponent } from 'react';
|
|
2
|
+
import { createRef, PureComponent, KeyboardEvent } from 'react';
|
|
4
3
|
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Size,
|
|
6
|
+
MonthFormat,
|
|
7
|
+
Position,
|
|
8
|
+
Breakpoint,
|
|
9
|
+
SizeSmall,
|
|
10
|
+
SizeMedium,
|
|
11
|
+
SizeLarge,
|
|
12
|
+
} from '../common';
|
|
6
13
|
import { isWithinRange, moveToWithinRange } from '../common/dateUtils';
|
|
7
14
|
import ResponsivePanel from '../common/responsivePanel';
|
|
8
15
|
|
|
@@ -12,18 +19,55 @@ import { getStartOfDay } from './getStartOfDay';
|
|
|
12
19
|
import MonthCalendar from './monthCalendar';
|
|
13
20
|
import YearCalendar from './yearCalendar';
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
export interface DateLookupProps {
|
|
23
|
+
id?: string;
|
|
24
|
+
value: Date | null;
|
|
25
|
+
min?: Date | null;
|
|
26
|
+
max?: Date | null;
|
|
27
|
+
size?: SizeSmall | SizeMedium | SizeLarge;
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
label?: string;
|
|
30
|
+
'aria-labelledby'?: string;
|
|
31
|
+
monthFormat?: `${MonthFormat}`;
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
clearable?: boolean;
|
|
34
|
+
onChange: (date: Date | null) => void;
|
|
35
|
+
onFocus?: () => void;
|
|
36
|
+
onBlur?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface DateLookupState {
|
|
40
|
+
selectedDate: Date | null;
|
|
41
|
+
originalDate: Date | null;
|
|
42
|
+
min: Date | null;
|
|
43
|
+
max: Date | null;
|
|
44
|
+
viewMonth: number;
|
|
45
|
+
viewYear: number;
|
|
46
|
+
open: boolean;
|
|
47
|
+
mode: 'day' | 'month' | 'year';
|
|
48
|
+
isMobile: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
class DateLookup extends PureComponent<DateLookupProps, DateLookupState> {
|
|
52
|
+
declare props: DateLookupProps &
|
|
53
|
+
Required<Pick<DateLookupProps, keyof typeof DateLookup.defaultProps>>;
|
|
20
54
|
|
|
21
|
-
|
|
22
|
-
|
|
55
|
+
static defaultProps = {
|
|
56
|
+
value: null,
|
|
57
|
+
min: null,
|
|
58
|
+
max: null,
|
|
59
|
+
size: Size.MEDIUM,
|
|
60
|
+
placeholder: '',
|
|
61
|
+
label: '',
|
|
62
|
+
monthFormat: MonthFormat.LONG,
|
|
63
|
+
disabled: false,
|
|
64
|
+
clearable: false,
|
|
65
|
+
} satisfies Partial<DateLookupProps>;
|
|
23
66
|
|
|
24
|
-
|
|
67
|
+
element = createRef<HTMLDivElement>();
|
|
68
|
+
dropdown = createRef<HTMLDivElement>();
|
|
25
69
|
|
|
26
|
-
constructor(props) {
|
|
70
|
+
constructor(props: DateLookup['props']) {
|
|
27
71
|
super(props);
|
|
28
72
|
this.state = {
|
|
29
73
|
selectedDate: getStartOfDay(props.value),
|
|
@@ -33,40 +77,41 @@ class DateLookup extends PureComponent {
|
|
|
33
77
|
viewMonth: (props.value || new Date()).getMonth(),
|
|
34
78
|
viewYear: (props.value || new Date()).getFullYear(),
|
|
35
79
|
open: false,
|
|
36
|
-
mode:
|
|
80
|
+
mode: 'day',
|
|
37
81
|
isMobile: false,
|
|
38
82
|
};
|
|
39
83
|
}
|
|
40
84
|
|
|
41
|
-
static getDerivedStateFromProps(props, state) {
|
|
85
|
+
static getDerivedStateFromProps(props: DateLookup['props'], state: DateLookupState) {
|
|
42
86
|
const propsSelected = getStartOfDay(props.value);
|
|
43
87
|
const propsMin = getStartOfDay(props.min);
|
|
44
88
|
const propsMax = getStartOfDay(props.max);
|
|
45
|
-
const hasSelectedChanged =
|
|
46
|
-
const hasMinChanged =
|
|
47
|
-
const hasMaxChanged =
|
|
89
|
+
const hasSelectedChanged = state.selectedDate?.getTime() !== propsSelected?.getTime();
|
|
90
|
+
const hasMinChanged = state.min?.getTime() !== propsMin?.getTime();
|
|
91
|
+
const hasMaxChanged = state.max?.getTime() !== propsMax?.getTime();
|
|
48
92
|
if (hasSelectedChanged || hasMinChanged || hasMaxChanged) {
|
|
49
93
|
const selectedDate = hasSelectedChanged ? propsSelected : state.selectedDate;
|
|
50
94
|
const min = hasMinChanged ? propsMin : state.min;
|
|
51
95
|
const max = hasMaxChanged ? propsMax : state.max;
|
|
52
|
-
|
|
53
|
-
if (!isWithinRange(selectedDate, min, max)) {
|
|
96
|
+
if (selectedDate && !isWithinRange(selectedDate, min, max)) {
|
|
54
97
|
props.onChange(moveToWithinRange(selectedDate, min, max));
|
|
55
98
|
return null;
|
|
56
99
|
}
|
|
57
|
-
const
|
|
58
|
-
|
|
100
|
+
const viewDateThatIsWithinRange: Date =
|
|
101
|
+
selectedDate || ((min || max) && moveToWithinRange(new Date(), min, max)) || new Date();
|
|
102
|
+
const viewMonth = viewDateThatIsWithinRange.getMonth();
|
|
103
|
+
const viewYear = viewDateThatIsWithinRange.getFullYear();
|
|
59
104
|
return { selectedDate, min, max, viewMonth, viewYear };
|
|
60
105
|
}
|
|
61
106
|
return null;
|
|
62
107
|
}
|
|
63
108
|
|
|
64
|
-
componentDidUpdate(previousProps) {
|
|
65
|
-
if (
|
|
109
|
+
componentDidUpdate(previousProps: DateLookupProps) {
|
|
110
|
+
if (this.props.value?.getTime() !== previousProps.value?.getTime() && this.state.open) {
|
|
66
111
|
this.focusOn('.active');
|
|
67
112
|
}
|
|
68
|
-
|
|
69
|
-
this.setState({ isMobile:
|
|
113
|
+
const mediaQuery = window.matchMedia(`(max-width: ${Breakpoint.SMALL}px)`);
|
|
114
|
+
this.setState({ isMobile: mediaQuery.matches });
|
|
70
115
|
}
|
|
71
116
|
|
|
72
117
|
componentWillUnmount() {
|
|
@@ -77,7 +122,7 @@ class DateLookup extends PureComponent {
|
|
|
77
122
|
open = () => {
|
|
78
123
|
const { onFocus } = this.props;
|
|
79
124
|
|
|
80
|
-
this.setState({ open: true, mode:
|
|
125
|
+
this.setState({ open: true, mode: 'day' });
|
|
81
126
|
if (onFocus) {
|
|
82
127
|
onFocus();
|
|
83
128
|
}
|
|
@@ -99,7 +144,7 @@ class DateLookup extends PureComponent {
|
|
|
99
144
|
}
|
|
100
145
|
};
|
|
101
146
|
|
|
102
|
-
handleKeyDown = (event) => {
|
|
147
|
+
handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
|
103
148
|
const { open, originalDate } = this.state;
|
|
104
149
|
switch (event.key) {
|
|
105
150
|
case 'ArrowLeft':
|
|
@@ -146,29 +191,31 @@ class DateLookup extends PureComponent {
|
|
|
146
191
|
}
|
|
147
192
|
};
|
|
148
193
|
|
|
149
|
-
adjustDate = (daysToAdd, monthsToAdd, yearsToAdd) => {
|
|
194
|
+
adjustDate = (daysToAdd: number, monthsToAdd: number, yearsToAdd: number) => {
|
|
150
195
|
const { selectedDate, min, max, mode, originalDate } = this.state;
|
|
151
196
|
if (originalDate === null) {
|
|
152
197
|
this.setState({ originalDate: selectedDate });
|
|
153
198
|
}
|
|
154
|
-
let date;
|
|
199
|
+
let date: Date | null;
|
|
155
200
|
if (selectedDate) {
|
|
156
201
|
date = new Date(
|
|
157
|
-
mode ===
|
|
158
|
-
mode ===
|
|
159
|
-
mode ===
|
|
202
|
+
mode === 'year' ? selectedDate.getFullYear() + yearsToAdd : selectedDate.getFullYear(),
|
|
203
|
+
mode === 'month' ? selectedDate.getMonth() + monthsToAdd : selectedDate.getMonth(),
|
|
204
|
+
mode === 'day' ? selectedDate.getDate() + daysToAdd : selectedDate.getDate(),
|
|
160
205
|
);
|
|
161
206
|
} else {
|
|
162
207
|
date = getStartOfDay(new Date());
|
|
163
208
|
}
|
|
164
|
-
|
|
165
|
-
|
|
209
|
+
if (date) {
|
|
210
|
+
date = moveToWithinRange(date, min, max);
|
|
211
|
+
}
|
|
212
|
+
if (date?.getTime() !== selectedDate?.getTime()) {
|
|
166
213
|
this.props.onChange(date);
|
|
167
214
|
}
|
|
168
215
|
};
|
|
169
216
|
|
|
170
|
-
focusOn = (preferredElement, fallbackElement) => {
|
|
171
|
-
const element = this.element.current
|
|
217
|
+
focusOn = (preferredElement: string, fallbackElement?: string) => {
|
|
218
|
+
const element = this.element.current?.querySelector(preferredElement) as HTMLElement | null;
|
|
172
219
|
if (element) {
|
|
173
220
|
element.focus();
|
|
174
221
|
} else if (fallbackElement) {
|
|
@@ -176,19 +223,19 @@ class DateLookup extends PureComponent {
|
|
|
176
223
|
}
|
|
177
224
|
};
|
|
178
225
|
|
|
179
|
-
switchMode = (mode) => {
|
|
226
|
+
switchMode = (mode: 'day' | 'month' | 'year') => {
|
|
180
227
|
this.setState({ mode }, () => {
|
|
181
228
|
this.focusOn('.active', '.today');
|
|
182
229
|
});
|
|
183
230
|
};
|
|
184
231
|
|
|
185
|
-
switchToDays = () => this.switchMode(
|
|
232
|
+
switchToDays = () => this.switchMode('day');
|
|
186
233
|
|
|
187
|
-
switchToMonths = () => this.switchMode(
|
|
234
|
+
switchToMonths = () => this.switchMode('month');
|
|
188
235
|
|
|
189
|
-
switchToYears = () => this.switchMode(
|
|
236
|
+
switchToYears = () => this.switchMode('year');
|
|
190
237
|
|
|
191
|
-
handleSelectedDateUpdate = (selectedDate) => {
|
|
238
|
+
handleSelectedDateUpdate = (selectedDate: Date) => {
|
|
192
239
|
this.setState({ selectedDate }, () => {
|
|
193
240
|
this.props.onChange(selectedDate);
|
|
194
241
|
this.close();
|
|
@@ -205,25 +252,38 @@ class DateLookup extends PureComponent {
|
|
|
205
252
|
const { placeholder, monthFormat } = this.props;
|
|
206
253
|
return (
|
|
207
254
|
<div className={classNames({ 'p-a-1': !isMobile })}>
|
|
208
|
-
{mode ===
|
|
255
|
+
{mode === 'day' && (
|
|
209
256
|
<DayCalendar
|
|
210
|
-
{
|
|
257
|
+
selectedDate={selectedDate}
|
|
258
|
+
min={min}
|
|
259
|
+
max={max}
|
|
260
|
+
viewMonth={viewMonth}
|
|
261
|
+
viewYear={viewYear}
|
|
262
|
+
monthFormat={monthFormat}
|
|
211
263
|
onSelect={this.handleSelectedDateUpdate}
|
|
212
264
|
onLabelClick={this.switchToYears}
|
|
213
265
|
onViewDateUpdate={this.handleViewDateUpdate}
|
|
214
266
|
/>
|
|
215
267
|
)}
|
|
216
|
-
{mode ===
|
|
268
|
+
{mode === 'month' && (
|
|
217
269
|
<MonthCalendar
|
|
218
|
-
{
|
|
270
|
+
selectedDate={selectedDate}
|
|
271
|
+
min={min}
|
|
272
|
+
max={max}
|
|
273
|
+
viewYear={viewYear}
|
|
274
|
+
placeholder={placeholder}
|
|
219
275
|
onSelect={this.switchToDays}
|
|
220
276
|
onLabelClick={this.switchToYears}
|
|
221
277
|
onViewDateUpdate={this.handleViewDateUpdate}
|
|
222
278
|
/>
|
|
223
279
|
)}
|
|
224
|
-
{mode ===
|
|
280
|
+
{mode === 'year' && (
|
|
225
281
|
<YearCalendar
|
|
226
|
-
{
|
|
282
|
+
selectedDate={selectedDate}
|
|
283
|
+
min={min}
|
|
284
|
+
max={max}
|
|
285
|
+
viewYear={viewYear}
|
|
286
|
+
placeholder={placeholder}
|
|
227
287
|
onSelect={this.switchToMonths}
|
|
228
288
|
onViewDateUpdate={this.handleViewDateUpdate}
|
|
229
289
|
/>
|
|
@@ -251,7 +311,7 @@ class DateLookup extends PureComponent {
|
|
|
251
311
|
value,
|
|
252
312
|
} = this.props;
|
|
253
313
|
return (
|
|
254
|
-
<div
|
|
314
|
+
<div
|
|
255
315
|
ref={this.element}
|
|
256
316
|
id={this.props.id}
|
|
257
317
|
aria-labelledby={ariaLabelledBy}
|
|
@@ -259,9 +319,14 @@ class DateLookup extends PureComponent {
|
|
|
259
319
|
onKeyDown={this.handleKeyDown}
|
|
260
320
|
>
|
|
261
321
|
<DateTrigger
|
|
262
|
-
{
|
|
322
|
+
selectedDate={selectedDate}
|
|
323
|
+
size={size}
|
|
324
|
+
placeholder={placeholder}
|
|
325
|
+
label={label}
|
|
326
|
+
monthFormat={monthFormat}
|
|
327
|
+
disabled={disabled || false}
|
|
263
328
|
onClick={this.open}
|
|
264
|
-
onClear={!disabled && clearable && value ? this.handleClear :
|
|
329
|
+
onClear={!disabled && clearable && value ? this.handleClear : undefined}
|
|
265
330
|
/>
|
|
266
331
|
<ResponsivePanel
|
|
267
332
|
anchorRef={this.element}
|
|
@@ -277,35 +342,4 @@ class DateLookup extends PureComponent {
|
|
|
277
342
|
}
|
|
278
343
|
}
|
|
279
344
|
|
|
280
|
-
DateLookup.propTypes = {
|
|
281
|
-
id: PropTypes.string,
|
|
282
|
-
value: PropTypes.instanceOf(Date),
|
|
283
|
-
min: PropTypes.instanceOf(Date),
|
|
284
|
-
max: PropTypes.instanceOf(Date),
|
|
285
|
-
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
|
286
|
-
placeholder: PropTypes.string,
|
|
287
|
-
label: PropTypes.string,
|
|
288
|
-
'aria-labelledby': PropTypes.string,
|
|
289
|
-
monthFormat: PropTypes.oneOf(['long', 'short']),
|
|
290
|
-
disabled: PropTypes.bool,
|
|
291
|
-
onChange: PropTypes.func.isRequired,
|
|
292
|
-
onFocus: PropTypes.func,
|
|
293
|
-
onBlur: PropTypes.func,
|
|
294
|
-
clearable: PropTypes.bool,
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
DateLookup.defaultProps = {
|
|
298
|
-
value: null,
|
|
299
|
-
min: null,
|
|
300
|
-
max: null,
|
|
301
|
-
size: Size.MEDIUM,
|
|
302
|
-
placeholder: '',
|
|
303
|
-
label: '',
|
|
304
|
-
monthFormat: MonthFormat.LONG,
|
|
305
|
-
disabled: false,
|
|
306
|
-
onFocus: null,
|
|
307
|
-
onBlur: null,
|
|
308
|
-
clearable: false,
|
|
309
|
-
};
|
|
310
|
-
|
|
311
345
|
export default DateLookup;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
2
|
import { useIntl } from 'react-intl';
|
|
4
3
|
|
|
5
4
|
import Chevron from '../../chevron';
|
|
@@ -10,7 +9,21 @@ import messages from '../DateLookup.messages';
|
|
|
10
9
|
|
|
11
10
|
const buttonClasses = 'btn-link p-a-0 text-no-decoration np-text-body-large-bold rounded-sm';
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
interface DateHeaderProps {
|
|
13
|
+
label?: string;
|
|
14
|
+
onLabelClick?: () => void;
|
|
15
|
+
onPreviousClick: () => void;
|
|
16
|
+
onNextClick: () => void;
|
|
17
|
+
dateMode: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DateHeader: React.FC<DateHeaderProps> = ({
|
|
21
|
+
label,
|
|
22
|
+
onLabelClick,
|
|
23
|
+
onPreviousClick,
|
|
24
|
+
onNextClick,
|
|
25
|
+
dateMode,
|
|
26
|
+
}) => {
|
|
14
27
|
const intl = useIntl();
|
|
15
28
|
const { isMobile } = useLayout();
|
|
16
29
|
return (
|
|
@@ -59,17 +72,4 @@ const DateHeader = ({ label, onLabelClick, onPreviousClick, onNextClick, dateMod
|
|
|
59
72
|
);
|
|
60
73
|
};
|
|
61
74
|
|
|
62
|
-
DateHeader.propTypes = {
|
|
63
|
-
label: PropTypes.string,
|
|
64
|
-
onLabelClick: PropTypes.func,
|
|
65
|
-
onPreviousClick: PropTypes.func.isRequired,
|
|
66
|
-
onNextClick: PropTypes.func.isRequired,
|
|
67
|
-
dateMode: PropTypes.string,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
DateHeader.defaultProps = {
|
|
71
|
-
label: null,
|
|
72
|
-
onLabelClick: () => {},
|
|
73
|
-
};
|
|
74
|
-
|
|
75
75
|
export default DateHeader;
|
|
@@ -2,7 +2,6 @@ import * as formatting from '@transferwise/formatting';
|
|
|
2
2
|
import { shallow } from 'enzyme';
|
|
3
3
|
|
|
4
4
|
import Chevron from '../../chevron';
|
|
5
|
-
import { fakeKeyDownEventForKey } from '../../common/fakeEvents';
|
|
6
5
|
|
|
7
6
|
import DateTrigger from '.';
|
|
8
7
|
|
|
@@ -116,27 +115,6 @@ describe('DateTrigger', () => {
|
|
|
116
115
|
expect(clearButton()).toHaveLength(1);
|
|
117
116
|
});
|
|
118
117
|
|
|
119
|
-
it('calls onClear when user press Space', () => {
|
|
120
|
-
const onClear = jest.fn();
|
|
121
|
-
component.setProps({ onClear });
|
|
122
|
-
clearButton().simulate('keypress', fakeKeyDownEventForKey(' '));
|
|
123
|
-
expect(onClear).toHaveBeenCalledTimes(1);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('calls onClear when user press Enter', () => {
|
|
127
|
-
const onClear = jest.fn();
|
|
128
|
-
component.setProps({ onClear });
|
|
129
|
-
clearButton().simulate('keypress', fakeKeyDownEventForKey('Enter'));
|
|
130
|
-
expect(onClear).toHaveBeenCalledTimes(1);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it(`doesn't call onClear when user press a random key`, () => {
|
|
134
|
-
const onClear = jest.fn();
|
|
135
|
-
component.setProps({ onClear });
|
|
136
|
-
clearButton().simulate('keypress', fakeKeyDownEventForKey('r'));
|
|
137
|
-
expect(onClear).not.toHaveBeenCalled();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
118
|
const button = () => component.find('.np-date-trigger');
|
|
141
119
|
const clearButton = () => component.find('.clear-btn');
|
|
142
120
|
const chevron = () => component.find(Chevron);
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { formatDate } from '@transferwise/formatting';
|
|
2
|
-
import { isKey } from '@transferwise/neptune-validation';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
2
|
import { useIntl } from 'react-intl';
|
|
5
3
|
|
|
6
4
|
import Chevron from '../../chevron';
|
|
7
|
-
import { Size, Position } from '../../common';
|
|
5
|
+
import { Size, Position, SizeSmall, SizeMedium, SizeLarge } from '../../common';
|
|
8
6
|
import { CloseButton } from '../../common/closeButton/CloseButton';
|
|
9
7
|
|
|
10
8
|
import messages from './DateTrigger.messages';
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
interface DateTriggerProps {
|
|
11
|
+
selectedDate: Date | null;
|
|
12
|
+
size: SizeSmall | SizeMedium | SizeLarge;
|
|
13
|
+
placeholder: string;
|
|
14
|
+
label: string;
|
|
15
|
+
monthFormat: 'short' | 'long';
|
|
16
|
+
disabled: boolean;
|
|
17
|
+
onClick: () => void;
|
|
18
|
+
onClear?: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const DateTrigger: React.FC<DateTriggerProps> = ({
|
|
13
22
|
selectedDate,
|
|
14
|
-
size,
|
|
23
|
+
size = Size.MEDIUM,
|
|
15
24
|
placeholder,
|
|
16
25
|
label,
|
|
17
26
|
monthFormat,
|
|
@@ -21,14 +30,6 @@ const DateTrigger = ({
|
|
|
21
30
|
}) => {
|
|
22
31
|
const { locale, formatMessage } = useIntl();
|
|
23
32
|
|
|
24
|
-
const handleKeyDown = (event) => {
|
|
25
|
-
if (isKey({ keyType: 'Space', event: event }) || isKey({ keyType: 'Enter', event: event })) {
|
|
26
|
-
event.stopPropagation();
|
|
27
|
-
event.preventDefault();
|
|
28
|
-
onClear();
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
33
|
return (
|
|
33
34
|
<>
|
|
34
35
|
<button
|
|
@@ -64,12 +65,11 @@ const DateTrigger = ({
|
|
|
64
65
|
className={`clear-btn clear-btn--${size}`}
|
|
65
66
|
aria-label={`${formatMessage(messages.ariaLabel)} ${label}`}
|
|
66
67
|
size={Size.SMALL}
|
|
67
|
-
onClick={(event) => {
|
|
68
|
+
onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
|
|
68
69
|
event.stopPropagation();
|
|
69
70
|
event.preventDefault();
|
|
70
71
|
onClear();
|
|
71
72
|
}}
|
|
72
|
-
onKeyPress={handleKeyDown}
|
|
73
73
|
/>
|
|
74
74
|
</span>
|
|
75
75
|
</>
|
|
@@ -78,21 +78,4 @@ const DateTrigger = ({
|
|
|
78
78
|
);
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
DateTrigger.propTypes = {
|
|
82
|
-
selectedDate: PropTypes.instanceOf(Date),
|
|
83
|
-
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
|
84
|
-
placeholder: PropTypes.string.isRequired,
|
|
85
|
-
label: PropTypes.string.isRequired,
|
|
86
|
-
monthFormat: PropTypes.oneOf(['short', 'long']).isRequired,
|
|
87
|
-
disabled: PropTypes.bool.isRequired,
|
|
88
|
-
onClick: PropTypes.func,
|
|
89
|
-
onClear: PropTypes.func,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
DateTrigger.defaultProps = {
|
|
93
|
-
selectedDate: null,
|
|
94
|
-
size: Size.MEDIUM,
|
|
95
|
-
onClear: undefined,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
81
|
export default DateTrigger;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { formatDate } from '@transferwise/formatting';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
2
|
import { PureComponent } from 'react';
|
|
4
|
-
import { injectIntl } from 'react-intl';
|
|
3
|
+
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
|
5
4
|
|
|
6
5
|
import { MonthFormat } from '../../common';
|
|
7
6
|
import messages from '../DateLookup.messages';
|
|
@@ -9,7 +8,19 @@ import DateHeader from '../dateHeader';
|
|
|
9
8
|
|
|
10
9
|
import DayCalendarTable from './table';
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
interface DayCalendarProps extends WrappedComponentProps {
|
|
12
|
+
selectedDate: Date | null;
|
|
13
|
+
min: Date | null;
|
|
14
|
+
max: Date | null;
|
|
15
|
+
viewMonth: number;
|
|
16
|
+
viewYear: number;
|
|
17
|
+
monthFormat: `${MonthFormat}`;
|
|
18
|
+
onSelect: (date: Date) => void;
|
|
19
|
+
onLabelClick: () => void;
|
|
20
|
+
onViewDateUpdate: (date: { month: number; year: number }) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class DayCalendar extends PureComponent<DayCalendarProps> {
|
|
13
24
|
selectPreviousMonth = () => {
|
|
14
25
|
const { viewMonth, viewYear } = this.props;
|
|
15
26
|
this.props.onViewDateUpdate({
|
|
@@ -56,22 +67,4 @@ class DayCalendar extends PureComponent {
|
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
DayCalendar.propTypes = {
|
|
60
|
-
selectedDate: PropTypes.instanceOf(Date),
|
|
61
|
-
min: PropTypes.instanceOf(Date),
|
|
62
|
-
max: PropTypes.instanceOf(Date),
|
|
63
|
-
viewMonth: PropTypes.number.isRequired,
|
|
64
|
-
viewYear: PropTypes.number.isRequired,
|
|
65
|
-
monthFormat: PropTypes.oneOf([MonthFormat.LONG, MonthFormat.SHORT]).isRequired,
|
|
66
|
-
onSelect: PropTypes.func.isRequired,
|
|
67
|
-
onLabelClick: PropTypes.func.isRequired,
|
|
68
|
-
onViewDateUpdate: PropTypes.func.isRequired,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
DayCalendar.defaultProps = {
|
|
72
|
-
selectedDate: null,
|
|
73
|
-
min: null,
|
|
74
|
-
max: null,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
70
|
export default injectIntl(DayCalendar);
|