@transferwise/components 46.30.2 → 46.32.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/index.js +931 -523
- package/build/index.js.map +1 -1
- package/build/index.mjs +928 -523
- package/build/index.mjs.map +1 -1
- package/build/main.css +135 -0
- package/build/styles/carousel/Carousel.css +135 -0
- package/build/styles/main.css +135 -0
- package/build/types/carousel/Carousel.d.ts +26 -0
- package/build/types/carousel/Carousel.d.ts.map +1 -0
- package/build/types/carousel/index.d.ts +3 -0
- package/build/types/carousel/index.d.ts.map +1 -0
- package/build/types/common/card/Card.d.ts +2 -2
- package/build/types/common/card/Card.d.ts.map +1 -1
- package/build/types/dateInput/DateInput.d.ts +5 -4
- package/build/types/dateInput/DateInput.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.d.ts +11 -4
- package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
- package/build/types/field/Field.d.ts +12 -0
- package/build/types/field/Field.d.ts.map +1 -0
- package/build/types/index.d.ts +6 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/inputs/Input.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts +1 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/inputs/TextArea.d.ts.map +1 -1
- package/build/types/inputs/_common.d.ts +2 -2
- package/build/types/inputs/_common.d.ts.map +1 -1
- package/build/types/inputs/contexts.d.ts +24 -0
- package/build/types/inputs/contexts.d.ts.map +1 -0
- package/build/types/label/Label.d.ts +9 -0
- package/build/types/label/Label.d.ts.map +1 -0
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
- package/build/types/promoCard/PromoCard.d.ts +16 -5
- package/build/types/promoCard/PromoCard.d.ts.map +1 -1
- package/build/types/radioGroup/RadioGroup.d.ts.map +1 -1
- package/build/types/switch/Switch.d.ts +6 -3
- package/build/types/switch/Switch.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/carousel/Carousel.css +135 -0
- package/src/carousel/Carousel.less +133 -0
- package/src/carousel/Carousel.spec.tsx +221 -0
- package/src/carousel/Carousel.story.tsx +63 -0
- package/src/carousel/Carousel.tsx +345 -0
- package/src/carousel/index.ts +3 -0
- package/src/common/card/Card.tsx +51 -43
- package/src/dateInput/DateInput.rtl.spec.tsx +17 -0
- package/src/dateInput/DateInput.tsx +28 -22
- package/src/dateLookup/DateLookup.keyboardEvents.spec.js +2 -2
- package/src/dateLookup/DateLookup.rtl.spec.tsx +21 -0
- package/src/dateLookup/DateLookup.state.spec.js +5 -5
- package/src/dateLookup/DateLookup.tests.story.tsx +4 -11
- package/src/dateLookup/DateLookup.tsx +24 -9
- package/src/dateLookup/DateLookup.view.spec.js +11 -11
- package/src/field/Field.spec.tsx +95 -0
- package/src/field/Field.story.tsx +59 -0
- package/src/field/Field.tsx +70 -0
- package/src/index.ts +6 -0
- package/src/inputs/Input.tsx +5 -3
- package/src/inputs/SelectInput.spec.tsx +10 -0
- package/src/inputs/SelectInput.tsx +9 -4
- package/src/inputs/TextArea.tsx +6 -3
- package/src/inputs/_ButtonInput.tsx +2 -2
- package/src/inputs/_common.ts +2 -2
- package/src/inputs/contexts.tsx +45 -0
- package/src/label/Label.spec.tsx +26 -0
- package/src/label/Label.story.tsx +37 -0
- package/src/label/Label.tsx +20 -0
- package/src/main.css +135 -0
- package/src/main.less +1 -0
- package/src/phoneNumberInput/PhoneNumberInput.story.tsx +16 -22
- package/src/phoneNumberInput/PhoneNumberInput.tsx +14 -2
- package/src/promoCard/PromoCard.story.tsx +2 -2
- package/src/promoCard/PromoCard.tsx +30 -9
- package/src/radioGroup/RadioGroup.rtl.spec.tsx +14 -0
- package/src/radioGroup/RadioGroup.story.tsx +26 -0
- package/src/radioGroup/RadioGroup.tsx +4 -1
- package/src/switch/Switch.spec.tsx +10 -0
- package/src/switch/Switch.tsx +22 -13
- package/src/utilities/logActionRequired.js +1 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { useId } from '@radix-ui/react-id';
|
|
2
2
|
import { Check } from '@transferwise/icons';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
-
import React, { forwardRef, FunctionComponent, useEffect, useState } from 'react';
|
|
4
|
+
import React, { forwardRef, type FunctionComponent, useEffect, useState } from 'react';
|
|
5
5
|
|
|
6
6
|
import Body from '../body';
|
|
7
7
|
import { Typography } from '../common';
|
|
8
|
-
import Card, { CardProps } from '../common/card';
|
|
8
|
+
import Card, { type CardProps } from '../common/card';
|
|
9
9
|
import Display from '../display';
|
|
10
10
|
import Image from '../image/Image';
|
|
11
11
|
import Title from '../title';
|
|
12
12
|
|
|
13
13
|
import { usePromoCardContext } from './PromoCardContext';
|
|
14
|
-
import PromoCardIndicator, { PromoCardIndicatorProps } from './PromoCardIndicator';
|
|
14
|
+
import PromoCardIndicator, { type PromoCardIndicatorProps } from './PromoCardIndicator';
|
|
15
15
|
|
|
16
|
-
export type ReferenceType = React.Ref<HTMLInputElement>;
|
|
16
|
+
export type ReferenceType = React.Ref<HTMLInputElement> | React.Ref<HTMLDivElement>;
|
|
17
17
|
export type RelatedTypes =
|
|
18
18
|
| ''
|
|
19
19
|
| 'alternate'
|
|
@@ -68,6 +68,9 @@ export interface PromoCardCommonProps {
|
|
|
68
68
|
/** Specify an onClick event handler */
|
|
69
69
|
onClick?: () => void;
|
|
70
70
|
|
|
71
|
+
/** Specify an onKeyDown event handler */
|
|
72
|
+
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
73
|
+
|
|
71
74
|
/** Optional prop to specify the ID used for testing */
|
|
72
75
|
testId?: string;
|
|
73
76
|
|
|
@@ -76,6 +79,8 @@ export interface PromoCardCommonProps {
|
|
|
76
79
|
|
|
77
80
|
/** Set to false to use body font style for the title */
|
|
78
81
|
useDisplayFont?: boolean;
|
|
82
|
+
|
|
83
|
+
ref?: ReferenceType;
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
export interface PromoCardLinkProps extends PromoCardCommonProps, Omit<CardProps, 'children'> {
|
|
@@ -91,6 +96,14 @@ export interface PromoCardLinkProps extends PromoCardCommonProps, Omit<CardProps
|
|
|
91
96
|
/** Optionally specify the language of the linked URL */
|
|
92
97
|
hrefLang?: string;
|
|
93
98
|
|
|
99
|
+
/** Optional property that can be pass a ref for the anchor. */
|
|
100
|
+
anchorRef?: React.Ref<HTMLAnchorElement>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Optional prop to specify the ID of the anchor element which can be useful when using a ref.
|
|
104
|
+
*/
|
|
105
|
+
anchorId?: string;
|
|
106
|
+
|
|
94
107
|
/**
|
|
95
108
|
* Relationship between the PromoCard href URL and the current page. See
|
|
96
109
|
* [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel).
|
|
@@ -105,7 +118,7 @@ export interface PromoCardLinkProps extends PromoCardCommonProps, Omit<CardProps
|
|
|
105
118
|
isChecked?: never;
|
|
106
119
|
tabIndex?: never;
|
|
107
120
|
type?: never;
|
|
108
|
-
|
|
121
|
+
ref?: ReferenceType;
|
|
109
122
|
value?: never;
|
|
110
123
|
}
|
|
111
124
|
|
|
@@ -120,7 +133,7 @@ export interface PromoCardCheckedProps extends PromoCardCommonProps, Omit<CardPr
|
|
|
120
133
|
tabIndex?: number;
|
|
121
134
|
|
|
122
135
|
/** Optional property to provide component Ref */
|
|
123
|
-
|
|
136
|
+
ref?: ReferenceType;
|
|
124
137
|
|
|
125
138
|
/** Optional prop to specify the input type of the PromoCard */
|
|
126
139
|
type?: 'checkbox' | 'radio';
|
|
@@ -131,6 +144,8 @@ export interface PromoCardCheckedProps extends PromoCardCommonProps, Omit<CardPr
|
|
|
131
144
|
/** Only applies to <a />s */
|
|
132
145
|
download?: never;
|
|
133
146
|
href?: never;
|
|
147
|
+
anchorRef?: never;
|
|
148
|
+
anchorId?: never;
|
|
134
149
|
hrefLang?: never;
|
|
135
150
|
rel?: never;
|
|
136
151
|
target?: never;
|
|
@@ -202,6 +217,7 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
|
|
|
202
217
|
isChecked,
|
|
203
218
|
isDisabled,
|
|
204
219
|
onClick,
|
|
220
|
+
onKeyDown,
|
|
205
221
|
rel,
|
|
206
222
|
tabIndex,
|
|
207
223
|
target,
|
|
@@ -211,9 +227,11 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
|
|
|
211
227
|
value,
|
|
212
228
|
isSmall,
|
|
213
229
|
useDisplayFont = true,
|
|
230
|
+
anchorRef,
|
|
231
|
+
anchorId,
|
|
214
232
|
...props
|
|
215
233
|
},
|
|
216
|
-
|
|
234
|
+
ref: ReferenceType,
|
|
217
235
|
) => {
|
|
218
236
|
// Set the `checked` state to the value of `defaultChecked` if it is truthy,
|
|
219
237
|
// or the value of `isChecked` if it is truthy, or `false` if neither
|
|
@@ -276,7 +294,8 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
|
|
|
276
294
|
id: componentId,
|
|
277
295
|
isDisabled: isDisabled || contextIsDisabled,
|
|
278
296
|
onClick,
|
|
279
|
-
|
|
297
|
+
onKeyDown,
|
|
298
|
+
ref,
|
|
280
299
|
'data-testid': testId,
|
|
281
300
|
isSmall,
|
|
282
301
|
};
|
|
@@ -291,6 +310,8 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
|
|
|
291
310
|
hrefLang,
|
|
292
311
|
rel,
|
|
293
312
|
target,
|
|
313
|
+
ref: anchorRef,
|
|
314
|
+
id: anchorId,
|
|
294
315
|
}
|
|
295
316
|
: {};
|
|
296
317
|
|
|
@@ -311,7 +332,7 @@ const PromoCard: FunctionComponent<PromoCardProps> = forwardRef(
|
|
|
311
332
|
handleClick();
|
|
312
333
|
}
|
|
313
334
|
},
|
|
314
|
-
ref
|
|
335
|
+
ref,
|
|
315
336
|
tabIndex: 0,
|
|
316
337
|
}
|
|
317
338
|
: {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { render, screen } from '@testing-library/react';
|
|
2
2
|
|
|
3
3
|
import RadioGroup from '.';
|
|
4
|
+
import { Field } from '../field/Field';
|
|
4
5
|
|
|
5
6
|
describe('RadioGroup', () => {
|
|
6
7
|
it('has accessible role', () => {
|
|
@@ -13,4 +14,17 @@ describe('RadioGroup', () => {
|
|
|
13
14
|
);
|
|
14
15
|
expect(screen.getByRole('radiogroup')).toBeInTheDocument();
|
|
15
16
|
});
|
|
17
|
+
|
|
18
|
+
it('supports `Field` for labeling', () => {
|
|
19
|
+
render(
|
|
20
|
+
<Field label="Currency">
|
|
21
|
+
<RadioGroup
|
|
22
|
+
name="currency"
|
|
23
|
+
radios={[{ label: 'USD' }, { label: 'EUR' }]}
|
|
24
|
+
onChange={() => {}}
|
|
25
|
+
/>
|
|
26
|
+
</Field>,
|
|
27
|
+
);
|
|
28
|
+
expect(screen.getByRole('radiogroup')).toHaveAccessibleName(/^Currency/);
|
|
29
|
+
});
|
|
16
30
|
});
|
|
@@ -5,6 +5,7 @@ import { Flag } from '@wise/art';
|
|
|
5
5
|
import Avatar, { AvatarType } from '../avatar';
|
|
6
6
|
|
|
7
7
|
import RadioGroup from './RadioGroup';
|
|
8
|
+
import { Field } from '../field/Field';
|
|
8
9
|
|
|
9
10
|
export default {
|
|
10
11
|
component: RadioGroup,
|
|
@@ -53,3 +54,28 @@ export const Basic = () => {
|
|
|
53
54
|
</div>
|
|
54
55
|
);
|
|
55
56
|
};
|
|
57
|
+
|
|
58
|
+
export const Labeled = () => {
|
|
59
|
+
return (
|
|
60
|
+
<Field label="Do you like our product?">
|
|
61
|
+
<RadioGroup
|
|
62
|
+
name="radio-group"
|
|
63
|
+
radios={[
|
|
64
|
+
{
|
|
65
|
+
value: 'yes',
|
|
66
|
+
label: 'Yes',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
value: 'definitely',
|
|
70
|
+
label: 'Definitely',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
value: 'absolutely',
|
|
74
|
+
label: 'Absolutely',
|
|
75
|
+
},
|
|
76
|
+
]}
|
|
77
|
+
onChange={(v) => action(v)}
|
|
78
|
+
/>
|
|
79
|
+
</Field>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import Radio from '../radio';
|
|
4
4
|
import { RadioProps } from '../radio/Radio';
|
|
5
|
+
import { useInputAttributes } from '../inputs/contexts';
|
|
5
6
|
|
|
6
7
|
export type RadioGroupRadio<T extends string | number = string> = Omit<
|
|
7
8
|
RadioProps<T>,
|
|
@@ -21,10 +22,12 @@ export default function RadioGroup<T extends string | number = never>({
|
|
|
21
22
|
selectedValue: controlledValue,
|
|
22
23
|
onChange,
|
|
23
24
|
}: RadioGroupProps<T>) {
|
|
25
|
+
const inputAttributes = useInputAttributes({ nonLabelable: true });
|
|
26
|
+
|
|
24
27
|
const [uncontrolledValue, setUncontrolledValue] = useState(controlledValue);
|
|
25
28
|
|
|
26
29
|
return radios.length > 0 ? (
|
|
27
|
-
<div role="radiogroup">
|
|
30
|
+
<div role="radiogroup" {...inputAttributes}>
|
|
28
31
|
{radios.map(({ value = '' as T, ...restProps }, index) => (
|
|
29
32
|
<Radio
|
|
30
33
|
// eslint-disable-next-line react/no-array-index-key
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Field } from '../field/Field';
|
|
1
2
|
import { render, fireEvent, screen } from '../test-utils';
|
|
2
3
|
|
|
3
4
|
import Switch from './Switch';
|
|
@@ -81,4 +82,13 @@ describe('Switch', () => {
|
|
|
81
82
|
fireEvent.click(input);
|
|
82
83
|
expect(mockCallback).not.toHaveBeenCalled();
|
|
83
84
|
});
|
|
85
|
+
|
|
86
|
+
it('supports `Field` for labeling', () => {
|
|
87
|
+
render(
|
|
88
|
+
<Field label="Dark mode">
|
|
89
|
+
<Switch checked onClick={props.onClick} />
|
|
90
|
+
</Field>,
|
|
91
|
+
);
|
|
92
|
+
expect(screen.getByLabelText('Dark mode')).toHaveAttribute('role', 'switch');
|
|
93
|
+
});
|
|
84
94
|
});
|
package/src/switch/Switch.tsx
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { CheckCircleFill, CrossCircleFill } from '@transferwise/icons';
|
|
2
2
|
import { useTheme } from '@wise/components-theming';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
|
-
import { KeyboardEventHandler, MouseEvent } from 'react';
|
|
4
|
+
import type { KeyboardEventHandler, MouseEvent } from 'react';
|
|
5
5
|
|
|
6
|
-
import { CommonProps } from '../common';
|
|
7
|
-
import {
|
|
6
|
+
import type { CommonProps } from '../common';
|
|
7
|
+
import { useInputAttributes } from '../inputs/contexts';
|
|
8
8
|
|
|
9
9
|
export type SwitchProps = CommonProps & {
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Used to describe the purpose of the switch. To be used if there is no external label (i.e. aria-labelledby is null)
|
|
12
|
+
* @deprecated Use `Field` wrapper or the `aria-labelledby` attribute instead.
|
|
13
|
+
*/
|
|
11
14
|
'aria-label'?: string;
|
|
12
15
|
/** A reference to a label that describes the purpose of the switch. Ignored if aria-label is provided */
|
|
13
16
|
'aria-labelledby'?: string;
|
|
@@ -21,8 +24,18 @@ export type SwitchProps = CommonProps & {
|
|
|
21
24
|
};
|
|
22
25
|
|
|
23
26
|
const Switch = (props: SwitchProps) => {
|
|
27
|
+
const inputAttributes = useInputAttributes({ nonLabelable: true });
|
|
28
|
+
|
|
24
29
|
const { isModern } = useTheme();
|
|
25
|
-
const {
|
|
30
|
+
const {
|
|
31
|
+
checked,
|
|
32
|
+
className,
|
|
33
|
+
id = inputAttributes.id,
|
|
34
|
+
'aria-label': ariaLabel,
|
|
35
|
+
'aria-labelledby': ariaLabelledbyProp,
|
|
36
|
+
onClick,
|
|
37
|
+
disabled,
|
|
38
|
+
} = props;
|
|
26
39
|
|
|
27
40
|
const handleKeyDown: KeyboardEventHandler = (event) => {
|
|
28
41
|
if (event.key === ' ') {
|
|
@@ -50,13 +63,8 @@ const Switch = (props: SwitchProps) => {
|
|
|
50
63
|
);
|
|
51
64
|
};
|
|
52
65
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
logActionRequiredIf(
|
|
57
|
-
'Switch now expects either `aria-label` or `aria-labelledby`, and will soon make these props required. Please update your usage to provide one or the other.',
|
|
58
|
-
!ariaLabel && !ariaLabelledby,
|
|
59
|
-
);
|
|
66
|
+
const ariaLabelledby =
|
|
67
|
+
(ariaLabel ? undefined : ariaLabelledbyProp) ?? inputAttributes['aria-labelledby'];
|
|
60
68
|
|
|
61
69
|
return (
|
|
62
70
|
<span
|
|
@@ -66,7 +74,7 @@ const Switch = (props: SwitchProps) => {
|
|
|
66
74
|
{
|
|
67
75
|
'np-switch--unchecked': !checked,
|
|
68
76
|
'np-switch--checked': checked,
|
|
69
|
-
disabled
|
|
77
|
+
disabled,
|
|
70
78
|
},
|
|
71
79
|
className,
|
|
72
80
|
)}
|
|
@@ -74,6 +82,7 @@ const Switch = (props: SwitchProps) => {
|
|
|
74
82
|
role="switch"
|
|
75
83
|
aria-checked={checked}
|
|
76
84
|
aria-label={ariaLabel}
|
|
85
|
+
{...inputAttributes}
|
|
77
86
|
aria-labelledby={ariaLabelledby}
|
|
78
87
|
id={id}
|
|
79
88
|
aria-disabled={disabled}
|