@transferwise/components 45.15.0 → 45.16.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/en.json +8 -0
- package/build/index.esm.js +550 -488
- package/build/index.esm.js.map +1 -1
- package/build/index.js +549 -487
- package/build/index.js.map +1 -1
- package/build/main.css +1 -1
- package/build/styles/dateLookup/DateLookup.css +1 -1
- package/build/styles/main.css +1 -1
- package/build/styles/popover/Popover.css +1 -1
- package/build/styles/promoCard/PromoCard.css +1 -1
- package/build/types/alert/Alert.d.ts.map +1 -1
- package/build/types/avatarWrapper/AvatarWrapper.d.ts +14 -5
- package/build/types/avatarWrapper/AvatarWrapper.d.ts.map +1 -1
- package/build/types/common/Option/Option.d.ts.map +1 -1
- package/build/types/common/card/Card.d.ts.map +1 -1
- package/build/types/common/card/index.d.ts +1 -0
- package/build/types/common/card/index.d.ts.map +1 -1
- package/build/types/common/focusBoundary/FocusBoundary.d.ts +2 -2
- package/build/types/common/focusBoundary/FocusBoundary.d.ts.map +1 -1
- package/build/types/dateInput/DateInput.d.ts +2 -0
- package/build/types/dateInput/DateInput.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.messages.d.ts +65 -0
- package/build/types/dateLookup/DateLookup.messages.d.ts.map +1 -0
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts +3 -1
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts.map +1 -1
- package/build/types/dateLookup/tableLink/TableLink.d.ts +4 -26
- package/build/types/dateLookup/tableLink/TableLink.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts +4 -29
- package/build/types/dateLookup/yearCalendar/YearCalendar.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/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
- package/build/types/promoCard/PromoCard.d.ts +9 -3
- package/build/types/promoCard/PromoCard.d.ts.map +1 -1
- package/build/types/promoCard/PromoCardIndicator.d.ts +5 -3
- package/build/types/promoCard/PromoCardIndicator.d.ts.map +1 -1
- package/build/types/snackbar/Snackbar.d.ts.map +1 -1
- package/build/types/tabs/Tabs.d.ts.map +1 -1
- package/build/types/upload/steps/completeStep/completeStep.d.ts.map +1 -1
- package/build/types/upload/steps/processingStep/processingStep.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/accordion/AccordionItem/__snapshots__/AccordionItem.spec.js.snap +6 -6
- package/src/alert/Alert.js +11 -9
- package/src/alert/Alert.spec.js +22 -13
- package/src/alert/withArrow/withArrow.spec.js +4 -4
- package/src/avatarWrapper/AvatarWrapper.tsx +20 -8
- package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +1 -1
- package/src/card/Card.spec.js +2 -2
- package/src/common/Option/Option.tsx +1 -7
- package/src/common/bottomSheet/__snapshots__/BottomSheet.spec.tsx.snap +8 -1
- package/src/common/card/Card.tsx +6 -2
- package/src/common/card/index.ts +1 -0
- package/src/common/focusBoundary/FocusBoundary.tsx +9 -32
- package/src/dateInput/DateInput.js +6 -0
- package/src/dateInput/DateInput.story.tsx +2 -0
- package/src/dateLookup/DateLookup.css +1 -1
- package/src/dateLookup/DateLookup.keyboardEvents.spec.js +3 -3
- package/src/dateLookup/DateLookup.less +4 -0
- package/src/dateLookup/DateLookup.messages.js +44 -0
- package/src/dateLookup/DateLookup.testingLibrary.spec.js +39 -0
- package/src/dateLookup/dateHeader/DateHeader.js +48 -26
- package/src/dateLookup/dateHeader/DateHeader.spec.js +37 -0
- package/src/dateLookup/dayCalendar/DayCalendar.js +3 -1
- package/src/dateLookup/dayCalendar/DayCalendar.spec.js +7 -1
- package/src/dateLookup/dayCalendar/table/DayCalendarTable.js +7 -3
- package/src/dateLookup/dayCalendar/table/DayCalendarTable.spec.js +1 -0
- package/src/dateLookup/monthCalendar/MonthCalendar.js +3 -1
- package/src/dateLookup/monthCalendar/MonthCalendar.spec.js +7 -1
- package/src/dateLookup/monthCalendar/table/MonthCalendarTable.spec.js +4 -5
- package/src/dateLookup/tableLink/TableLink.js +25 -3
- package/src/dateLookup/tableLink/TableLink.spec.js +66 -4
- package/src/dateLookup/yearCalendar/YearCalendar.js +16 -3
- package/src/dateLookup/yearCalendar/YearCalendar.spec.js +14 -1
- package/src/dateLookup/yearCalendar/table/YearCalendarTable.spec.js +4 -5
- package/src/i18n/en.json +8 -0
- package/src/inputs/SelectInput.story.tsx +36 -9
- package/src/inputs/_BottomSheet.less +1 -1
- package/src/inputs/_BottomSheet.tsx +57 -52
- package/src/inputs/_Popover.less +1 -1
- package/src/inputs/_Popover.tsx +31 -24
- package/src/listItem/ListItem.story.tsx +1 -1
- package/src/main.css +1 -1
- package/src/phoneNumberInput/PhoneNumberInput.js +1 -0
- package/src/popover/Popover.css +1 -1
- package/src/promoCard/PromoCard.css +1 -1
- package/src/promoCard/PromoCard.less +9 -9
- package/src/promoCard/PromoCard.spec.tsx +1 -0
- package/src/promoCard/PromoCard.story.tsx +90 -30
- package/src/promoCard/PromoCard.tsx +69 -22
- package/src/promoCard/PromoCardIndicator.tsx +20 -8
- package/src/snackbar/Snackbar.js +6 -1
- package/src/snackbar/Snackbar.spec.js +1 -3
- package/src/tabs/Tabs.js +2 -1
- package/src/upload/Upload.js +1 -1
- package/src/upload/steps/completeStep/completeStep.js +4 -1
- package/src/upload/steps/processingStep/processingStep.js +1 -0
- package/src/uploadInput/uploadItem/UploadItem.tsx +1 -1
- package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts +0 -2
- package/build/types/common/focusBoundary/utils/getFocusableElements.d.ts.map +0 -1
- package/build/types/common/focusBoundary/utils/index.d.ts +0 -3
- package/build/types/common/focusBoundary/utils/index.d.ts.map +0 -1
- package/build/types/common/focusBoundary/utils/resetFocus.d.ts +0 -2
- package/build/types/common/focusBoundary/utils/resetFocus.d.ts.map +0 -1
- package/src/common/focusBoundary/FocusBoundary.spec.tsx +0 -66
- package/src/common/focusBoundary/__snapshots__/FocusBoundary.spec.tsx.snap +0 -16
- package/src/common/focusBoundary/utils/getFocusableElements.js +0 -25
- package/src/common/focusBoundary/utils/getFocusableElements.spec.js +0 -51
- package/src/common/focusBoundary/utils/index.js +0 -2
- package/src/common/focusBoundary/utils/resetFocus.js +0 -23
- package/src/common/focusBoundary/utils/resetFocus.spec.js +0 -103
- package/src/snackbar/__snapshots__/Snackbar.spec.js.snap +0 -5
package/src/alert/Alert.spec.js
CHANGED
|
@@ -61,7 +61,7 @@ describe('Alert', () => {
|
|
|
61
61
|
<Alert message={message} />
|
|
62
62
|
</ThemeProvider>,
|
|
63
63
|
));
|
|
64
|
-
component = screen.
|
|
64
|
+
component = screen.getByTestId('alert');
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it('the message is rendered', () => {
|
|
@@ -85,7 +85,7 @@ describe('Alert', () => {
|
|
|
85
85
|
describe('deprecated props', () => {
|
|
86
86
|
it('renders arrows but logs a warning', () => {
|
|
87
87
|
render(<Alert arrow={AlertArrowPosition.BOTTOM} message={message} />);
|
|
88
|
-
component = screen.
|
|
88
|
+
component = screen.getByTestId('alert');
|
|
89
89
|
|
|
90
90
|
expect(component).toHaveClass('arrow');
|
|
91
91
|
expect(component).toHaveClass('arrow-bottom');
|
|
@@ -125,7 +125,7 @@ describe('Alert', () => {
|
|
|
125
125
|
it('maps type SUCCESS to type POSITIVE and logs a warning', () => {
|
|
126
126
|
render(<Alert type={Sentiment.SUCCESS} message={message} />);
|
|
127
127
|
|
|
128
|
-
const success = screen.
|
|
128
|
+
const success = screen.getByTestId('alert');
|
|
129
129
|
|
|
130
130
|
expect(success).toHaveClass(classForType(Sentiment.POSITIVE));
|
|
131
131
|
expect(screen.getByTestId('check-circle-icon')).toBeInTheDocument();
|
|
@@ -137,7 +137,7 @@ describe('Alert', () => {
|
|
|
137
137
|
it('maps type INFO to type NEUTRAL and logs a warning', () => {
|
|
138
138
|
render(<Alert type={Sentiment.INFO} message={message} />);
|
|
139
139
|
|
|
140
|
-
const info = screen.
|
|
140
|
+
const info = screen.getByTestId('alert');
|
|
141
141
|
|
|
142
142
|
expect(info).toHaveClass(classForType(Sentiment.NEUTRAL));
|
|
143
143
|
expect(screen.getByTestId('info-circle-icon')).toBeInTheDocument();
|
|
@@ -150,7 +150,7 @@ describe('Alert', () => {
|
|
|
150
150
|
it('maps type ERROR to type NEGATIVE and logs a warning', () => {
|
|
151
151
|
render(<Alert type={Sentiment.ERROR} message={message} />);
|
|
152
152
|
|
|
153
|
-
const error = screen.
|
|
153
|
+
const error = screen.getByTestId('alert');
|
|
154
154
|
|
|
155
155
|
expect(error).toHaveClass(classForType(Sentiment.NEGATIVE));
|
|
156
156
|
expect(screen.getByTestId('cross-circle-icon')).toBeInTheDocument();
|
|
@@ -197,14 +197,14 @@ describe('Alert', () => {
|
|
|
197
197
|
it('converts message to markdown', () => {
|
|
198
198
|
render(<Alert message={input} />);
|
|
199
199
|
|
|
200
|
-
expect(screen.
|
|
200
|
+
expect(screen.getByTestId('alert')).toContainHTML(output);
|
|
201
201
|
});
|
|
202
202
|
|
|
203
203
|
it('does not convert children to markdown', () => {
|
|
204
204
|
render(<Alert>{input}</Alert>);
|
|
205
205
|
|
|
206
206
|
expect(screen.getByText(input)).toBeInTheDocument();
|
|
207
|
-
expect(screen.
|
|
207
|
+
expect(screen.getByTestId('alert')).not.toContainHTML(output);
|
|
208
208
|
});
|
|
209
209
|
});
|
|
210
210
|
|
|
@@ -212,7 +212,7 @@ describe('Alert', () => {
|
|
|
212
212
|
it('applies provided classes', () => {
|
|
213
213
|
render(<Alert className="cats" message={message} />);
|
|
214
214
|
|
|
215
|
-
expect(screen.
|
|
215
|
+
expect(screen.getByTestId('alert')).toHaveClass('cats');
|
|
216
216
|
});
|
|
217
217
|
});
|
|
218
218
|
|
|
@@ -221,7 +221,7 @@ describe('Alert', () => {
|
|
|
221
221
|
const icon = <HappyEmoji />;
|
|
222
222
|
|
|
223
223
|
render(<Alert icon={icon} message={message} />);
|
|
224
|
-
component = screen.
|
|
224
|
+
component = screen.getByTestId('alert');
|
|
225
225
|
expect(screen.getByTestId('happy-emoji-icon')).toBeInTheDocument();
|
|
226
226
|
});
|
|
227
227
|
});
|
|
@@ -247,7 +247,7 @@ describe('Alert', () => {
|
|
|
247
247
|
describe('types', () => {
|
|
248
248
|
const getComponentWithType = (type) => {
|
|
249
249
|
render(<Alert type={type} message={message} />);
|
|
250
|
-
return screen.
|
|
250
|
+
return screen.getByTestId('alert');
|
|
251
251
|
};
|
|
252
252
|
|
|
253
253
|
it('renders neutral', () => {
|
|
@@ -277,6 +277,15 @@ describe('Alert', () => {
|
|
|
277
277
|
expect(component).toHaveClass(classForType(Sentiment.WARNING));
|
|
278
278
|
expect(screen.getByTestId('warning-icon')).toBeInTheDocument();
|
|
279
279
|
});
|
|
280
|
+
|
|
281
|
+
it('renders error alerts with aria-role alert', () => {
|
|
282
|
+
component = getComponentWithType(Sentiment.NEGATIVE);
|
|
283
|
+
expect(screen.getByRole('alert')).toBeInTheDocument();
|
|
284
|
+
});
|
|
285
|
+
it('renders neutral alerts with aria-role status', () => {
|
|
286
|
+
component = getComponentWithType(Sentiment.NEUTRAL);
|
|
287
|
+
expect(screen.getByRole('status')).toBeInTheDocument();
|
|
288
|
+
});
|
|
280
289
|
});
|
|
281
290
|
|
|
282
291
|
describe('on touch devices', () => {
|
|
@@ -304,7 +313,7 @@ describe('Alert', () => {
|
|
|
304
313
|
|
|
305
314
|
render(<Alert action={action} message={message} onDismiss={jest.fn()} />);
|
|
306
315
|
|
|
307
|
-
alert = screen.
|
|
316
|
+
alert = screen.getByTestId('alert');
|
|
308
317
|
closeButton = screen.getByLabelText('Close');
|
|
309
318
|
|
|
310
319
|
jest.spyOn(React, 'useRef').mockReturnValue({
|
|
@@ -344,7 +353,7 @@ describe('Alert', () => {
|
|
|
344
353
|
|
|
345
354
|
render(<Alert action={action} message={message} onDismiss={jest.fn()} />);
|
|
346
355
|
|
|
347
|
-
alert = screen.
|
|
356
|
+
alert = screen.getByTestId('alert');
|
|
348
357
|
closeButton = screen.getByLabelText('Close');
|
|
349
358
|
|
|
350
359
|
jest.spyOn(React, 'useRef').mockReturnValue({
|
|
@@ -368,7 +377,7 @@ describe('Alert', () => {
|
|
|
368
377
|
beforeEach(() => {
|
|
369
378
|
render(<Alert message={message} onDismiss={jest.fn()} />);
|
|
370
379
|
|
|
371
|
-
alert = screen.
|
|
380
|
+
alert = screen.getByTestId('alert');
|
|
372
381
|
closeButton = screen.getByLabelText('Close');
|
|
373
382
|
|
|
374
383
|
jest.spyOn(React, 'useRef').mockReturnValue({
|
|
@@ -12,7 +12,7 @@ describe('withArrow', () => {
|
|
|
12
12
|
const ArrowLessAlert = withArrow(Alert);
|
|
13
13
|
|
|
14
14
|
render(<ArrowLessAlert message={message} />);
|
|
15
|
-
const component = screen.
|
|
15
|
+
const component = screen.getByTestId('alert');
|
|
16
16
|
|
|
17
17
|
expect(component).not.toHaveClass('arrow');
|
|
18
18
|
});
|
|
@@ -21,7 +21,7 @@ describe('withArrow', () => {
|
|
|
21
21
|
const AlertTopArrow = withArrow(Alert, ArrowPosition.TOP_LEFT);
|
|
22
22
|
|
|
23
23
|
render(<AlertTopArrow message={message} arrow={ArrowPosition.BOTTOM_LEFT} />);
|
|
24
|
-
const component = screen.
|
|
24
|
+
const component = screen.getByTestId('alert');
|
|
25
25
|
expect(component).toHaveClass('arrow');
|
|
26
26
|
expect(component).not.toHaveClass('arrow-bottom');
|
|
27
27
|
});
|
|
@@ -33,7 +33,7 @@ describe('withArrow', () => {
|
|
|
33
33
|
it(`returns an bottom arrowed alert if you pass a bottom arrow`, () => {
|
|
34
34
|
const BottomArrowAlert = getPointyAlert(ArrowPosition.BOTTOM);
|
|
35
35
|
render(<BottomArrowAlert message={message} />);
|
|
36
|
-
const component = screen.
|
|
36
|
+
const component = screen.getByTestId('alert');
|
|
37
37
|
|
|
38
38
|
expect(component).toHaveClass('arrow');
|
|
39
39
|
expect(component).toHaveClass('arrow-bottom');
|
|
@@ -42,7 +42,7 @@ describe('withArrow', () => {
|
|
|
42
42
|
it(`returns an top-right arrowed alert if you pass a top right arrow`, () => {
|
|
43
43
|
const BottomArrowAlert = getPointyAlert(ArrowPosition.TOP_RIGHT);
|
|
44
44
|
render(<BottomArrowAlert message={message} />);
|
|
45
|
-
const component = screen.
|
|
45
|
+
const component = screen.getByTestId('alert');
|
|
46
46
|
|
|
47
47
|
expect(component).toHaveClass('arrow');
|
|
48
48
|
expect(component).toHaveClass('arrow-right');
|
|
@@ -6,11 +6,10 @@ import Badge, { BadgeProps } from '../badge';
|
|
|
6
6
|
import { ProfileType, ProfileTypePersonal, ProfileTypeBusiness, Size, Sentiment } from '../common';
|
|
7
7
|
import StatusIcon from '../statusIcon/StatusIcon';
|
|
8
8
|
|
|
9
|
-
interface OptionalBadgeProps {
|
|
9
|
+
interface OptionalBadgeProps extends Omit<BadgeProps, 'badge'> {
|
|
10
10
|
url?: string;
|
|
11
11
|
altText?: string;
|
|
12
12
|
statusIcon?: Sentiment;
|
|
13
|
-
children: React.ReactNode;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
const OptionalBadge = ({ url, altText, statusIcon, children, ...rest }: OptionalBadgeProps) => {
|
|
@@ -31,17 +30,30 @@ const OptionalBadge = ({ url, altText, statusIcon, children, ...rest }: Optional
|
|
|
31
30
|
return <>{children}</>;
|
|
32
31
|
};
|
|
33
32
|
|
|
34
|
-
export
|
|
33
|
+
export type AvatarWrapperProps = {
|
|
35
34
|
url?: string;
|
|
36
35
|
profileType?: ProfileTypeBusiness | ProfileTypePersonal;
|
|
37
36
|
profileId?: string;
|
|
38
|
-
badgeUrl?: string;
|
|
39
|
-
badgeAltText?: string;
|
|
40
|
-
badgeStatusIcon?: Sentiment;
|
|
41
37
|
name?: string;
|
|
42
38
|
avatarProps?: AvatarProps;
|
|
43
39
|
badgeProps?: BadgeProps;
|
|
44
|
-
}
|
|
40
|
+
} & (
|
|
41
|
+
| {
|
|
42
|
+
badgeUrl: string;
|
|
43
|
+
badgeAltText: string;
|
|
44
|
+
badgeStatusIcon?: never;
|
|
45
|
+
}
|
|
46
|
+
| {
|
|
47
|
+
badgeUrl?: never;
|
|
48
|
+
badgeAltText?: never;
|
|
49
|
+
badgeStatusIcon: Sentiment;
|
|
50
|
+
}
|
|
51
|
+
| {
|
|
52
|
+
badgeUrl?: never;
|
|
53
|
+
badgeAltText?: never;
|
|
54
|
+
badgeStatusIcon?: never;
|
|
55
|
+
}
|
|
56
|
+
);
|
|
45
57
|
|
|
46
58
|
const AvatarWrapper = ({
|
|
47
59
|
url,
|
|
@@ -64,7 +76,7 @@ const AvatarWrapper = ({
|
|
|
64
76
|
if (url && !hasImageLoadError) {
|
|
65
77
|
return {
|
|
66
78
|
type: AvatarType.THUMBNAIL,
|
|
67
|
-
children: <img src={url} alt="
|
|
79
|
+
children: <img src={url} alt="" onError={() => setImageLoadError(true)} />,
|
|
68
80
|
...avatarProps,
|
|
69
81
|
};
|
|
70
82
|
}
|
package/src/card/Card.spec.js
CHANGED
|
@@ -56,12 +56,12 @@ describe('Card', () => {
|
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
describe('when there is no children prop', () => {
|
|
59
|
-
it('
|
|
59
|
+
it('renders Option title as a heading 4', () => {
|
|
60
60
|
const onClick = jest.fn();
|
|
61
61
|
renderCard(onClick);
|
|
62
62
|
|
|
63
63
|
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
64
|
-
expect(screen.getByText(defaultProps.title).tagName).toBe('
|
|
64
|
+
expect(screen.getByText(defaultProps.title).tagName).toBe('H4');
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it('has an inactive class', () => {
|
|
@@ -85,13 +85,7 @@ const Option = forwardRef<ReferenceType, OptionProps>(
|
|
|
85
85
|
</div>
|
|
86
86
|
)}
|
|
87
87
|
<div className="media-body">
|
|
88
|
-
<
|
|
89
|
-
as="span"
|
|
90
|
-
type={Typography.BODY_LARGE_BOLD}
|
|
91
|
-
className="text-primary np-option__title d-block"
|
|
92
|
-
>
|
|
93
|
-
{title}
|
|
94
|
-
</Body>
|
|
88
|
+
<h4 className="np-text-body-large-bold text-primary np-option__title">{title}</h4>
|
|
95
89
|
{content && <Body className="d-block np-option__body">{content}</Body>}
|
|
96
90
|
</div>
|
|
97
91
|
<div className="media-right">{button}</div>
|
|
@@ -7,9 +7,12 @@ exports[`BottomSheet renders content when open 1`] = `
|
|
|
7
7
|
class="np-theme-light"
|
|
8
8
|
>
|
|
9
9
|
<div
|
|
10
|
-
class="np-focus-boundary outline-none"
|
|
11
10
|
tabindex="-1"
|
|
12
11
|
>
|
|
12
|
+
<span
|
|
13
|
+
data-focus-scope-start="true"
|
|
14
|
+
hidden=""
|
|
15
|
+
/>
|
|
13
16
|
<div
|
|
14
17
|
class="dimmer"
|
|
15
18
|
role="presentation"
|
|
@@ -63,6 +66,10 @@ exports[`BottomSheet renders content when open 1`] = `
|
|
|
63
66
|
</div>
|
|
64
67
|
</div>
|
|
65
68
|
</div>
|
|
69
|
+
<span
|
|
70
|
+
data-focus-scope-end="true"
|
|
71
|
+
hidden=""
|
|
72
|
+
/>
|
|
66
73
|
</div>
|
|
67
74
|
</div>
|
|
68
75
|
</body>
|
package/src/common/card/Card.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import classNames from 'classnames';
|
|
|
2
2
|
import { MouseEvent, ReactNode, useRef } from 'react';
|
|
3
3
|
|
|
4
4
|
import { CloseButton } from '../closeButton';
|
|
5
|
+
import { stopPropagation } from '../domHelpers';
|
|
5
6
|
|
|
6
7
|
export interface CardProps {
|
|
7
8
|
/** Content to display inside Card. */
|
|
@@ -49,7 +50,7 @@ export interface CardProps {
|
|
|
49
50
|
*/
|
|
50
51
|
const Card: React.FC<CardProps> = ({
|
|
51
52
|
className,
|
|
52
|
-
children,
|
|
53
|
+
children = null,
|
|
53
54
|
id,
|
|
54
55
|
isDisabled = false,
|
|
55
56
|
isSmall = false,
|
|
@@ -80,7 +81,10 @@ const Card: React.FC<CardProps> = ({
|
|
|
80
81
|
size={isSmall ? 'sm' : 'md'}
|
|
81
82
|
isDisabled={isDisabled}
|
|
82
83
|
testId="close-button"
|
|
83
|
-
onClick={
|
|
84
|
+
onClick={(e) => {
|
|
85
|
+
stopPropagation(e);
|
|
86
|
+
onDismiss();
|
|
87
|
+
}}
|
|
84
88
|
/>
|
|
85
89
|
)}
|
|
86
90
|
{children}
|
package/src/common/card/index.ts
CHANGED
|
@@ -1,44 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { useConditionalListener } from '../hooks';
|
|
5
|
-
import { Key } from '../key';
|
|
6
|
-
|
|
7
|
-
import { getFocusableElements, resetFocus } from './utils';
|
|
8
|
-
|
|
9
|
-
const { TAB } = Key;
|
|
1
|
+
import { FocusScope } from '@react-aria/focus';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
10
3
|
|
|
11
4
|
type FocusBoundaryProps = {
|
|
12
|
-
children: ReactNode;
|
|
5
|
+
children: React.ReactNode;
|
|
13
6
|
};
|
|
14
7
|
|
|
15
8
|
const FocusBoundary = ({ children }: FocusBoundaryProps) => {
|
|
16
|
-
const
|
|
17
|
-
const parent = isUndefined(document) ? undefined : document;
|
|
18
|
-
const [focusableEls, setFocusableEls] = useState({});
|
|
19
|
-
|
|
9
|
+
const wrapperReference = useRef<HTMLDivElement>(null);
|
|
20
10
|
useEffect(() => {
|
|
21
|
-
|
|
22
|
-
boundaryReference.current.focus({ preventScroll: true });
|
|
23
|
-
setFocusableEls(getFocusableElements(boundaryReference.current));
|
|
24
|
-
}
|
|
11
|
+
wrapperReference.current?.focus({ preventScroll: true });
|
|
25
12
|
}, []);
|
|
26
13
|
|
|
27
|
-
// If event type is Tab the resetFocus will force the focus to either the first focusable or last in boundaryRef .
|
|
28
|
-
useConditionalListener({
|
|
29
|
-
eventType: 'keydown',
|
|
30
|
-
callback: (event) => {
|
|
31
|
-
if (isKey({ keyType: TAB, event })) {
|
|
32
|
-
resetFocus({ event, focusableEls });
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
attachListener: true,
|
|
36
|
-
parent,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
14
|
return (
|
|
40
|
-
<div ref={
|
|
41
|
-
|
|
15
|
+
<div ref={wrapperReference} tabIndex={-1}>
|
|
16
|
+
<FocusScope contain restoreFocus>
|
|
17
|
+
{children}
|
|
18
|
+
</FocusScope>
|
|
42
19
|
</div>
|
|
43
20
|
);
|
|
44
21
|
};
|
|
@@ -18,8 +18,10 @@ const DateInput = ({
|
|
|
18
18
|
size,
|
|
19
19
|
value,
|
|
20
20
|
dayLabel,
|
|
21
|
+
dayAutoComplete,
|
|
21
22
|
monthLabel,
|
|
22
23
|
yearLabel,
|
|
24
|
+
yearAutoComplete,
|
|
23
25
|
monthFormat,
|
|
24
26
|
mode,
|
|
25
27
|
onChange,
|
|
@@ -239,6 +241,7 @@ const DateInput = ({
|
|
|
239
241
|
<Input
|
|
240
242
|
type="number"
|
|
241
243
|
name="day"
|
|
244
|
+
autoComplete={dayAutoComplete}
|
|
242
245
|
value={day || ''}
|
|
243
246
|
placeholder={placeholders.day}
|
|
244
247
|
disabled={disabled}
|
|
@@ -259,6 +262,7 @@ const DateInput = ({
|
|
|
259
262
|
<Input
|
|
260
263
|
type="number"
|
|
261
264
|
name="year"
|
|
265
|
+
autoComplete={yearAutoComplete}
|
|
262
266
|
placeholder={placeholders.year}
|
|
263
267
|
value={year || ''}
|
|
264
268
|
disabled={disabled}
|
|
@@ -303,8 +307,10 @@ DateInput.propTypes = {
|
|
|
303
307
|
onFocus: PropTypes.func,
|
|
304
308
|
onBlur: PropTypes.func,
|
|
305
309
|
dayLabel: PropTypes.string,
|
|
310
|
+
dayAutoComplete: PropTypes.string,
|
|
306
311
|
monthLabel: PropTypes.string,
|
|
307
312
|
yearLabel: PropTypes.string,
|
|
313
|
+
yearAutoComplete: PropTypes.string,
|
|
308
314
|
monthFormat: PropTypes.oneOf(['long', 'short']),
|
|
309
315
|
mode: PropTypes.oneOf(['day-month-year', 'month-year']),
|
|
310
316
|
placeholders: PropTypes.shape({
|
|
@@ -8,8 +8,10 @@ export default {
|
|
|
8
8
|
title: 'Forms/DateInput',
|
|
9
9
|
args: {
|
|
10
10
|
dayLabel: 'Day input',
|
|
11
|
+
dayAutoComplete: 'bday-day',
|
|
11
12
|
monthLabel: 'Month select',
|
|
12
13
|
yearLabel: 'Year input',
|
|
14
|
+
yearAutoComplete: 'bday-year',
|
|
13
15
|
selectProps: {
|
|
14
16
|
buttonProps: {
|
|
15
17
|
'aria-label': 'Select month',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.tw-date-lookup-menu{width:400px}.tw-date-lookup-calendar{min-width:300px;table-layout:fixed;text-align:center}.tw-date-lookup-calendar>tbody>tr>td{padding:4px;padding:var(--size-4)}.tw-date-lookup-calendar>tbody>tr>td button{background-color:transparent;border:transparent;border-radius:10px;border-radius:var(--radius-small);color:#0097c7;color:var(--color-content-accent);font-weight:600;font-weight:var(--font-weight-semi-bold);padding:4px 0;padding:var(--size-4) 0;width:100%}.tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled).active{background-color:#0081ba;background-color:var(--color-interactive-accent-active);color:#fff}.tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled):hover{background-color:#008fc9;background-color:var(--color-interactive-accent-hover);color:#fff}.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td button{color:#37517e;color:var(--color-content-primary)}.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled).active,.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled):hover{color:var(--color-interactive-control)}.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td:nth-child(7n+6) button,.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td:nth-child(7n+7) button,.np-theme-personal .tw-date-lookup-calendar>thead>tr>th:nth-child(7n+6),.np-theme-personal .tw-date-lookup-calendar>thead>tr>th:nth-child(7n+7){color:#5d7079;color:var(--color-content-secondary);font-weight:400;font-weight:var(--font-weight-regular)}.np-theme-personal .tw-date-lookup-calendar{background-color:inherit}.tw-date-lookup-header-current{font-weight:800;font-weight:var(--font-weight-bold)}.np-theme-personal .tw-date-lookup-menu .table-bordered,.np-theme-personal.tw-date-lookup-menu .table-bordered{border:none}.np-theme-personal .tw-date-lookup-menu thead,.np-theme-personal.tw-date-lookup-menu thead{background-color:unset}.np-theme-personal .tw-date-lookup-menu td,.np-theme-personal.tw-date-lookup-menu td{border:none}.np-theme-personal .tw-date-lookup-menu .tw-date-lookup-header-current,.np-theme-personal.tw-date-lookup-menu .tw-date-lookup-header-current{color:#37517e;color:var(--color-content-primary)}.np-theme-personal .tw-date-lookup-menu .tw-date-lookup-day-option,.np-theme-personal.tw-date-lookup-menu .tw-date-lookup-day-option{align-items:center;color:#37517e;color:var(--color-content-primary);display:inline-flex;height:32px;height:var(--size-32);justify-content:center;line-height:32px;line-height:var(--size-32)}.np-theme-personal .tw-date-lookup-menu .tw-date-lookup-day-option.active,.np-theme-personal.tw-date-lookup-menu .tw-date-lookup-day-option.active{background-color:#00a2dd;background-color:var(--color-interactive-accent);color:var(--color-interactive-primary)}
|
|
1
|
+
.tw-date-lookup-menu{width:400px}.tw-date-lookup-calendar{min-width:300px;table-layout:fixed;text-align:center}.tw-date-lookup-calendar>tbody>tr>td{padding:4px;padding:var(--size-4)}.tw-date-lookup-calendar>tbody>tr>td button{background-color:transparent;border:transparent;border-radius:10px;border-radius:var(--radius-small);color:#0097c7;color:var(--color-content-accent);font-weight:600;font-weight:var(--font-weight-semi-bold);padding:4px 0;padding:var(--size-4) 0;width:100%}.tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled).active{background-color:#0081ba;background-color:var(--color-interactive-accent-active);color:#fff}.tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled):hover{background-color:#008fc9;background-color:var(--color-interactive-accent-hover);color:#fff}.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td button{color:#37517e;color:var(--color-content-primary)}.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled).active,.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td button:not(.disabled,:disabled):hover{color:var(--color-interactive-control)}.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td:nth-child(7n+6) button,.np-theme-personal .tw-date-lookup-calendar>tbody>tr>td:nth-child(7n+7) button,.np-theme-personal .tw-date-lookup-calendar>thead>tr>th:nth-child(7n+6),.np-theme-personal .tw-date-lookup-calendar>thead>tr>th:nth-child(7n+7){color:#5d7079;color:var(--color-content-secondary);font-weight:400;font-weight:var(--font-weight-regular)}.tw-date-lookup-calendar abbr{text-decoration:none}.np-theme-personal .tw-date-lookup-calendar{background-color:inherit}.tw-date-lookup-header-current{font-weight:800;font-weight:var(--font-weight-bold)}.np-theme-personal .tw-date-lookup-menu .table-bordered,.np-theme-personal.tw-date-lookup-menu .table-bordered{border:none}.np-theme-personal .tw-date-lookup-menu thead,.np-theme-personal.tw-date-lookup-menu thead{background-color:unset}.np-theme-personal .tw-date-lookup-menu td,.np-theme-personal.tw-date-lookup-menu td{border:none}.np-theme-personal .tw-date-lookup-menu .tw-date-lookup-header-current,.np-theme-personal.tw-date-lookup-menu .tw-date-lookup-header-current{color:#37517e;color:var(--color-content-primary)}.np-theme-personal .tw-date-lookup-menu .tw-date-lookup-day-option,.np-theme-personal.tw-date-lookup-menu .tw-date-lookup-day-option{align-items:center;color:#37517e;color:var(--color-content-primary);display:inline-flex;height:32px;height:var(--size-32);justify-content:center;line-height:32px;line-height:var(--size-32)}.np-theme-personal .tw-date-lookup-menu .tw-date-lookup-day-option.active,.np-theme-personal.tw-date-lookup-menu .tw-date-lookup-day-option.active{background-color:#00a2dd;background-color:var(--color-interactive-accent);color:var(--color-interactive-primary)}
|
|
@@ -7,13 +7,13 @@ import KEY_CODES from '../common/keyCodes';
|
|
|
7
7
|
import DateLookup from '.';
|
|
8
8
|
|
|
9
9
|
const defaultLocale = 'en-GB';
|
|
10
|
-
|
|
10
|
+
const formatMessage = (id) => `${id}`;
|
|
11
11
|
jest.mock('react-intl', () => ({
|
|
12
12
|
injectIntl: (Component) =>
|
|
13
13
|
function (props) {
|
|
14
|
-
return <Component {...props} intl={{ locale: defaultLocale }} />;
|
|
14
|
+
return <Component {...props} intl={{ locale: defaultLocale, formatMessage }} />;
|
|
15
15
|
},
|
|
16
|
-
useIntl: () => ({ locale: defaultLocale }),
|
|
16
|
+
useIntl: () => ({ locale: defaultLocale, formatMessage }),
|
|
17
17
|
defineMessages: (translations) => translations,
|
|
18
18
|
}));
|
|
19
19
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defineMessages } from 'react-intl';
|
|
2
|
+
|
|
3
|
+
export default defineMessages({
|
|
4
|
+
next: {
|
|
5
|
+
id: 'neptune.DateLookup.next',
|
|
6
|
+
defaultMessage: 'next',
|
|
7
|
+
description: 'Description of next button',
|
|
8
|
+
},
|
|
9
|
+
previous: {
|
|
10
|
+
id: 'neptune.DateLookup.previous',
|
|
11
|
+
defaultMessage: 'previous',
|
|
12
|
+
description: 'Description of previous button',
|
|
13
|
+
},
|
|
14
|
+
day: {
|
|
15
|
+
id: 'neptune.DateLookup.day',
|
|
16
|
+
defaultMessage: 'day',
|
|
17
|
+
description: 'Description of next/previous/selected day button',
|
|
18
|
+
},
|
|
19
|
+
month: {
|
|
20
|
+
id: 'neptune.DateLookup.month',
|
|
21
|
+
defaultMessage: 'month',
|
|
22
|
+
description: 'Description of next/previous/selected month button',
|
|
23
|
+
},
|
|
24
|
+
year: {
|
|
25
|
+
id: 'neptune.DateLookup.year',
|
|
26
|
+
defaultMessage: 'year',
|
|
27
|
+
description: 'Description of next/previous/selected year button',
|
|
28
|
+
},
|
|
29
|
+
twentyYears: {
|
|
30
|
+
id: 'neptune.DateLookup.twentyYears',
|
|
31
|
+
defaultMessage: '20 years',
|
|
32
|
+
description: 'Description of next/previous 20 years button',
|
|
33
|
+
},
|
|
34
|
+
selected: {
|
|
35
|
+
id: 'neptune.DateLookup.selected',
|
|
36
|
+
defaultMessage: 'selected',
|
|
37
|
+
description: 'Description of the selected day/month/year',
|
|
38
|
+
},
|
|
39
|
+
goTo20YearView: {
|
|
40
|
+
id: 'neptune.DateLookup.goTo20YearView',
|
|
41
|
+
defaultMessage: 'Go to 20 year view',
|
|
42
|
+
description: 'Description of the button to go to 20 year view',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
@@ -54,6 +54,14 @@ describe('DateLookup (events)', () => {
|
|
|
54
54
|
expect(getActiveYearButton()).toHaveFocus();
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
it('has aria-label for 20 years', () => {
|
|
58
|
+
openDateLookup();
|
|
59
|
+
clickDateButton();
|
|
60
|
+
|
|
61
|
+
expect(getButtonByAriaLabel('next 20 years')).toBeInTheDocument();
|
|
62
|
+
expect(getButtonByAriaLabel('previous 20 years')).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
57
65
|
it('switches to months', () => {
|
|
58
66
|
openDateLookup();
|
|
59
67
|
clickDateButton();
|
|
@@ -62,6 +70,15 @@ describe('DateLookup (events)', () => {
|
|
|
62
70
|
expect(getActiveMonthButton()).toHaveFocus();
|
|
63
71
|
});
|
|
64
72
|
|
|
73
|
+
it('has aria label for year', () => {
|
|
74
|
+
openDateLookup();
|
|
75
|
+
clickDateButton();
|
|
76
|
+
user.click(getActiveYearButton());
|
|
77
|
+
|
|
78
|
+
expect(getButtonByAriaLabel('next year')).toBeInTheDocument();
|
|
79
|
+
expect(getButtonByAriaLabel('previous year')).toBeInTheDocument();
|
|
80
|
+
});
|
|
81
|
+
|
|
65
82
|
it('switches to days', () => {
|
|
66
83
|
openDateLookup();
|
|
67
84
|
clickDateButton();
|
|
@@ -71,6 +88,16 @@ describe('DateLookup (events)', () => {
|
|
|
71
88
|
expect(getActiveDayButton()).toHaveFocus();
|
|
72
89
|
});
|
|
73
90
|
|
|
91
|
+
it('has aria label for month', () => {
|
|
92
|
+
openDateLookup();
|
|
93
|
+
clickDateButton();
|
|
94
|
+
user.click(getActiveYearButton());
|
|
95
|
+
user.click(getActiveMonthButton());
|
|
96
|
+
|
|
97
|
+
expect(getButtonByAriaLabel('next month')).toBeInTheDocument();
|
|
98
|
+
expect(getButtonByAriaLabel('previous month')).toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
|
|
74
101
|
it('updates selected date and closes', () => {
|
|
75
102
|
openDateLookup();
|
|
76
103
|
const d = new Date(2018, 11, 28);
|
|
@@ -81,6 +108,15 @@ describe('DateLookup (events)', () => {
|
|
|
81
108
|
expect(getOpenButton()).toHaveFocus();
|
|
82
109
|
});
|
|
83
110
|
|
|
111
|
+
it('has aria label on selected date', () => {
|
|
112
|
+
openDateLookup();
|
|
113
|
+
const d = new Date(2018, 11, 28);
|
|
114
|
+
const newDay = screen.getByText(`${d.getDate()}`);
|
|
115
|
+
user.click(newDay);
|
|
116
|
+
openDateLookup();
|
|
117
|
+
expect(screen.getByRole('button', { name: /selected day/i })).toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
|
|
84
120
|
describe('at extra small breakpoints', () => {
|
|
85
121
|
it('opens dateLookup using slider on small + 1 width', () => {
|
|
86
122
|
winWidth(Breakpoint.SMALL + 1);
|
|
@@ -148,6 +184,9 @@ describe('DateLookup (events)', () => {
|
|
|
148
184
|
return container.querySelector('button.tw-date-lookup-day-option.active');
|
|
149
185
|
};
|
|
150
186
|
|
|
187
|
+
const getButtonByAriaLabel = (ariaLabel) => {
|
|
188
|
+
return screen.getByRole('button', { name: ariaLabel });
|
|
189
|
+
};
|
|
151
190
|
const getClearButton = () => container.querySelector('.clear-btn');
|
|
152
191
|
const getOpenButton = () => container.querySelector('button.np-date-trigger');
|
|
153
192
|
const getDateButton = () => container.querySelector('button.tw-date-lookup-header-current');
|