@transferwise/components 46.27.0 → 46.29.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/index.js +344 -1147
- package/build/index.js.map +1 -1
- package/build/index.mjs +346 -1147
- package/build/index.mjs.map +1 -1
- package/build/main.css +16 -5
- package/build/styles/logo/Logo.css +16 -0
- package/build/styles/main.css +16 -5
- 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/dimmer/Dimmer.d.ts.map +1 -1
- package/build/types/index.d.ts +2 -2
- 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/loader/Loader.d.ts.map +1 -1
- package/build/types/logo/Logo.d.ts.map +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
- package/build/types/popover/Popover.d.ts.map +1 -1
- package/build/types/segmentedControl/SegmentedControl.d.ts +2 -2
- package/build/types/segmentedControl/SegmentedControl.d.ts.map +1 -1
- package/build/types/select/Select.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/build/types/stepper/deviceDetection.d.ts.map +1 -1
- package/build/types/uploadInput/uploadButton/UploadButton.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/accordion/Accordion.story.tsx +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 +219 -0
- package/src/alert/index.ts +2 -0
- package/src/avatar/colors/colors.ts +1 -1
- package/src/body/Body.spec.tsx +1 -1
- package/src/body/Body.story.tsx +8 -8
- package/src/button/Button.tsx +6 -10
- package/src/checkbox/Checkbox.js +1 -1
- package/src/checkboxButton/CheckboxButton.spec.tsx +0 -1
- package/src/common/Option/Option.tsx +1 -1
- 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/deviceDetection/deviceDetection.js +1 -1
- package/src/common/deviceDetection/deviceDetection.spec.js +4 -2
- package/src/common/propsValues/sentiment.ts +0 -10
- package/src/common/responsivePanel/ResponsivePanel.spec.js +11 -15
- 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/decision/Decision.spec.js +0 -1
- package/src/dimmer/Dimmer.tsx +6 -2
- package/src/i18n/th.json +2 -2
- package/src/index.ts +2 -2
- package/src/inlineAlert/InlineAlert.spec.tsx +0 -7
- package/src/inlineAlert/InlineAlert.story.tsx +8 -7
- package/src/inlineAlert/InlineAlert.tsx +19 -47
- package/src/inputs/InputGroup.tsx +3 -3
- package/src/inputs/SelectInput.tsx +2 -0
- package/src/inputs/_BottomSheet.tsx +21 -26
- package/src/inputs/_Popover.tsx +4 -4
- package/src/link/Link.story.tsx +16 -16
- package/src/loader/Loader.tsx +0 -1
- package/src/logo/Logo.css +16 -0
- package/src/logo/Logo.js +4 -9
- package/src/logo/Logo.less +16 -0
- package/src/logo/__snapshots__/Logo.spec.js.snap +104 -8
- package/src/main.css +16 -5
- package/src/main.less +0 -1
- package/src/moneyInput/MoneyInput.story.tsx +3 -3
- package/src/nudge/Nudge.spec.tsx +5 -5
- package/src/phoneNumberInput/PhoneNumberInput.tsx +2 -1
- package/src/phoneNumberInput/utils/cleanNumber/cleanNumber.ts +1 -1
- package/src/popover/Popover.tsx +2 -1
- package/src/promoCard/PromoCard.tsx +1 -1
- package/src/radioGroup/RadioGroup.spec.js +1 -1
- package/src/section/Section.story.tsx +2 -1
- package/src/segmentedControl/SegmentedControl.spec.tsx +88 -2
- package/src/segmentedControl/SegmentedControl.story.tsx +54 -16
- package/src/segmentedControl/SegmentedControl.tsx +21 -33
- package/src/select/Select.js +2 -3
- package/src/statusIcon/StatusIcon.tsx +14 -14
- package/src/stepper/deviceDetection.js +1 -2
- package/src/stepper/deviceDetection.spec.js +8 -3
- package/src/test-utils/index.js +1 -1
- package/src/test-utils/story-config.ts +1 -1
- package/src/title/Title.spec.tsx +1 -1
- package/src/typeahead/Typeahead.spec.js +4 -2
- package/src/upload/Upload.spec.js +8 -4
- package/src/uploadInput/uploadButton/UploadButton.tsx +1 -0
- package/build/styles/dynamicFieldDefinitionList/FormattedValue/FormattedValue.css +0 -5
- 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/build/types/common/requirements.d.ts +0 -3
- package/build/types/common/requirements.d.ts.map +0 -1
- package/build/types/dynamicFieldDefinitionList/DynamicFieldDefinitionList.d.ts +0 -21
- package/build/types/dynamicFieldDefinitionList/DynamicFieldDefinitionList.d.ts.map +0 -1
- package/build/types/dynamicFieldDefinitionList/FormattedValue/FormattedValue.d.ts +0 -12
- package/build/types/dynamicFieldDefinitionList/FormattedValue/FormattedValue.d.ts.map +0 -1
- package/build/types/dynamicFieldDefinitionList/FormattedValue/index.d.ts +0 -2
- package/build/types/dynamicFieldDefinitionList/FormattedValue/index.d.ts.map +0 -1
- package/build/types/dynamicFieldDefinitionList/index.d.ts +0 -2
- package/build/types/dynamicFieldDefinitionList/index.d.ts.map +0 -1
- package/build/types/dynamicFieldDefinitionList/utils/createDefinitions.d.ts +0 -2
- package/build/types/dynamicFieldDefinitionList/utils/createDefinitions.d.ts.map +0 -1
- package/build/types/dynamicFieldDefinitionList/utils/text-format.d.ts +0 -2
- package/build/types/dynamicFieldDefinitionList/utils/text-format.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/dynamicFieldDefinitionList/DynamicFieldDefinitionList.js +0 -41
- package/src/dynamicFieldDefinitionList/DynamicFieldDefinitionList.spec.js +0 -21
- package/src/dynamicFieldDefinitionList/DynamicFieldDefinitionList.story.js +0 -134
- package/src/dynamicFieldDefinitionList/FormattedValue/FormattedValue.css +0 -5
- package/src/dynamicFieldDefinitionList/FormattedValue/FormattedValue.js +0 -73
- package/src/dynamicFieldDefinitionList/FormattedValue/FormattedValue.less +0 -4
- package/src/dynamicFieldDefinitionList/FormattedValue/FormattedValue.spec.js +0 -200
- package/src/dynamicFieldDefinitionList/FormattedValue/index.js +0 -1
- package/src/dynamicFieldDefinitionList/index.js +0 -1
- package/src/dynamicFieldDefinitionList/utils/createDefinitions.js +0 -33
- package/src/dynamicFieldDefinitionList/utils/createDefinitions.spec.js +0 -83
- package/src/dynamicFieldDefinitionList/utils/text-format.js +0 -46
- package/src/dynamicFieldDefinitionList/utils/text-format.spec.js +0 -43
- /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
|
@@ -2,8 +2,10 @@ import { isIosDevice } from './deviceDetection';
|
|
|
2
2
|
|
|
3
3
|
describe('Device detection', () => {
|
|
4
4
|
function fakeUserAgent(userAgent) {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
Object.defineProperty(navigator, 'userAgent', {
|
|
6
|
+
value: userAgent,
|
|
7
|
+
configurable: true,
|
|
8
|
+
});
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
beforeEach(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Breakpoint, Position } from '..';
|
|
2
|
-
import { mockMatchMedia, render
|
|
2
|
+
import { mockMatchMedia, render } from '../../test-utils';
|
|
3
3
|
|
|
4
4
|
import ResponsivePanel from './ResponsivePanel';
|
|
5
5
|
|
|
@@ -45,13 +45,11 @@ describe('ResponsivePanel', () => {
|
|
|
45
45
|
|
|
46
46
|
describe('on desktop', () => {
|
|
47
47
|
it('renders Panel', async () => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
));
|
|
54
|
-
});
|
|
48
|
+
({ container } = render(
|
|
49
|
+
<ResponsivePanel {...props} intialOpen>
|
|
50
|
+
children
|
|
51
|
+
</ResponsivePanel>,
|
|
52
|
+
));
|
|
55
53
|
|
|
56
54
|
expect(container).toMatchSnapshot();
|
|
57
55
|
});
|
|
@@ -63,13 +61,11 @@ describe('ResponsivePanel', () => {
|
|
|
63
61
|
});
|
|
64
62
|
|
|
65
63
|
it('renders bottomSheet', async () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
));
|
|
72
|
-
});
|
|
64
|
+
({ container } = render(
|
|
65
|
+
<ResponsivePanel {...props} open>
|
|
66
|
+
children
|
|
67
|
+
</ResponsivePanel>,
|
|
68
|
+
));
|
|
73
69
|
|
|
74
70
|
expect(container).toMatchSnapshot();
|
|
75
71
|
});
|
|
@@ -66,4 +66,11 @@ describe('DateLookup state', () => {
|
|
|
66
66
|
DateLookup.getDerivedStateFromProps(props, defaultState);
|
|
67
67
|
expect(onChange).toHaveBeenCalledWith(new Date(2018, 10, 1));
|
|
68
68
|
});
|
|
69
|
+
|
|
70
|
+
it('updates viewMonth and viewYear to date within min/max on Clear', () => {
|
|
71
|
+
const props = { value: null, min: new Date(2018, 11, 26), max: new Date(2018, 11, 26) };
|
|
72
|
+
const newState = DateLookup.getDerivedStateFromProps(props, defaultState);
|
|
73
|
+
expect(newState.viewMonth).toBe(11);
|
|
74
|
+
expect(newState.viewYear).toBe(2018);
|
|
75
|
+
});
|
|
69
76
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { boolean, select,
|
|
2
|
-
import { userEvent
|
|
1
|
+
import { boolean, select, text, date } from '@storybook/addon-knobs';
|
|
2
|
+
import { userEvent } from '@storybook/test';
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { Size } from '../common';
|
|
@@ -13,21 +13,21 @@ export default {
|
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const epoch = new Date('2011-01-01');
|
|
16
|
-
|
|
16
|
+
const theFuture = new Date(epoch);
|
|
17
17
|
theFuture.setUTCDate(epoch.getUTCDate() + 10);
|
|
18
|
-
|
|
18
|
+
const thePast = new Date(epoch);
|
|
19
19
|
thePast.setUTCDate(epoch.getUTCDate() - 10);
|
|
20
|
+
const size = select('size', Object.values([Size.SMALL, Size.MEDIUM, Size.LARGE]), Size.MEDIUM);
|
|
20
21
|
|
|
21
22
|
export const Basic = () => {
|
|
22
|
-
const [value, setValue] = useState(epoch);
|
|
23
|
+
const [value, setValue] = useState<Date | null>(epoch);
|
|
23
24
|
const disabled = boolean('disabled', false);
|
|
24
25
|
const label = text('label', 'label');
|
|
25
|
-
const monthFormat = select('monthFormat', ['long', 'short']);
|
|
26
|
+
const monthFormat = select('monthFormat', ['long', 'short'], 'long');
|
|
26
27
|
const placeholder = text('placeholder', 'placeholder');
|
|
27
|
-
const size = select('size', Object.values(Size), Size.MEDIUM);
|
|
28
28
|
const id = text('id', 'date-lookup');
|
|
29
29
|
|
|
30
|
-
const clearable = boolean('clearable',
|
|
30
|
+
const clearable = boolean('clearable', true);
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<DateLookup
|
|
@@ -35,6 +35,7 @@ export const Basic = () => {
|
|
|
35
35
|
id={id}
|
|
36
36
|
label={label}
|
|
37
37
|
min={thePast}
|
|
38
|
+
max={theFuture}
|
|
38
39
|
monthFormat={monthFormat}
|
|
39
40
|
placeholder={placeholder}
|
|
40
41
|
size={size}
|
|
@@ -48,10 +49,9 @@ export const Basic = () => {
|
|
|
48
49
|
);
|
|
49
50
|
};
|
|
50
51
|
|
|
51
|
-
Basic.play = async ({ canvasElement }) => {
|
|
52
|
+
Basic.play = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
|
52
53
|
// testing focus state on keyboard nav
|
|
53
|
-
|
|
54
|
-
await userEvent.tab(canvas.getByRole('button'));
|
|
54
|
+
await userEvent.tab();
|
|
55
55
|
await userEvent.keyboard(' ');
|
|
56
56
|
};
|
|
57
57
|
|
|
@@ -61,12 +61,11 @@ export const Basic400Zoom = storyConfig(
|
|
|
61
61
|
);
|
|
62
62
|
|
|
63
63
|
export const RightAligned = () => {
|
|
64
|
-
const [value, setValue] = useState(epoch);
|
|
64
|
+
const [value, setValue] = useState<Date | null>(epoch);
|
|
65
65
|
const disabled = boolean('disabled', false);
|
|
66
66
|
const label = text('label', 'label');
|
|
67
|
-
const monthFormat = select('monthFormat', ['long', 'short']);
|
|
67
|
+
const monthFormat = select('monthFormat', ['long', 'short'], 'long');
|
|
68
68
|
const placeholder = text('placeholder', 'placeholder');
|
|
69
|
-
const size = select('size', Object.values(Size), Size.MEDIUM);
|
|
70
69
|
|
|
71
70
|
const minvalue = date('minvalue', thePast);
|
|
72
71
|
const maxvalue = date('maxvalue', theFuture);
|
|
@@ -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);
|