@transferwise/components 46.17.2 → 46.17.3

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 (77) hide show
  1. package/build/index.esm.js +16 -15
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +15 -14
  4. package/build/index.js.map +1 -1
  5. package/build/types/accordion/Accordion.d.ts +1 -1
  6. package/build/types/accordion/Accordion.d.ts.map +1 -1
  7. package/build/types/chips/Chips.d.ts +2 -2
  8. package/build/types/chips/Chips.d.ts.map +1 -1
  9. package/build/types/dateLookup/getFocusableTime/getFocusableTime.d.ts +1 -1
  10. package/build/types/dateLookup/getFocusableTime/getFocusableTime.d.ts.map +1 -1
  11. package/build/types/decision/Decision.d.ts +1 -1
  12. package/build/types/decision/Decision.d.ts.map +1 -1
  13. package/build/types/flowNavigation/FlowNavigation.d.ts +1 -1
  14. package/build/types/flowNavigation/FlowNavigation.d.ts.map +1 -1
  15. package/build/types/flowNavigation/animatedLabel/AnimatedLabel.d.ts +1 -1
  16. package/build/types/flowNavigation/animatedLabel/AnimatedLabel.d.ts.map +1 -1
  17. package/build/types/instructionsList/InstructionsList.d.ts +4 -4
  18. package/build/types/instructionsList/InstructionsList.d.ts.map +1 -1
  19. package/build/types/markdown/Markdown.d.ts +2 -2
  20. package/build/types/markdown/Markdown.d.ts.map +1 -1
  21. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts +1 -1
  22. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  23. package/build/types/phoneNumberInput/utils/excludeCountries/excludeCountries.d.ts +1 -1
  24. package/build/types/phoneNumberInput/utils/excludeCountries/excludeCountries.d.ts.map +1 -1
  25. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.d.ts +1 -1
  26. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.d.ts.map +1 -1
  27. package/build/types/phoneNumberInput/utils/longestMatchingPrefix/index.d.ts +1 -1
  28. package/build/types/phoneNumberInput/utils/longestMatchingPrefix/index.d.ts.map +1 -1
  29. package/build/types/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.d.ts +1 -1
  30. package/build/types/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.d.ts.map +1 -1
  31. package/build/types/radioGroup/RadioGroup.d.ts +1 -1
  32. package/build/types/radioGroup/RadioGroup.d.ts.map +1 -1
  33. package/build/types/segmentedControl/SegmentedControl.d.ts +3 -3
  34. package/build/types/segmentedControl/SegmentedControl.d.ts.map +1 -1
  35. package/build/types/slidingPanel/SlidingPanel.d.ts.map +1 -1
  36. package/build/types/stepper/Stepper.d.ts +1 -1
  37. package/build/types/stepper/Stepper.d.ts.map +1 -1
  38. package/build/types/typeahead/Typeahead.d.ts +5 -5
  39. package/build/types/typeahead/Typeahead.d.ts.map +1 -1
  40. package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts +1 -1
  41. package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts.map +1 -1
  42. package/build/types/uploadInput/UploadInput.d.ts +1 -1
  43. package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
  44. package/build/types/uploadInput/uploadButton/UploadButton.d.ts +1 -1
  45. package/build/types/uploadInput/uploadButton/UploadButton.d.ts.map +1 -1
  46. package/build/types/uploadInput/uploadButton/getAllowedFileTypes.d.ts +1 -1
  47. package/build/types/uploadInput/uploadButton/getAllowedFileTypes.d.ts.map +1 -1
  48. package/package.json +1 -1
  49. package/src/accordion/Accordion.tsx +1 -1
  50. package/src/chips/Chips.story.tsx +2 -2
  51. package/src/chips/Chips.tsx +2 -2
  52. package/src/dateLookup/dateTrigger/DateTrigger.js +1 -1
  53. package/src/dateLookup/dateTrigger/DateTrigger.spec.js +11 -3
  54. package/src/dateLookup/getFocusableTime/getFocusableTime.tsx +1 -1
  55. package/src/decision/Decision.tsx +1 -1
  56. package/src/flowNavigation/FlowNavigation.tsx +1 -1
  57. package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +6 -0
  58. package/src/flowNavigation/animatedLabel/AnimatedLabel.tsx +1 -1
  59. package/src/instructionsList/InstructionsList.tsx +4 -4
  60. package/src/markdown/Markdown.tsx +3 -3
  61. package/src/moneyInput/MoneyInput.tsx +3 -3
  62. package/src/phoneNumberInput/PhoneNumberInput.tsx +1 -1
  63. package/src/phoneNumberInput/utils/excludeCountries/excludeCountries.ts +5 -2
  64. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.ts +1 -1
  65. package/src/phoneNumberInput/utils/longestMatchingPrefix/index.ts +1 -1
  66. package/src/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.ts +1 -1
  67. package/src/promoCard/PromoCardGroup.tsx +1 -1
  68. package/src/radioGroup/RadioGroup.tsx +1 -1
  69. package/src/segmentedControl/SegmentedControl.tsx +3 -3
  70. package/src/slidingPanel/SlidingPanel.js +1 -0
  71. package/src/stepper/Stepper.spec.js +16 -0
  72. package/src/stepper/Stepper.tsx +2 -1
  73. package/src/typeahead/Typeahead.tsx +6 -6
  74. package/src/typeahead/typeaheadInput/TypeaheadInput.tsx +1 -1
  75. package/src/uploadInput/UploadInput.tsx +6 -6
  76. package/src/uploadInput/uploadButton/UploadButton.tsx +5 -7
  77. package/src/uploadInput/uploadButton/getAllowedFileTypes.ts +1 -1
