@transferwise/components 46.14.0 → 46.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.
Files changed (63) hide show
  1. package/build/index.esm.js +97 -196
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +100 -199
  4. package/build/index.js.map +1 -1
  5. package/build/types/actionButton/ActionButton.d.ts +1 -1
  6. package/build/types/common/Option/Option.d.ts.map +1 -1
  7. package/build/types/common/RadioButton/RadioButton.d.ts +10 -34
  8. package/build/types/common/RadioButton/RadioButton.d.ts.map +1 -1
  9. package/build/types/common/RadioButton/index.d.ts +1 -1
  10. package/build/types/common/RadioButton/index.d.ts.map +1 -1
  11. package/build/types/index.d.ts +4 -0
  12. package/build/types/index.d.ts.map +1 -1
  13. package/build/types/instructionsList/InstructionsList.d.ts +4 -2
  14. package/build/types/instructionsList/InstructionsList.d.ts.map +1 -1
  15. package/build/types/instructionsList/index.d.ts +2 -2
  16. package/build/types/instructionsList/index.d.ts.map +1 -1
  17. package/build/types/moneyInput/MoneyInput.d.ts +1 -0
  18. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  19. package/build/types/radio/Radio.d.ts +10 -21
  20. package/build/types/radio/Radio.d.ts.map +1 -1
  21. package/build/types/radio/index.d.ts +2 -2
  22. package/build/types/radio/index.d.ts.map +1 -1
  23. package/build/types/radioGroup/RadioGroup.d.ts +10 -26
  24. package/build/types/radioGroup/RadioGroup.d.ts.map +1 -1
  25. package/build/types/radioGroup/index.d.ts +2 -1
  26. package/build/types/radioGroup/index.d.ts.map +1 -1
  27. package/build/types/radioOption/RadioOption.d.ts +15 -23
  28. package/build/types/radioOption/RadioOption.d.ts.map +1 -1
  29. package/build/types/radioOption/index.d.ts +2 -1
  30. package/build/types/radioOption/index.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/common/Option/Option.tsx +0 -1
  33. package/src/common/RadioButton/RadioButton.tsx +43 -0
  34. package/src/index.ts +4 -0
  35. package/src/instructionsList/InstructionsList.spec.tsx +14 -0
  36. package/src/instructionsList/{InstructionList.story.tsx → InstructionsList.story.tsx} +14 -2
  37. package/src/instructionsList/InstructionsList.tsx +31 -17
  38. package/src/instructionsList/index.ts +3 -0
  39. package/src/moneyInput/MoneyInput.rtl.spec.tsx +12 -0
  40. package/src/moneyInput/MoneyInput.tsx +12 -2
  41. package/src/radio/{Radio.story.js → Radio.story.tsx} +0 -3
  42. package/src/radio/{Radio.js → Radio.tsx} +18 -28
  43. package/src/radio/index.ts +2 -0
  44. package/src/radioGroup/RadioGroup.spec.js +24 -26
  45. package/src/radioGroup/{RadioGroup.story.js → RadioGroup.story.tsx} +0 -3
  46. package/src/radioGroup/RadioGroup.tsx +39 -0
  47. package/src/radioGroup/index.ts +2 -0
  48. package/src/radioOption/RadioOption.spec.js +4 -4
  49. package/src/radioOption/{RadioOption.story.js → RadioOption.story.tsx} +4 -4
  50. package/src/radioOption/RadioOption.tsx +60 -0
  51. package/src/radioOption/index.ts +2 -0
  52. package/src/common/RadioButton/RadioButton.js +0 -41
  53. package/src/instructionsList/index.js +0 -3
  54. package/src/radio/index.js +0 -3
  55. package/src/radioGroup/RadioGroup.js +0 -66
  56. package/src/radioGroup/index.js +0 -1
  57. package/src/radioOption/RadioOption.js +0 -81
  58. package/src/radioOption/index.js +0 -1
  59. /package/src/common/RadioButton/{RadioButton.spec.js → RadioButton.spec.tsx} +0 -0
  60. /package/src/common/RadioButton/__snapshots__/{RadioButton.spec.js.snap → RadioButton.spec.tsx.snap} +0 -0
  61. /package/src/common/RadioButton/{index.js → index.ts} +0 -0
  62. /package/src/radio/{Radio.rtl.spec.js → Radio.rtl.spec.tsx} +0 -0
  63. /package/src/radio/__snapshots__/{Radio.rtl.spec.js.snap → Radio.rtl.spec.tsx.snap} +0 -0
