@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
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
import {
|
|
3
|
-
InfoCircle,
|
|
4
|
-
CheckCircle,
|
|
5
|
-
AlertCircle,
|
|
6
|
-
Warning as AlertIcon,
|
|
7
|
-
HappyEmoji,
|
|
8
|
-
} from '@transferwise/icons';
|
|
2
|
+
import { HappyEmoji } from '@transferwise/icons';
|
|
9
3
|
import { ThemeProvider } from '@wise/components-theming';
|
|
10
4
|
import React from 'react';
|
|
11
5
|
|
|
12
6
|
import { Sentiment, Size, Theme, Variant } from '../common';
|
|
13
7
|
import { render, cleanup, screen, userEvent, fireEvent } from '../test-utils';
|
|
14
8
|
|
|
15
|
-
import Alert from './Alert';
|
|
16
|
-
import { AlertArrowPosition } from './withArrow';
|
|
9
|
+
import Alert, { AlertAction, AlertArrowPosition, AlertType } from './Alert';
|
|
17
10
|
|
|
18
11
|
jest.mock('react', () => {
|
|
19
|
-
const originReact = jest.requireActual('react');
|
|
12
|
+
const originReact = jest.requireActual<typeof import('react')>('react');
|
|
20
13
|
const mUseReference = jest.fn();
|
|
21
14
|
return {
|
|
22
15
|
...originReact,
|
|
@@ -25,20 +18,18 @@ jest.mock('react', () => {
|
|
|
25
18
|
});
|
|
26
19
|
|
|
27
20
|
describe('Alert', () => {
|
|
28
|
-
let component;
|
|
29
|
-
let container;
|
|
30
|
-
let alert;
|
|
31
|
-
let closeButton;
|
|
32
|
-
let action;
|
|
21
|
+
let component: HTMLElement;
|
|
22
|
+
let container: HTMLElement;
|
|
23
|
+
let alert: HTMLElement;
|
|
24
|
+
let closeButton: HTMLElement;
|
|
25
|
+
let action: AlertAction;
|
|
33
26
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const classForType = (type) => `alert-${type}`;
|
|
27
|
+
const classForType = (type: AlertType) => `alert-${type}`;
|
|
37
28
|
|
|
38
29
|
const message = 'Your card is on its way.';
|
|
39
30
|
|
|
40
31
|
const origWarn = console.warn;
|
|
41
|
-
let mockedWarn;
|
|
32
|
+
let mockedWarn: jest.Mock;
|
|
42
33
|
|
|
43
34
|
beforeAll(() => {
|
|
44
35
|
mockedWarn = jest.fn();
|
|
@@ -56,11 +47,11 @@ describe('Alert', () => {
|
|
|
56
47
|
|
|
57
48
|
describe('defaults', () => {
|
|
58
49
|
beforeEach(() => {
|
|
59
|
-
|
|
50
|
+
container = render(
|
|
60
51
|
<ThemeProvider theme={Theme.LIGHT}>
|
|
61
52
|
<Alert message={message} />
|
|
62
53
|
</ThemeProvider>,
|
|
63
|
-
)
|
|
54
|
+
).container;
|
|
64
55
|
component = screen.getByTestId('alert');
|
|
65
56
|
});
|
|
66
57
|
|
|
@@ -70,7 +61,7 @@ describe('Alert', () => {
|
|
|
70
61
|
|
|
71
62
|
it('will be of type neutral', () => {
|
|
72
63
|
expect(component).toHaveClass(classForType(Sentiment.NEUTRAL));
|
|
73
|
-
expect(screen.getByTestId('info-
|
|
64
|
+
expect(screen.getByTestId('info-icon')).toBeInTheDocument();
|
|
74
65
|
});
|
|
75
66
|
|
|
76
67
|
it('is not dismissible', () => {
|
|
@@ -90,7 +81,9 @@ describe('Alert', () => {
|
|
|
90
81
|
expect(component).toHaveClass('arrow');
|
|
91
82
|
expect(component).toHaveClass('arrow-bottom');
|
|
92
83
|
expect(mockedWarn).toHaveBeenCalledWith(
|
|
93
|
-
expect.stringContaining(
|
|
84
|
+
expect.stringContaining(
|
|
85
|
+
"Alert component doesn't support 'arrow' anymore, use 'InlineAlert' instead.",
|
|
86
|
+
),
|
|
94
87
|
);
|
|
95
88
|
});
|
|
96
89
|
|
|
@@ -99,7 +92,9 @@ describe('Alert', () => {
|
|
|
99
92
|
|
|
100
93
|
expect(screen.getByText(message)).toBeInTheDocument();
|
|
101
94
|
expect(mockedWarn).toHaveBeenCalledWith(
|
|
102
|
-
expect.stringContaining(
|
|
95
|
+
expect.stringContaining(
|
|
96
|
+
"Alert component doesn't support 'children' anymore, use 'message' instead.",
|
|
97
|
+
),
|
|
103
98
|
);
|
|
104
99
|
});
|
|
105
100
|
|
|
@@ -108,7 +103,9 @@ describe('Alert', () => {
|
|
|
108
103
|
|
|
109
104
|
expect(container.querySelector('button')).not.toBeInTheDocument();
|
|
110
105
|
expect(mockedWarn).toHaveBeenCalledWith(
|
|
111
|
-
expect.stringContaining(
|
|
106
|
+
expect.stringContaining(
|
|
107
|
+
"Alert component doesn't support 'dismissible' anymore, use 'onDismiss' instead.",
|
|
108
|
+
),
|
|
112
109
|
);
|
|
113
110
|
});
|
|
114
111
|
|
|
@@ -118,7 +115,9 @@ describe('Alert', () => {
|
|
|
118
115
|
|
|
119
116
|
expect(small.innerHTML).toStrictEqual(large.innerHTML);
|
|
120
117
|
expect(mockedWarn).toHaveBeenCalledWith(
|
|
121
|
-
expect.stringContaining(
|
|
118
|
+
expect.stringContaining(
|
|
119
|
+
"Alert component doesn't support 'size' anymore, please remove that prop.",
|
|
120
|
+
),
|
|
122
121
|
);
|
|
123
122
|
});
|
|
124
123
|
|
|
@@ -128,9 +127,9 @@ describe('Alert', () => {
|
|
|
128
127
|
const success = screen.getByTestId('alert');
|
|
129
128
|
|
|
130
129
|
expect(success).toHaveClass(classForType(Sentiment.POSITIVE));
|
|
131
|
-
expect(screen.getByTestId('check-
|
|
130
|
+
expect(screen.getByTestId('check-icon')).toBeInTheDocument();
|
|
132
131
|
expect(mockedWarn).toHaveBeenCalledWith(
|
|
133
|
-
|
|
132
|
+
"Alert component has deprecated 'success' value for the 'type' prop. Please use 'positive' instead.",
|
|
134
133
|
);
|
|
135
134
|
});
|
|
136
135
|
|
|
@@ -140,9 +139,9 @@ describe('Alert', () => {
|
|
|
140
139
|
const info = screen.getByTestId('alert');
|
|
141
140
|
|
|
142
141
|
expect(info).toHaveClass(classForType(Sentiment.NEUTRAL));
|
|
143
|
-
expect(screen.getByTestId('info-
|
|
142
|
+
expect(screen.getByTestId('info-icon')).toBeInTheDocument();
|
|
144
143
|
expect(mockedWarn).toHaveBeenCalledWith(
|
|
145
|
-
|
|
144
|
+
"Alert component has deprecated 'info' value for the 'type' prop. Please use 'neutral' instead.",
|
|
146
145
|
);
|
|
147
146
|
});
|
|
148
147
|
});
|
|
@@ -153,9 +152,11 @@ describe('Alert', () => {
|
|
|
153
152
|
const error = screen.getByTestId('alert');
|
|
154
153
|
|
|
155
154
|
expect(error).toHaveClass(classForType(Sentiment.NEGATIVE));
|
|
156
|
-
expect(screen.getByTestId('cross-
|
|
155
|
+
expect(screen.getByTestId('cross-icon')).toBeInTheDocument();
|
|
157
156
|
expect(mockedWarn).toHaveBeenCalledWith(
|
|
158
|
-
expect.stringContaining(
|
|
157
|
+
expect.stringContaining(
|
|
158
|
+
"Alert component has deprecated 'error' value for the 'type' prop. Please use 'negative' instead.",
|
|
159
|
+
),
|
|
159
160
|
);
|
|
160
161
|
});
|
|
161
162
|
|
|
@@ -167,7 +168,7 @@ describe('Alert', () => {
|
|
|
167
168
|
};
|
|
168
169
|
render(<Alert action={action} message={message} />);
|
|
169
170
|
|
|
170
|
-
const element = screen.getByText(action.text);
|
|
171
|
+
const element = screen.getByText(action.text?.toString() ?? '');
|
|
171
172
|
|
|
172
173
|
expect(element).toHaveAttribute('href', action.href);
|
|
173
174
|
expect(element).not.toHaveAttribute('aria-label');
|
|
@@ -183,7 +184,7 @@ describe('Alert', () => {
|
|
|
183
184
|
};
|
|
184
185
|
render(<Alert action={action} message={message} />);
|
|
185
186
|
|
|
186
|
-
const element = screen.getByText(action.text);
|
|
187
|
+
const element = screen.getByText(action.text?.toString() ?? '');
|
|
187
188
|
|
|
188
189
|
expect(element).toHaveAttribute('aria-label', action['aria-label']);
|
|
189
190
|
expect(element).toHaveAttribute('target', action.target);
|
|
@@ -245,7 +246,7 @@ describe('Alert', () => {
|
|
|
245
246
|
});
|
|
246
247
|
|
|
247
248
|
describe('types', () => {
|
|
248
|
-
const getComponentWithType = (type) => {
|
|
249
|
+
const getComponentWithType = (type: AlertType) => {
|
|
249
250
|
render(<Alert type={type} message={message} />);
|
|
250
251
|
return screen.getByTestId('alert');
|
|
251
252
|
};
|
|
@@ -254,28 +255,28 @@ describe('Alert', () => {
|
|
|
254
255
|
component = getComponentWithType(Sentiment.NEUTRAL);
|
|
255
256
|
|
|
256
257
|
expect(component).toHaveClass(classForType(Sentiment.NEUTRAL));
|
|
257
|
-
expect(screen.getByTestId('info-
|
|
258
|
+
expect(screen.getByTestId('info-icon')).toBeInTheDocument();
|
|
258
259
|
});
|
|
259
260
|
|
|
260
261
|
it('renders positive', () => {
|
|
261
262
|
component = getComponentWithType(Sentiment.POSITIVE);
|
|
262
263
|
|
|
263
264
|
expect(component).toHaveClass(classForType(Sentiment.POSITIVE));
|
|
264
|
-
expect(screen.getByTestId('check-
|
|
265
|
+
expect(screen.getByTestId('check-icon')).toBeInTheDocument();
|
|
265
266
|
});
|
|
266
267
|
|
|
267
268
|
it('renders negative', () => {
|
|
268
269
|
component = getComponentWithType(Sentiment.NEGATIVE);
|
|
269
270
|
|
|
270
271
|
expect(component).toHaveClass(classForType(Sentiment.NEGATIVE));
|
|
271
|
-
expect(screen.getByTestId('cross-
|
|
272
|
+
expect(screen.getByTestId('cross-icon')).toBeInTheDocument();
|
|
272
273
|
});
|
|
273
274
|
|
|
274
275
|
it('renders warning', () => {
|
|
275
276
|
component = getComponentWithType(Sentiment.WARNING);
|
|
276
277
|
|
|
277
278
|
expect(component).toHaveClass(classForType(Sentiment.WARNING));
|
|
278
|
-
expect(screen.getByTestId('
|
|
279
|
+
expect(screen.getByTestId('alert-icon')).toBeInTheDocument();
|
|
279
280
|
});
|
|
280
281
|
|
|
281
282
|
it('renders error alerts with aria-role alert', () => {
|
|
@@ -292,9 +293,11 @@ describe('Alert', () => {
|
|
|
292
293
|
const { location } = window;
|
|
293
294
|
|
|
294
295
|
beforeAll(() => {
|
|
295
|
-
delete window.location;
|
|
296
296
|
jest.spyOn(window, 'open').mockImplementation();
|
|
297
|
+
// @ts-expect-error value gets set right after its deletion
|
|
298
|
+
delete window.location;
|
|
297
299
|
window.location = {
|
|
300
|
+
...window.location,
|
|
298
301
|
assign: jest.fn(),
|
|
299
302
|
};
|
|
300
303
|
});
|
|
@@ -4,8 +4,7 @@ import { ClockBorderless } from '@transferwise/icons';
|
|
|
4
4
|
|
|
5
5
|
import { Sentiment } from '../common';
|
|
6
6
|
|
|
7
|
-
import Alert from './Alert';
|
|
8
|
-
import { AlertArrowPosition } from './withArrow';
|
|
7
|
+
import Alert, { AlertArrowPosition } from './Alert';
|
|
9
8
|
|
|
10
9
|
export default {
|
|
11
10
|
component: Alert,
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import { useState, useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
import Body from '../body/Body';
|
|
5
|
+
import { Sentiment, Size, Typography, Variant } from '../common';
|
|
6
|
+
import { CloseButton } from '../common/closeButton';
|
|
7
|
+
import Link from '../link';
|
|
8
|
+
import StatusIcon from '../statusIcon';
|
|
9
|
+
import Title from '../title/Title';
|
|
10
|
+
import { logActionRequired } from '../utilities';
|
|
11
|
+
|
|
12
|
+
import InlineMarkdown from './inlineMarkdown';
|
|
13
|
+
|
|
14
|
+
export type AlertAction = {
|
|
15
|
+
'aria-label'?: string;
|
|
16
|
+
href: string;
|
|
17
|
+
target?: string;
|
|
18
|
+
text: React.ReactNode;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** @deprecated Use `"top" | "bottom"` instead. */
|
|
22
|
+
type AlertTypeDeprecated = `${Sentiment.SUCCESS | Sentiment.INFO | Sentiment.ERROR}`;
|
|
23
|
+
type AlertTypeResolved = `${
|
|
24
|
+
| Sentiment.POSITIVE
|
|
25
|
+
| Sentiment.NEUTRAL
|
|
26
|
+
| Sentiment.WARNING
|
|
27
|
+
| Sentiment.NEGATIVE}`;
|
|
28
|
+
export type AlertType = AlertTypeResolved | AlertTypeDeprecated;
|
|
29
|
+
|
|
30
|
+
export enum AlertArrowPosition {
|
|
31
|
+
TOP_LEFT = 'up-left',
|
|
32
|
+
TOP = 'up-center',
|
|
33
|
+
TOP_RIGHT = 'up-right',
|
|
34
|
+
BOTTOM_LEFT = 'down-left',
|
|
35
|
+
BOTTOM = 'down-center',
|
|
36
|
+
BOTTOM_RIGHT = 'down-right',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AlertProps {
|
|
40
|
+
/** An optional call to action to sit under the main body of the alert. If your label is short, use aria-label to provide more context */
|
|
41
|
+
action?: AlertAction;
|
|
42
|
+
className?: string;
|
|
43
|
+
/** An optional icon. If not provided, we will default the icon to something appropriate for the type */
|
|
44
|
+
icon?: React.ReactElement;
|
|
45
|
+
/** Title for the alert component */
|
|
46
|
+
title?: string;
|
|
47
|
+
/** The main body of the alert. Accepts plain text and bold words specified with **double stars*/
|
|
48
|
+
message?: string;
|
|
49
|
+
/** The presence of the onDismiss handler will trigger the visibility of the close button */
|
|
50
|
+
onDismiss?: React.MouseEventHandler<HTMLButtonElement>;
|
|
51
|
+
/** The type dictates which icon and colour will be used */
|
|
52
|
+
type?: AlertType;
|
|
53
|
+
variant?: `${Variant}`;
|
|
54
|
+
/** @deprecated Use `InlineAlert` instead. */
|
|
55
|
+
arrow?: `${AlertArrowPosition}`;
|
|
56
|
+
/** @deprecated Use `message` instead. Be aware `message` only accepts plain text or text with **bold** markdown. */
|
|
57
|
+
children?: React.ReactNode;
|
|
58
|
+
/** @deprecated Use `onDismiss` instead. */
|
|
59
|
+
dismissible?: boolean;
|
|
60
|
+
/** @deprecated Alert component doesn't support `size` anymore, please remove this prop. */
|
|
61
|
+
size?: `${Size}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function resolveType(type: AlertType): AlertTypeResolved {
|
|
65
|
+
switch (type) {
|
|
66
|
+
case 'success':
|
|
67
|
+
return 'positive';
|
|
68
|
+
case 'info':
|
|
69
|
+
return 'neutral';
|
|
70
|
+
case 'error':
|
|
71
|
+
return 'negative';
|
|
72
|
+
}
|
|
73
|
+
return type;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default function Alert({
|
|
77
|
+
arrow,
|
|
78
|
+
action,
|
|
79
|
+
children,
|
|
80
|
+
className,
|
|
81
|
+
dismissible,
|
|
82
|
+
icon,
|
|
83
|
+
onDismiss,
|
|
84
|
+
message,
|
|
85
|
+
size,
|
|
86
|
+
title,
|
|
87
|
+
type = 'neutral',
|
|
88
|
+
variant = 'desktop',
|
|
89
|
+
}: AlertProps) {
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (arrow !== undefined) {
|
|
92
|
+
logActionRequired(
|
|
93
|
+
"Alert component doesn't support 'arrow' anymore, use 'InlineAlert' instead.",
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}, [arrow]);
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (children !== undefined) {
|
|
100
|
+
logActionRequired(
|
|
101
|
+
"Alert component doesn't support 'children' anymore, use 'message' instead.",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}, [children]);
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (dismissible !== undefined) {
|
|
108
|
+
logActionRequired(
|
|
109
|
+
"Alert component doesn't support 'dismissible' anymore, use 'onDismiss' instead.",
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}, [dismissible]);
|
|
113
|
+
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (size !== undefined) {
|
|
116
|
+
logActionRequired("Alert component doesn't support 'size' anymore, please remove that prop.");
|
|
117
|
+
}
|
|
118
|
+
}, [size]);
|
|
119
|
+
|
|
120
|
+
const resolvedType = resolveType(type);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (resolvedType !== type) {
|
|
123
|
+
logActionRequired(
|
|
124
|
+
`Alert component has deprecated '${type}' value for the 'type' prop. Please use '${resolvedType}' instead.`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}, [resolvedType, type]);
|
|
128
|
+
|
|
129
|
+
const [shouldFire, setShouldFire] = useState(false);
|
|
130
|
+
|
|
131
|
+
const closeButtonReference = useRef<HTMLButtonElement>(null);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div
|
|
135
|
+
className={classNames(
|
|
136
|
+
'alert d-flex',
|
|
137
|
+
`alert-${resolvedType}`,
|
|
138
|
+
arrow != null && alertArrowClassNames(arrow),
|
|
139
|
+
className,
|
|
140
|
+
)}
|
|
141
|
+
data-testid="alert"
|
|
142
|
+
onTouchStart={() => setShouldFire(true)}
|
|
143
|
+
onTouchEnd={(event) => {
|
|
144
|
+
if (
|
|
145
|
+
shouldFire &&
|
|
146
|
+
action &&
|
|
147
|
+
// Check if current event is triggered from closeButton
|
|
148
|
+
event.target instanceof Node &&
|
|
149
|
+
closeButtonReference.current &&
|
|
150
|
+
!closeButtonReference.current.contains(event.target)
|
|
151
|
+
) {
|
|
152
|
+
if (action.target === '_blank') {
|
|
153
|
+
window.top?.open(action.href);
|
|
154
|
+
} else {
|
|
155
|
+
window.top?.location.assign(action.href);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
setShouldFire(false);
|
|
159
|
+
}}
|
|
160
|
+
onTouchMove={() => setShouldFire(false)}
|
|
161
|
+
>
|
|
162
|
+
<div
|
|
163
|
+
className={classNames('alert__content', 'd-flex', 'flex-grow-1', variant)}
|
|
164
|
+
data-testid={variant}
|
|
165
|
+
>
|
|
166
|
+
{icon ? (
|
|
167
|
+
<div className="alert__icon">{icon}</div>
|
|
168
|
+
) : (
|
|
169
|
+
<StatusIcon size={Size.LARGE} sentiment={resolvedType} />
|
|
170
|
+
)}
|
|
171
|
+
<div className="alert__message">
|
|
172
|
+
<div role={Sentiment.NEGATIVE === resolvedType ? 'alert' : 'status'}>
|
|
173
|
+
{title && (
|
|
174
|
+
<Title className="m-b-1" type={Typography.TITLE_BODY}>
|
|
175
|
+
{title}
|
|
176
|
+
</Title>
|
|
177
|
+
)}
|
|
178
|
+
<Body as="span" className="d-block" type={Typography.BODY_LARGE}>
|
|
179
|
+
{children || <InlineMarkdown>{message}</InlineMarkdown>}
|
|
180
|
+
</Body>
|
|
181
|
+
</div>
|
|
182
|
+
{action && (
|
|
183
|
+
<Link
|
|
184
|
+
href={action.href}
|
|
185
|
+
className="m-t-1"
|
|
186
|
+
aria-label={action['aria-label']}
|
|
187
|
+
target={action.target}
|
|
188
|
+
type={Typography.LINK_LARGE}
|
|
189
|
+
>
|
|
190
|
+
{action.text}
|
|
191
|
+
</Link>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
{onDismiss && (
|
|
196
|
+
<CloseButton ref={closeButtonReference} className="m-l-2" onClick={onDismiss} />
|
|
197
|
+
)}
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function alertArrowClassNames(arrow: `${AlertArrowPosition}`) {
|
|
203
|
+
switch (arrow) {
|
|
204
|
+
case 'down-center':
|
|
205
|
+
return 'arrow arrow-bottom arrow-center';
|
|
206
|
+
case 'down-left':
|
|
207
|
+
return 'arrow arrow-bottom arrow-left';
|
|
208
|
+
case 'down-right':
|
|
209
|
+
return 'arrow arrow-bottom arrow-right';
|
|
210
|
+
case 'up-center':
|
|
211
|
+
return 'arrow arrow-center';
|
|
212
|
+
case 'up-right':
|
|
213
|
+
return 'arrow arrow-right';
|
|
214
|
+
case 'up-left':
|
|
215
|
+
default:
|
|
216
|
+
return 'arrow';
|
|
217
|
+
}
|
|
218
|
+
}
|
package/src/button/Button.tsx
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
SizeSmall,
|
|
17
17
|
SizeMedium,
|
|
18
18
|
SizeLarge,
|
|
19
|
-
LinkProps,
|
|
20
19
|
} from '../common';
|
|
21
20
|
import ProcessIndicator from '../processIndicator';
|
|
22
21
|
|
|
@@ -30,8 +29,7 @@ type DeprecatedTypes = 'primary' | 'pay' | 'secondary' | 'danger' | 'link';
|
|
|
30
29
|
/** @deprecated */
|
|
31
30
|
type DeprecatedSizes = SizeExtraSmall;
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
as?: ElementType;
|
|
32
|
+
type CommonProps = {
|
|
35
33
|
block?: boolean;
|
|
36
34
|
disabled?: boolean;
|
|
37
35
|
loading?: boolean;
|
|
@@ -40,22 +38,20 @@ export type CommonProps = {
|
|
|
40
38
|
size?: SizeSmall | SizeMedium | SizeLarge | DeprecatedSizes;
|
|
41
39
|
};
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
Omit<
|
|
41
|
+
type ButtonProps = CommonProps &
|
|
42
|
+
Omit<React.ComponentPropsWithRef<'button'>, 'type'> & {
|
|
45
43
|
as?: 'button';
|
|
46
44
|
htmlType?: 'submit' | 'reset' | 'button';
|
|
47
45
|
};
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Omit<LinkProps, 'href'> & {
|
|
47
|
+
type AnchorProps = CommonProps &
|
|
48
|
+
React.ComponentPropsWithRef<'a'> & {
|
|
52
49
|
as?: 'a';
|
|
53
|
-
href?: string; // Optional due to usage of component with next/link's passHref behavior
|
|
54
50
|
};
|
|
55
51
|
|
|
56
52
|
export type Props = ButtonProps | AnchorProps;
|
|
57
53
|
|
|
58
|
-
|
|
54
|
+
type ButtonReferenceType = HTMLButtonElement | HTMLAnchorElement;
|
|
59
55
|
|
|
60
56
|
const Button = forwardRef<ButtonReferenceType, Props>(
|
|
61
57
|
(
|
|
@@ -22,10 +22,31 @@ describe('isWithinRange', () => {
|
|
|
22
22
|
expect(isWithinRange(date, min, max)).toBe(false);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
it('returns false when min > date and max is undefined', () => {
|
|
26
|
+
const date = new Date('1995-12-20');
|
|
27
|
+
const min = new Date('1995-12-21');
|
|
28
|
+
const max = null;
|
|
29
|
+
expect(isWithinRange(date, min, max)).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
|
|
25
32
|
it('returns false when date > max', () => {
|
|
26
33
|
const date = new Date('1995-12-23');
|
|
27
34
|
const min = new Date('1995-12-20');
|
|
28
35
|
const max = new Date('1995-12-22');
|
|
29
36
|
expect(isWithinRange(date, min, max)).toBe(false);
|
|
30
37
|
});
|
|
38
|
+
|
|
39
|
+
it('returns false when date > max and min is undefined', () => {
|
|
40
|
+
const date = new Date('1995-12-23');
|
|
41
|
+
const min = null;
|
|
42
|
+
const max = new Date('1995-12-22');
|
|
43
|
+
expect(isWithinRange(date, min, max)).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns true when min and max are undefined', () => {
|
|
47
|
+
const date = new Date('1995-12-23');
|
|
48
|
+
const min = null;
|
|
49
|
+
const max = null;
|
|
50
|
+
expect(isWithinRange(date, min, max)).toBe(true);
|
|
51
|
+
});
|
|
31
52
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export function isWithinRange(date: Date, min: Date, max: Date) {
|
|
2
|
-
return
|
|
1
|
+
export function isWithinRange(date: Date, min: Date | null, max: Date | null) {
|
|
2
|
+
return (!min || date >= min) && (!max || date <= max);
|
|
3
3
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { isWithinRange } from '..';
|
|
2
|
-
|
|
3
1
|
// Makes sure that date is between min and max dates, returns a cloned min or max
|
|
4
|
-
export function moveToWithinRange(date: Date, min: Date, max: Date) {
|
|
5
|
-
|
|
2
|
+
export function moveToWithinRange(date: Date, min: Date | null, max: Date | null) {
|
|
3
|
+
if (min && date < min) {
|
|
4
|
+
return new Date(min);
|
|
5
|
+
}
|
|
6
|
+
if (max && date > max) {
|
|
7
|
+
return new Date(max);
|
|
8
|
+
}
|
|
9
|
+
return date;
|
|
6
10
|
}
|
|
@@ -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);
|