@@ -12,13 +12,13 @@ type InstructionNode = {
12
12
  export type InstructionsListProps = CommonProps &
13
13
  (
14
14
  | {
15
- dos?: ReactNode[];
16
- donts?: ReactNode[];
15
+ dos?: readonly ReactNode[];
16
+ donts?: readonly ReactNode[];
17
17
  sort?: 'dosFirst' | 'dontsFirst';
18
18
  }
19
19
  | {
20
- dos?: InstructionNode[];
21
- donts?: InstructionNode[];
20
+ dos?: readonly InstructionNode[];
21
+ donts?: readonly InstructionNode[];
22
22
  sort?: 'dosFirst' | 'dontsFirst';
23
23
  }
24
24
  );
@@ -17,12 +17,12 @@ export type MarkdownProps = {
17
17
  children?: string;
18
18
  } & (
19
19
  | {
20
- allowList?: `${MarkdownNodeType}`[];
20
+ allowList?: readonly `${MarkdownNodeType}`[];
21
21
  blockList?: never;
22
22
  }
23
23
  | {
24
24
  allowList?: never;
25
- blockList?: `${MarkdownNodeType}`[];
25
+ blockList?: readonly `${MarkdownNodeType}`[];
26
26
  }
27
27
  );
28
28
 
@@ -61,7 +61,7 @@ export default function Markdown({
61
61
  return <Element className={className} dangerouslySetInnerHTML={{ __html: createMarkup() }} />;
62
62
  }
63
63
 
64
- function stripNodes({ blockList, parsed }: { blockList: string[]; parsed: MarkdownNode }) {
64
+ function stripNodes({ blockList, parsed }: { blockList: readonly string[]; parsed: MarkdownNode }) {
65
65
  if (!parsed) {
66
66
  return parsed;
67
67
  }
@@ -462,7 +462,7 @@ function filterCurrenciesForQuery(
462
462
  return sortOptionsLabelsToFirst(filteredOptions, query);
463
463
  }
464
464
 
465
- function removeDuplicateValueOptions(options: CurrencyOptionItem[]) {
465
+ function removeDuplicateValueOptions(options: readonly CurrencyOptionItem[]) {
466
466
  const uniqueValues = new Set<string>();
467
467
  return options.filter((option) => {
468
468
  if (!uniqueValues.has(option.value)) {
@@ -489,8 +489,8 @@ function contains(property: string | undefined, query: string) {
489
489
  return property && property.toLowerCase().includes(query.toLowerCase());
490
490
  }
491
491
 
492
- function sortOptionsLabelsToFirst(options: CurrencyOptionItem[], query: string) {
493
- return options.sort((first, second) => {
492
+ function sortOptionsLabelsToFirst(options: readonly CurrencyOptionItem[], query: string) {
493
+ return [...options].sort((first, second) => {
494
494
  const firstContains = contains(first.label, query);
495
495
  const secondContains = contains(second.label, query);
496
496
 
@@ -34,7 +34,7 @@ export interface PhoneNumberInputProps {
34
34
  placeholder?: string;
35
35
  selectProps?: Partial<SelectInputProps<string | null>>;
36
36
  /** List of iso3 codes of countries to remove from the list */
37
- disabledCountries?: string[];
37
+ disabledCountries?: readonly string[];
38
38
  }
39
39
 
40
40
  const defaultSelectProps = {} satisfies PhoneNumberInputProps['selectProps'];
@@ -1,7 +1,7 @@
1
1
  import type { Country } from '../../data/countries';
2
2
 
3
3
  // Reference fro localeCompare : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
4
- const filterCountriesByIso3 = (countries: Country[], iso3Codes: string[]) => {
4
+ const filterCountriesByIso3 = (countries: readonly Country[], iso3Codes: readonly string[]) => {
5
5
  const iso3CodesSet = new Set(iso3Codes);
6
6
  return countries.filter((country) => !iso3CodesSet.has(country.iso3));
7
7
  };
@@ -12,7 +12,10 @@ const filterCountriesByIso3 = (countries: Country[], iso3Codes: string[]) => {
12
12
  * @param countries list of country metadata objects
13
13
  * @param disabledCountries list of iso3 country codes to remove from the list
14
14
  */
15
- export const excludeCountries = (countries: Country[], disabledCountries: string[]) => {
15
+ export const excludeCountries = (
16
+ countries: readonly Country[],
17
+ disabledCountries: readonly string[],
18
+ ) => {
16
19
  return disabledCountries.length > 0
17
20
  ? filterCountriesByIso3(countries, disabledCountries)
18
21
  : countries;
@@ -1,6 +1,6 @@
1
1
  import { Country } from '../../data/countries';
2
2
 
3
- export const groupCountriesByPrefix = (countries: Country[]) => {
3
+ export const groupCountriesByPrefix = (countries: readonly Country[]) => {
4
4
  const countriesByPrefix = new Map<string, Country[]>();
5
5
  countries.forEach((country) => {
6
6
  countriesByPrefix.set(country.phone, [
@@ -1,4 +1,4 @@
1
1
  import { Country } from '../../data/countries';
2
2
 
3
- export const longestMatchingPrefix = (matchingCodes: Country[]) =>
3
+ export const longestMatchingPrefix = (matchingCodes: readonly Country[]) =>
4
4
  matchingCodes.reduce((a, b) => (a.phone.length > b.phone.length ? a : b));
@@ -1,5 +1,5 @@
1
1
  export function sortArrayByProperty<T extends Record<PropertyKey, string>>(
2
- arrayToSort: T[],
2
+ arrayToSort: readonly T[],
3
3
  property: keyof T,
4
4
  ) {
5
5
  return [...arrayToSort].sort((a, b) => a[property].localeCompare(b[property]));
@@ -106,7 +106,7 @@ const PromoCardGroup: FunctionComponent<PromoCardGroupProps> = ({
106
106
  setState(defaultChecked);
107
107
 
108
108
  // Collect an array of types from the children PromoCard components
109
- const types: ('radio' | 'checkbox')[] =
109
+ const types =
110
110
  React.Children.map(children, (child) => {
111
111
  if (React.isValidElement<PromoCardProps>(child) && child.props.type) {
112
112
  return child.props.type;
@@ -5,7 +5,7 @@ import { RadioProps } from '../radio/Radio';
5
5
 
6
6
  export interface RadioGroupProps<T extends string | number = string> {
7
7
  name: string;
8
- radios: Omit<RadioProps<T>, 'name' | 'checked' | 'onChange' | 'className'>[];
8
+ radios: readonly Omit<RadioProps<T>, 'name' | 'checked' | 'onChange' | 'className'>[];
9
9
  selectedValue?: T; // TODO: `NoInfer<T>` from TypeScript 5.4
10
10
  onChange: NonNullable<RadioProps<T>['onChange']>;
11
11
  }
@@ -9,7 +9,7 @@ type SegmentBase = { id: string; label: string; value: string };
9
9
  type Segment = SegmentBase & { controls?: never };
10
10
  type SegmentWithControls = SegmentBase & { controls: string };
11
11
 
12
- export type Segments = Segment[] | SegmentWithControls[];
12
+ export type Segments = readonly Segment[] | readonly SegmentWithControls[];
13
13
 
14
14
  type SegmentedControlPropsBase = {
15
15
  name: string;
@@ -20,12 +20,12 @@ type SegmentedControlPropsBase = {
20
20
 
21
21
  type SegmentedControlViewProps = {
22
22
  mode: 'view';
23
- segments: SegmentWithControls[];
23
+ segments: readonly SegmentWithControls[];
24
24
  };
25
25
 
26
26
  type SegmentedControlInputProps = {
27
27
  mode: 'input';
28
- segments: Segment[];
28
+ segments: readonly Segment[];
29
29
  };
30
30
 
31
31
  export type SegmentedControlProps = SegmentedControlPropsBase &
@@ -25,6 +25,7 @@ const SlidingPanel = forwardRef(
25
25
  return (
26
26
  <CSSTransition
27
27
  {...rest}
28
+ key={`sliding-panel--open-${position}`}
28
29
  nodeRef={localReference}
29
30
  in={open}
30
31
  // Wait for animation to finish before unmount.
@@ -162,6 +162,22 @@ describe('Stepper', () => {
162
162
  expect(step(1).clickable).toBe(true);
163
163
  expect(step(2).clickable).toBe(true);
164
164
  });
165
+
166
+ it('are aria-current=step when active', () => {
167
+ const stepCurrent = (index) =>
168
+ component.find('.tw-stepper__step').at(index).props()['aria-current'];
169
+ steps(4);
170
+ activeStep(1);
171
+ expect(stepCurrent(0)).toBe(false);
172
+ expect(stepCurrent(1)).toBe('step');
173
+ expect(stepCurrent(2)).toBe(false);
174
+ expect(stepCurrent(3)).toBe(false);
175
+ activeStep(2);
176
+ expect(stepCurrent(0)).toBe(false);
177
+ expect(stepCurrent(1)).toBe(false);
178
+ expect(stepCurrent(2)).toBe('step');
179
+ expect(stepCurrent(3)).toBe(false);
180
+ });
165
181
  });
166
182
 
167
183
  describe('hover labels', () => {
@@ -18,7 +18,7 @@ export interface Step {
18
18
  }
19
19
 
20
20
  export interface StepperProps {
21
- steps: Step[];
21
+ steps: readonly Step[];
22
22
  activeStep?: number;
23
23
  className?: string;
24
24
  }
@@ -60,6 +60,7 @@ const Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {
60
60
  clickable && 'tw-stepper__step--clickable',
61
61
  step.hoverLabel && 'tw-stepper__step--has-tooltip',
62
62
  )}
63
+ aria-current={active ? 'step' : false}
63
64
  style={
64
65
  isRTL
65
66
  ? { right: `${index * stepPercentage * 100}%` }
@@ -43,16 +43,16 @@ export interface TypeaheadProps<T> {
43
43
  allowNew?: boolean;
44
44
  autoFillOnBlur?: boolean;
45
45
  autoFocus?: boolean;
46
- chipSeparators?: string[];
46
+ chipSeparators?: readonly string[];
47
47
  clearable?: boolean;
48
48
  footer?: ReactNode;
49
- initialValue?: TypeaheadOption<T>[];
49
+ initialValue?: readonly TypeaheadOption<T>[];
50
50
  inputAutoComplete?: string;
51
51
  maxHeight?: number;
52
52
  minQueryLength?: number;
53
53
  placeholder?: string;
54
54
  multiple?: boolean;
55
- options: TypeaheadOption<T>[];
55
+ options: readonly TypeaheadOption<T>[];
56
56
  searchDelay?: number;
57
57
  showSuggestions?: boolean;
58
58
  showNewEntry?: boolean;
@@ -67,7 +67,7 @@ export interface TypeaheadProps<T> {
67
67
  }
68
68
 
69
69
  type TypeaheadState<T> = {
70
- selected: TypeaheadOption<T>[];
70
+ selected: readonly TypeaheadOption<T>[];
71
71
  keyboardFocusedOptionIndex: number | null;
72
72
  errorState: boolean;
73
73
  query: string;
@@ -311,12 +311,12 @@ export default class Typeahead<T> extends Component<TypeaheadProps<T>, Typeahead
311
311
  );
312
312
  };
313
313
 
314
- updateSelectedValue = (selected: TypeaheadOption<T>[]) => {
314
+ updateSelectedValue = (selected: readonly TypeaheadOption<T>[]) => {
315
315
  const { onChange, validateChip } = this.props;
316
316
 
317
317
  const errorState = selected.some((chip) => !validateChip(chip));
318
318
  this.setState({ selected, errorState }, () => {
319
- onChange(selected);
319
+ onChange([...selected]);
320
320
  });
321
321
  };
322
322
 
@@ -12,7 +12,7 @@ const DEFAULT_INPUT_MIN_WIDTH = 10;
12
12
  export type TypeaheadInputProps<T> = {
13
13
  typeaheadId: string;
14
14
  value: string;
15
- selected: TypeaheadOption<T>[];
15
+ selected: readonly TypeaheadOption<T>[];
16
16
  optionsShown?: boolean;
17
17
  autoComplete: string;
18
18
  onChange: React.ChangeEventHandler<HTMLInputElement>;
@@ -19,7 +19,7 @@ export type UploadInputProps = {
19
19
  /**
20
20
  * List of already existing, failed or in progress files
21
21
  */
22
- files?: UploadedFile[];
22
+ files?: readonly UploadedFile[];
23
23
 
24
24
  /**
25
25
  * The key of the file in the returned FormData object (default: file)
@@ -135,14 +135,14 @@ const UploadInput = ({
135
135
 
136
136
  const PROGRESS_STATUSES = new Set([Status.PENDING, Status.PROCESSING]);
137
137
 
138
- const [uploadedFiles, setUploadedFiles] = useState<UploadedFile[]>(
138
+ const [uploadedFiles, setUploadedFiles] = useState<readonly UploadedFile[]>(
139
139
  multiple || files.length === 0 ? files : [files[0]],
140
140
  );
141
141
 
142
142
  const uploadedFilesListReference = useRef(multiple || files.length === 0 ? files : [files[0]]);
143
143
 
144
144
  function addFileToList(recentUploadedFile: UploadedFile) {
145
- function addToList(listToAddTo: UploadedFile[]) {
145
+ function addToList(listToAddTo: readonly UploadedFile[]) {
146
146
  return [...listToAddTo, recentUploadedFile];
147
147
  }
148
148
 
@@ -151,7 +151,7 @@ const UploadInput = ({
151
151
  }
152
152
 
153
153
  const removeFileFromList = (file: UploadedFile) => {
154
- function filterOutFrom(listToFilterFrom: UploadedFile[]) {
154
+ function filterOutFrom(listToFilterFrom: readonly UploadedFile[]) {
155
155
  return listToFilterFrom.filter(
156
156
  (fileInList) => file !== fileInList && file.id !== fileInList.id,
157
157
  );
@@ -162,7 +162,7 @@ const UploadInput = ({
162
162
  };
163
163
 
164
164
  const modifyFileInList = (file: UploadedFile, updates: Partial<UploadedFile>) => {
165
- const updateListItem = (listToUpdate: UploadedFile[]) =>
165
+ const updateListItem = (listToUpdate: readonly UploadedFile[]) =>
166
166
  listToUpdate.map((fileInList) => {
167
167
  return fileInList === file || fileInList.id === file.id
168
168
  ? { ...file, ...updates }
@@ -295,7 +295,7 @@ const UploadInput = ({
295
295
 
296
296
  useEffect(() => {
297
297
  if (onFilesChange && mounted) {
298
- onFilesChange(uploadedFiles);
298
+ onFilesChange([...uploadedFiles]);
299
299
  }
300
300
  }, [onFilesChange, uploadedFiles]); // eslint-disable-line react-hooks/exhaustive-deps
301
301
 
@@ -12,7 +12,7 @@ import MESSAGES from './UploadButton.messages';
12
12
  import { DEFAULT_SIZE_LIMIT, imageFileTypes } from './defaults';
13
13
  import getAllowedFileTypes from './getAllowedFileTypes';
14
14
 
15
- type AllowedFileTypes = string | string[] | FileType[];
15
+ type AllowedFileTypes = string | readonly string[] | readonly FileType[];
16
16
  export type UploadButtonProps = {
17
17
  /**
18
18
  * Disable the upload button if your app is not yet ready to accept uploads
@@ -144,9 +144,7 @@ const UploadButton = ({
144
144
  return fileTypes;
145
145
  }
146
146
 
147
- return Array.isArray(fileTypes)
148
- ? getAllowedFileTypes(fileTypes).join(', ')
149
- : getAllowedFileTypes([fileTypes]).join(', ');
147
+ return getAllowedFileTypes(Array.isArray(fileTypes) ? fileTypes : [fileTypes]).join(', ');
150
148
  };
151
149
 
152
150
  function getDescription() {
@@ -165,18 +163,18 @@ const UploadButton = ({
165
163
  });
166
164
  }
167
165
 
168
- function getAcceptedTypes() {
166
+ function getAcceptedTypes(): Pick<React.ComponentPropsWithoutRef<'input'>, 'accept'> {
169
167
  const areAllFilesAllowed = getFileTypesDescription() === '*';
170
168
 
171
169
  if (areAllFilesAllowed) {
172
- return null; //file input by default allows all files
170
+ return {}; //file input by default allows all files
173
171
  }
174
172
 
175
173
  if (Array.isArray(fileTypes)) {
176
174
  return { accept: fileTypes.join(',') };
177
175
  }
178
176
 
179
- return { accept: fileTypes };
177
+ return { accept: fileTypes as string };
180
178
  }
181
179
 
182
180
  function renderDescription() {
@@ -1,6 +1,6 @@
1
1
  import { FileType } from '../../common';
2
2
 
3
- const getAllowedFileTypes = (fileTypes: FileType[] | string[]): string[] =>
3
+ const getAllowedFileTypes = (fileTypes: readonly FileType[] | readonly string[]): string[] =>
4
4
  fileTypes.map((fileTypeDefinition: string) =>
5
5
  fileTypeDefinition
6
6
  .split(',')