@@ -90,6 +90,7 @@ const allowedInputKeys = new Set([
90
90
 
91
91
  export interface MoneyInputProps extends WrappedComponentProps {
92
92
  id?: string;
93
+ 'aria-labelledby'?: string;
93
94
  currencies: readonly CurrencyItem[];
94
95
  selectedCurrency: CurrencyOptionItem;
95
96
  onCurrencyChange?: (value: CurrencyOptionItem) => void;
@@ -295,8 +296,16 @@ class MoneyInput extends Component<MoneyInputProps, MoneyInputState> {
295
296
  style = (className: string) => this.props.classNames[className] || className;
296
297
 
297
298
  render() {
298
- const { selectedCurrency, onCurrencyChange, size, addon, id, selectProps, maxLengthOverride } =
299
- this.props;
299
+ const {
300
+ selectedCurrency,
301
+ onCurrencyChange,
302
+ size,
303
+ addon,
304
+ id,
305
+ 'aria-labelledby': ariaLabelledBy,
306
+ selectProps,
307
+ maxLengthOverride,
308
+ } = this.props;
300
309
  const selectOptions = this.getSelectOptions();
301
310
 
302
311
  const hasSingleCurrency = () => {
@@ -326,6 +335,7 @@ class MoneyInput extends Component<MoneyInputProps, MoneyInputState> {
326
335
  const disabled = !this.props.onAmountChange;
327
336
  return (
328
337
  <div
338
+ aria-labelledby={ariaLabelledBy}
329
339
  className={classNames(
330
340
  this.style('tw-money-input'),
331
341
  this.style('input-group'),
@@ -1,5 +1,4 @@
1
1
  import { boolean, text } from '@storybook/addon-knobs';
2
- import { Check } from '@transferwise/icons';
3
2
  import { Flag } from '@wise/art';
4
3
  import { useState } from 'react';
5
4
 
@@ -62,7 +61,6 @@ export const Basic = () => {
62
61
  <div className={`form-group ${hasError ? 'has-error' : ''}`}>
63
62
  <Checkbox
64
63
  label={label}
65
- name="lol"
66
64
  id="test"
67
65
  checked={checked}
68
66
  disabled={disabled}
@@ -73,7 +71,6 @@ export const Basic = () => {
73
71
  <div className={`form-group ${hasError ? 'has-error' : ''}`}>
74
72
  <Checkbox
75
73
  label={label}
76
- name="lol"
77
74
  id="test"
78
75
  checked={checked}
79
76
  disabled={disabled}
@@ -1,12 +1,27 @@
1
1
  import { useTheme } from '@wise/components-theming';
2
2
  import classNames from 'classnames';
3
- import PropTypes from 'prop-types';
4
3
 
5
4
  import Body from '../body/Body';
6
5
  import { Typography } from '../common';
7
6
  import RadioButton from '../common/RadioButton';
7
+ import { RadioButtonProps } from '../common/RadioButton/RadioButton';
8
8
 
9
- const Radio = ({ label, id, disabled, className, avatar, secondary, ...otherProps }) => {
9
+ export interface RadioProps<T extends string | number = string> extends RadioButtonProps<T> {
10
+ avatar?: React.ReactNode;
11
+ label: string;
12
+ secondary?: string;
13
+ className?: string;
14
+ }
15
+
16
+ export default function Radio<T extends string | number = string>({
17
+ label,
18
+ id,
19
+ disabled,
20
+ className,
21
+ avatar,
22
+ secondary,
23
+ ...otherProps
24
+ }: RadioProps<T>) {
10
25
  const { isModern } = useTheme();
11
26
  return (
12
27
  <div
@@ -39,29 +54,4 @@ const Radio = ({ label, id, disabled, className, avatar, secondary, ...otherProp
39
54
  </label>
40
55
  </div>
41
56
  );
42
- };
43
-
44
- Radio.propTypes = {
45
- avatar: PropTypes.element,
46
- checked: PropTypes.bool,
47
- disabled: PropTypes.bool,
48
- id: PropTypes.string,
49
- label: PropTypes.string.isRequired,
50
- name: PropTypes.string.isRequired,
51
- onChange: PropTypes.func.isRequired,
52
- secondary: PropTypes.string,
53
- value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
54
- className: PropTypes.string,
55
- };
56
-
57
- Radio.defaultProps = {
58
- avatar: undefined,
59
- checked: false,
60
- disabled: false,
61
- id: null,
62
- secondary: null,
63
- value: '',
64
- className: undefined,
65
- };
66
-
67
- export default Radio;
57
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from './Radio';
2
+ export type { RadioProps } from './Radio';
@@ -40,37 +40,35 @@ describe('RadioGroup', () => {
40
40
  it('renders radio options', () => {
41
41
  const component = shallow(<RadioGroup radios={RADIOS} {...props} />);
42
42
  expect(component.find(Radio)).toHaveLength(RADIOS.length);
43
- expect(JSON.stringify(component.find(Radio).at(0).props())).toStrictEqual(
44
- JSON.stringify({
45
- id: 'id-test-0',
46
- value: 'value-test0',
47
- label: 'Radio1',
48
- name: 'radio-group',
49
- disabled: true,
50
- checked: false,
51
- secondary: 'secondary',
52
- onChange: () => props.onChange,
53
- avatar,
54
- }),
55
- );
43
+
44
+ const { onChange, ...primitiveProps } = component.find(Radio).at(0).props();
45
+ expect(primitiveProps).toStrictEqual({
46
+ id: 'id-test-0',
47
+ value: 'value-test0',
48
+ label: 'Radio1',
49
+ name: 'radio-group',
50
+ disabled: true,
51
+ checked: false,
52
+ secondary: 'secondary',
53
+ avatar,
54
+ });
56
55
  });
57
56
 
58
57
  it('renders a single radio option, when radios array contains a single element', () => {
59
58
  const component = shallow(<RadioGroup radios={RADIOS.slice(0, 1)} {...props} />);
60
59
  expect(component.find(Radio)).toHaveLength(1);
61
- expect(JSON.stringify(component.find(Radio).at(0).props())).toStrictEqual(
62
- JSON.stringify({
63
- id: 'id-test-0',
64
- value: 'value-test0',
65
- label: 'Radio1',
66
- name: 'radio-group',
67
- disabled: true,
68
- checked: false,
69
- secondary: 'secondary',
70
- onChange: () => props.onChange,
71
- avatar,
72
- }),
73
- );
60
+
61
+ const { onChange, ...primitiveProps } = component.find(Radio).at(0).props();
62
+ expect(primitiveProps).toStrictEqual({
63
+ id: 'id-test-0',
64
+ value: 'value-test0',
65
+ label: 'Radio1',
66
+ name: 'radio-group',
67
+ disabled: true,
68
+ checked: false,
69
+ secondary: 'secondary',
70
+ avatar,
71
+ });
74
72
  });
75
73
 
76
74
  it('checks specified radio', () => {
@@ -31,14 +31,12 @@ export const Basic = () => {
31
31
  value: 'radio-1',
32
32
  label: 'Radio1',
33
33
  secondary: 'Secondary line 1',
34
- name: 'name',
35
34
  disabled: false,
36
35
  avatar,
37
36
  },
38
37
  {
39
38
  value: 'radio-2',
40
39
  label: 'Radio2',
41
- name: 'name',
42
40
  disabled: false,
43
41
  avatar,
44
42
  },
@@ -46,7 +44,6 @@ export const Basic = () => {
46
44
  value: 'radio-3',
47
45
  label: 'Radio3',
48
46
  secondary: 'Secondary line 3',
49
- name: 'name',
50
47
  disabled: true,
51
48
  avatar,
52
49
  },
@@ -0,0 +1,39 @@
1
+ import { useState } from 'react';
2
+
3
+ import Radio from '../radio';
4
+ import { RadioProps } from '../radio/Radio';
5
+
6
+ export interface RadioGroupProps<T extends string | number = string> {
7
+ name: string;
8
+ radios: Omit<RadioProps<T>, 'name' | 'checked' | 'onChange' | 'className'>[];
9
+ selectedValue?: T | '';
10
+ onChange: NonNullable<RadioProps<T>['onChange']>;
11
+ }
12
+
13
+ export default function RadioGroup<T extends string | number = string>({
14
+ name,
15
+ radios,
16
+ selectedValue: controlledValue,
17
+ onChange,
18
+ }: RadioGroupProps<T>) {
19
+ const [uncontrolledValue, setUncontrolledValue] = useState(controlledValue);
20
+
21
+ return radios.length > 0 ? (
22
+ <div role="radiogroup">
23
+ {radios.map(({ value = '', ...restProps }, index) => (
24
+ <Radio
25
+ // eslint-disable-next-line react/no-array-index-key
26
+ key={index}
27
+ {...restProps}
28
+ name={name}
29
+ value={value}
30
+ checked={value === uncontrolledValue}
31
+ onChange={(nextValue) => {
32
+ setUncontrolledValue(nextValue);
33
+ onChange(nextValue);
34
+ }}
35
+ />
36
+ ))}
37
+ </div>
38
+ ) : null;
39
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from './RadioGroup';
2
+ export type { RadioGroupProps } from './RadioGroup';
@@ -38,9 +38,9 @@ describe('Radio option', () => {
38
38
  });
39
39
 
40
40
  it('passes checked to radio button passed as button', () => {
41
- expect(buttonProperty('checked')).toBe(false);
41
+ expect(buttonProperty('checked')).toBeFalsy();
42
42
  component.setProps({ checked: true });
43
- expect(buttonProperty('checked')).toBe(true);
43
+ expect(buttonProperty('checked')).toBeTruthy();
44
44
  });
45
45
 
46
46
  it('passes change handler to radio button passed as button', () => {
@@ -50,9 +50,9 @@ describe('Radio option', () => {
50
50
  });
51
51
 
52
52
  it('passes disabled to radio button passed as button', () => {
53
- expect(buttonProperty('disabled')).toBe(false);
53
+ expect(buttonProperty('disabled')).toBeFalsy();
54
54
  component.setProps({ disabled: true });
55
- expect(buttonProperty('disabled')).toBe(true);
55
+ expect(buttonProperty('disabled')).toBeTruthy();
56
56
  });
57
57
 
58
58
  it('renders aligned with container content', () => {
@@ -5,14 +5,14 @@ import { useState } from 'react';
5
5
 
6
6
  import { Nudge } from '..';
7
7
 
8
- import RadioOption from './RadioOption';
8
+ import RadioOption, { RadioOptionProps } from './RadioOption';
9
9
 
10
10
  export default {
11
11
  component: RadioOption,
12
12
  title: 'Option/RadioOption',
13
13
  };
14
14
 
15
- const Template = (props) => {
15
+ const Template = (props: Partial<RadioOptionProps>) => {
16
16
  const showMediaAtAllSizes = boolean('showMediaAtAllSizes', false);
17
17
  const title = text('title', 'title');
18
18
  const disabled = boolean('disabled', false);
@@ -32,9 +32,9 @@ const Template = (props) => {
32
32
  value="value"
33
33
  showMediaAtAllSizes={showMediaAtAllSizes}
34
34
  isContainerAligned={isContainerAligned}
35
- onChange={() => {
35
+ onChange={(value) => {
36
36
  action('checked');
37
- props.onChange();
37
+ props.onChange?.(value);
38
38
  }}
39
39
  />
40
40
  );
@@ -0,0 +1,60 @@
1
+ import Option from '../common/Option';
2
+ import RadioButton from '../common/RadioButton';
3
+ import { RadioButtonProps } from '../common/RadioButton/RadioButton';
4
+
5
+ export interface RadioOptionProps<T extends string | number = string>
6
+ extends Required<Pick<RadioButtonProps<T>, 'id' | 'name' | 'onChange'>>,
7
+ Omit<RadioButtonProps<T>, 'readOnly' | 'id' | 'name' | 'onChange'> {
8
+ 'aria-label'?: string;
9
+ media?: React.ReactNode;
10
+ title: React.ReactNode;
11
+ content?: React.ReactNode;
12
+ complex?: boolean;
13
+ showMediaCircle?: boolean;
14
+ showMediaAtAllSizes?: boolean;
15
+ isContainerAligned?: boolean;
16
+ }
17
+
18
+ function RadioOption<T extends string | number = string>({
19
+ 'aria-label': ariaLabel,
20
+ media,
21
+ title,
22
+ content,
23
+ id,
24
+ name,
25
+ checked,
26
+ onChange,
27
+ complex,
28
+ disabled,
29
+ value,
30
+ showMediaCircle,
31
+ showMediaAtAllSizes,
32
+ isContainerAligned,
33
+ }: RadioOptionProps<T>) {
34
+ return (
35
+ <Option
36
+ aria-label={ariaLabel}
37
+ media={media}
38
+ title={title}
39
+ content={content}
40
+ name={name}
41
+ complex={complex}
42
+ disabled={disabled}
43
+ showMediaCircle={showMediaCircle}
44
+ showMediaAtAllSizes={showMediaAtAllSizes}
45
+ isContainerAligned={isContainerAligned}
46
+ button={
47
+ <RadioButton
48
+ id={id}
49
+ name={name}
50
+ checked={checked}
51
+ disabled={disabled}
52
+ value={value}
53
+ onChange={onChange}
54
+ />
55
+ }
56
+ />
57
+ );
58
+ }
59
+
60
+ export default RadioOption;
@@ -0,0 +1,2 @@
1
+ export { default } from './RadioOption';
2
+ export type { RadioOptionProps } from './RadioOption';
@@ -1,41 +0,0 @@
1
- import classNames from 'classnames';
2
- import PropTypes from 'prop-types';
3
-
4
- const RadioButton = ({ id, value, name, checked, onChange, disabled, readOnly }) => (
5
- <>
6
- <input
7
- type="radio"
8
- className="sr-only"
9
- id={id}
10
- value={value}
11
- name={name}
12
- checked={checked}
13
- disabled={disabled || readOnly}
14
- onChange={() => (!checked ? onChange(value) : null)}
15
- />
16
- <span className={classNames('tw-radio-button', { checked, disabled: disabled || readOnly })}>
17
- <span className="tw-radio-check" />
18
- </span>
19
- </>
20
- );
21
-
22
- RadioButton.propTypes = {
23
- id: PropTypes.string,
24
- name: PropTypes.string.isRequired,
25
- checked: PropTypes.bool,
26
- onChange: PropTypes.func,
27
- disabled: PropTypes.bool,
28
- value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
29
- readOnly: PropTypes.bool,
30
- };
31
-
32
- RadioButton.defaultProps = {
33
- checked: false,
34
- onChange: () => {},
35
- disabled: false,
36
- id: null,
37
- value: '',
38
- readOnly: false,
39
- };
40
-
41
- export default RadioButton;
@@ -1,3 +0,0 @@
1
- import InstructionsList from './InstructionsList';
2
-
3
- export default InstructionsList;
@@ -1,3 +0,0 @@
1
- import Radio from './Radio';
2
-
3
- export default Radio;
@@ -1,66 +0,0 @@
1
- import PropTypes from 'prop-types';
2
- import { Component } from 'react';
3
-
4
- import Radio from '../radio';
5
-
6
- class RadioGroup extends Component {
7
- constructor(props) {
8
- super(props);
9
- this.state = {
10
- selectedValue: props.selectedValue,
11
- };
12
- }
13
-
14
- handleOnChange = (selectedValue) => {
15
- const { onChange } = this.props;
16
- this.setState({ selectedValue }, onChange && onChange(selectedValue));
17
- };
18
-
19
- render() {
20
- const { radios, name } = this.props;
21
- const { selectedValue } = this.state;
22
- return radios && radios.length > 0 ? (
23
- <div role="radiogroup">
24
- {radios.map(({ id, avatar, value, label, disabled, secondary, readOnly }, index) => (
25
- <Radio
26
- // eslint-disable-next-line react/no-array-index-key
27
- key={index}
28
- id={id}
29
- value={value}
30
- label={label}
31
- name={name}
32
- disabled={disabled}
33
- checked={selectedValue === value}
34
- secondary={secondary}
35
- readOnly={readOnly}
36
- avatar={avatar}
37
- onChange={(value_) => this.handleOnChange(value_)}
38
- />
39
- ))}
40
- </div>
41
- ) : null;
42
- }
43
- }
44
-
45
- RadioGroup.propTypes = {
46
- radios: PropTypes.arrayOf(
47
- PropTypes.shape({
48
- id: PropTypes.string,
49
- avatar: PropTypes.element,
50
- value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
51
- secondary: PropTypes.string,
52
- label: PropTypes.string.isRequired,
53
- disabled: PropTypes.bool,
54
- readOnly: PropTypes.bool,
55
- }),
56
- ).isRequired,
57
- onChange: PropTypes.func.isRequired,
58
- selectedValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
59
- name: PropTypes.string.isRequired,
60
- };
61
-
62
- RadioGroup.defaultProps = {
63
- selectedValue: null,
64
- };
65
-
66
- export default RadioGroup;
@@ -1 +0,0 @@
1
- export { default } from './RadioGroup';
@@ -1,81 +0,0 @@
1
- import PropTypes from 'prop-types';
2
-
3
- import Option from '../common/Option';
4
- import RadioButton from '../common/RadioButton';
5
-
6
- const RadioOption = ({
7
- 'aria-label': ariaLabel,
8
- media,
9
- title,
10
- content,
11
- id,
12
- name,
13
- checked,
14
- onChange,
15
- complex,
16
- disabled,
17
- value,
18
- showMediaCircle,
19
- showMediaAtAllSizes,
20
- isContainerAligned,
21
- }) => {
22
- const sharedProps = {
23
- 'aria-label': ariaLabel,
24
- media,
25
- title,
26
- content,
27
- name,
28
- complex,
29
- disabled,
30
- showMediaCircle,
31
- showMediaAtAllSizes,
32
- isContainerAligned,
33
- };
34
- return (
35
- <Option
36
- {...sharedProps}
37
- button={
38
- <RadioButton
39
- id={id}
40
- name={name}
41
- checked={checked}
42
- disabled={disabled}
43
- value={value}
44
- onChange={onChange}
45
- />
46
- }
47
- />
48
- );
49
- };
50
-
51
- RadioOption.propTypes = {
52
- 'aria-label': PropTypes.string,
53
- media: PropTypes.node,
54
- id: PropTypes.string.isRequired,
55
- name: PropTypes.string.isRequired,
56
- title: PropTypes.node.isRequired,
57
- content: PropTypes.node,
58
- checked: PropTypes.bool,
59
- onChange: PropTypes.func.isRequired,
60
- complex: PropTypes.bool,
61
- disabled: PropTypes.bool,
62
- value: PropTypes.string,
63
- showMediaCircle: PropTypes.bool,
64
- showMediaAtAllSizes: PropTypes.bool,
65
- isContainerAligned: PropTypes.bool,
66
- };
67
-
68
- RadioOption.defaultProps = {
69
- 'aria-label': undefined,
70
- media: null,
71
- content: null,
72
- checked: false,
73
- complex: false,
74
- disabled: false,
75
- showMediaCircle: true,
76
- showMediaAtAllSizes: false,
77
- isContainerAligned: false,
78
- value: '',
79
- };
80
-
81
- export default RadioOption;
@@ -1 +0,0 @@
1
- export { default } from './RadioOption';
File without changes