@transferwise/components 0.0.0-experimental-47ae02a → 0.0.0-experimental-da6dbbf

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 (89) hide show
  1. package/build/index.js +940 -642
  2. package/build/index.js.map +1 -1
  3. package/build/index.mjs +930 -633
  4. package/build/index.mjs.map +1 -1
  5. package/build/main.css +135 -0
  6. package/build/styles/carousel/Carousel.css +135 -0
  7. package/build/styles/main.css +135 -0
  8. package/build/types/accordion/AccordionItem/AccordionItem.d.ts.map +1 -1
  9. package/build/types/carousel/Carousel.d.ts +26 -0
  10. package/build/types/carousel/Carousel.d.ts.map +1 -0
  11. package/build/types/carousel/index.d.ts +3 -0
  12. package/build/types/carousel/index.d.ts.map +1 -0
  13. package/build/types/common/card/Card.d.ts +2 -2
  14. package/build/types/common/card/Card.d.ts.map +1 -1
  15. package/build/types/common/hooks/useMedia.d.ts.map +1 -1
  16. package/build/types/common/panel/Panel.d.ts.map +1 -1
  17. package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
  18. package/build/types/dimmer/Dimmer.d.ts +11 -1
  19. package/build/types/dimmer/Dimmer.d.ts.map +1 -1
  20. package/build/types/drawer/Drawer.d.ts +4 -4
  21. package/build/types/index.d.ts +4 -3
  22. package/build/types/index.d.ts.map +1 -1
  23. package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts +1 -2
  24. package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts.map +1 -1
  25. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  26. package/build/types/modal/Modal.d.ts.map +1 -1
  27. package/build/types/processIndicator/ProcessIndicator.d.ts +19 -36
  28. package/build/types/processIndicator/ProcessIndicator.d.ts.map +1 -1
  29. package/build/types/processIndicator/index.d.ts +2 -2
  30. package/build/types/processIndicator/index.d.ts.map +1 -1
  31. package/build/types/promoCard/PromoCard.d.ts +16 -5
  32. package/build/types/promoCard/PromoCard.d.ts.map +1 -1
  33. package/build/types/select/searchBox/SearchBox.d.ts +1 -1
  34. package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts +1 -2
  35. package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts.map +1 -1
  36. package/build/types/tooltip/Tooltip.d.ts +1 -1
  37. package/build/types/tooltip/Tooltip.d.ts.map +1 -1
  38. package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
  39. package/build/types/withDisplayFormat/WithDisplayFormat.d.ts +14 -14
  40. package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
  41. package/package.json +11 -7
  42. package/src/accordion/AccordionItem/AccordionItem.tsx +4 -2
  43. package/src/avatarWrapper/AvatarWrapper.story.tsx +3 -1
  44. package/src/button/Button.tsx +1 -1
  45. package/src/carousel/Carousel.css +135 -0
  46. package/src/carousel/Carousel.less +133 -0
  47. package/src/carousel/Carousel.spec.tsx +221 -0
  48. package/src/carousel/Carousel.story.tsx +63 -0
  49. package/src/carousel/Carousel.tsx +345 -0
  50. package/src/carousel/index.ts +3 -0
  51. package/src/common/card/Card.tsx +51 -43
  52. package/src/common/hooks/useConditionalListener/useConditionalListener.spec.js +1 -1
  53. package/src/common/hooks/useHasIntersected/useHasIntersected.spec.js +3 -3
  54. package/src/common/hooks/useMedia.spec.ts +1 -1
  55. package/src/common/hooks/useMedia.ts +2 -1
  56. package/src/common/panel/Panel.tsx +92 -90
  57. package/src/common/responsivePanel/ResponsivePanel.tsx +38 -34
  58. package/src/dateLookup/DateLookup.keyboardEvents.spec.js +180 -0
  59. package/src/dateLookup/DateLookup.rtl.spec.tsx +5 -181
  60. package/src/dateLookup/DateLookup.testingLibrary.spec.js +124 -171
  61. package/src/drawer/Drawer.js +3 -3
  62. package/src/field/Field.tsx +3 -3
  63. package/src/index.ts +4 -3
  64. package/src/inputWithDisplayFormat/InputWithDisplayFormat.tsx +1 -2
  65. package/src/inputs/SelectInput.story.tsx +0 -1
  66. package/src/inputs/SelectInput.tsx +2 -10
  67. package/src/main.css +135 -0
  68. package/src/main.less +1 -0
  69. package/src/modal/Modal.tsx +2 -1
  70. package/src/processIndicator/ProcessIndicator.js +117 -0
  71. package/src/processIndicator/ProcessIndicator.spec.js +101 -0
  72. package/src/promoCard/PromoCard.story.tsx +2 -2
  73. package/src/promoCard/PromoCard.tsx +31 -9
  74. package/src/radio/__snapshots__/Radio.rtl.spec.tsx.snap +1 -0
  75. package/src/snackbar/Snackbar.spec.js +1 -4
  76. package/src/tabs/Tabs.spec.js +27 -46
  77. package/src/test-utils/index.js +7 -5
  78. package/src/test-utils/jest.setup.js +3 -9
  79. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.tsx +1 -2
  80. package/src/tooltip/Tooltip.tsx +46 -44
  81. package/src/tooltip/__snapshots__/Tooltip.spec.tsx.snap +2 -2
  82. package/src/upload/Upload.spec.js +13 -34
  83. package/src/uploadInput/UploadInput.spec.tsx +23 -21
  84. package/src/uploadInput/uploadItem/UploadItem.tsx +3 -1
  85. package/src/withDisplayFormat/WithDisplayFormat.spec.js +32 -63
  86. package/src/withDisplayFormat/WithDisplayFormat.tsx +28 -28
  87. package/src/processIndicator/ProcessIndicator.rtl.spec.tsx +0 -45
  88. package/src/processIndicator/ProcessIndicator.tsx +0 -110
  89. /package/src/processIndicator/{index.ts → index.js} +0 -0
@@ -1,9 +1,9 @@
1
1
  import '@testing-library/jest-dom';
2
2
  import user from '@testing-library/user-event';
3
- import { act } from 'react';
4
3
 
5
4
  import { render, screen, mockMatchMedia } from '../test-utils';
6
- import DateLookup from './DateLookup';
5
+
6
+ import DateLookup from '.';
7
7
 
8
8
  mockMatchMedia();
9
9
 
@@ -20,218 +20,171 @@ describe('DateLookup (events)', () => {
20
20
  const min = new Date(2018, 11, 26);
21
21
  const max = new Date(2018, 11, 28);
22
22
 
23
- describe('when not clearable', () => {
24
- /** @type {jest.Mock} */
25
- let handleChange;
26
-
27
- const setup = async () => {
28
- handleChange = jest.fn();
29
-
30
- /** @type {import('@testing-library/react').RenderResult} */
31
- let view;
32
- await act(async () => {
33
- view = render(
34
- <>
35
- {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
36
- <label id="prioritized-label">Prioritized label</label>
37
- <DateLookup
38
- value={date}
39
- min={min}
40
- max={max}
41
- size="lg"
42
- placeholder="Asd.."
43
- label="label"
44
- aria-labelledby="prioritized-label"
45
- disabled={false}
46
- clearable={false}
47
- onChange={handleChange}
48
- onClick={jest.fn()}
49
- />
50
- </>,
51
- );
52
- });
53
- return view;
54
- };
55
-
56
- it('switches to years', async () => {
57
- const view = await setup();
58
- openDateLookup(view);
59
- clickDateButton(view);
60
-
61
- expect(getActiveYearButton(view)).toHaveFocus();
62
-
63
- closeDateLookup(view);
64
- });
65
-
66
- it('has aria-label for 20 years', async () => {
67
- const view = await setup();
68
- openDateLookup(view);
69
- clickDateButton(view);
70
-
71
- expect(getButtonByAriaLabel('next 20 years')).toBeInTheDocument();
72
- expect(getButtonByAriaLabel('previous 20 years')).toBeInTheDocument();
73
-
74
- closeDateLookup(view);
75
- });
76
-
77
- it('switches to months', async () => {
78
- const view = await setup();
79
- openDateLookup(view);
80
- clickDateButton(view);
81
- user.click(getActiveYearButton(view));
23
+ let props;
24
+ let container;
25
+ let rerender;
82
26
 
83
- expect(getActiveMonthButton(view)).toHaveFocus();
27
+ beforeEach(() => {
28
+ props = {
29
+ value: date,
30
+ min,
31
+ max,
32
+ size: 'lg',
33
+ placeholder: 'Asd..',
34
+ label: 'label',
35
+ 'aria-labelledby': 'prioritized-label',
36
+ onChange: jest.fn(),
37
+ onClick: jest.fn(),
38
+ disabled: false,
39
+ clearable: false,
40
+ };
41
+ ({ container } = render(
42
+ <>
43
+ {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
44
+ <label id="prioritized-label">Prioritized label</label>
45
+ <DateLookup {...props} />
46
+ </>,
47
+ ));
48
+ });
84
49
 
85
- closeDateLookup(view);
86
- });
50
+ afterEach(() => {
51
+ closeDateLookup();
52
+ });
87
53
 
88
- it('has aria label for year', async () => {
89
- const view = await setup();
90
- openDateLookup(view);
91
- clickDateButton(view);
92
- user.click(getActiveYearButton(view));
54
+ it('switches to years', () => {
55
+ openDateLookup();
56
+ clickDateButton();
93
57
 
94
- expect(getButtonByAriaLabel('next year')).toBeInTheDocument();
95
- expect(getButtonByAriaLabel('previous year')).toBeInTheDocument();
58
+ expect(getActiveYearButton()).toHaveFocus();
59
+ });
96
60
 
97
- closeDateLookup(view);
98
- });
61
+ it('has aria-label for 20 years', () => {
62
+ openDateLookup();
63
+ clickDateButton();
99
64
 
100
- it('switches to days', async () => {
101
- const view = await setup();
102
- openDateLookup(view);
103
- clickDateButton(view);
104
- user.click(getActiveYearButton(view));
105
- user.click(getActiveMonthButton(view));
65
+ expect(getButtonByAriaLabel('next 20 years')).toBeInTheDocument();
66
+ expect(getButtonByAriaLabel('previous 20 years')).toBeInTheDocument();
67
+ });
106
68
 
107
- expect(getActiveDayButton(view)).toHaveFocus();
69
+ it('switches to months', () => {
70
+ openDateLookup();
71
+ clickDateButton();
72
+ user.click(getActiveYearButton());
108
73
 
109
- closeDateLookup(view);
110
- });
74
+ expect(getActiveMonthButton()).toHaveFocus();
75
+ });
111
76
 
112
- it('has aria label for month', async () => {
113
- const view = await setup();
114
- openDateLookup(view);
115
- clickDateButton(view);
116
- user.click(getActiveYearButton(view));
117
- user.click(getActiveMonthButton(view));
77
+ it('has aria label for year', () => {
78
+ openDateLookup();
79
+ clickDateButton();
80
+ user.click(getActiveYearButton());
118
81
 
119
- expect(getButtonByAriaLabel('next month')).toBeInTheDocument();
120
- expect(getButtonByAriaLabel('previous month')).toBeInTheDocument();
82
+ expect(getButtonByAriaLabel('next year')).toBeInTheDocument();
83
+ expect(getButtonByAriaLabel('previous year')).toBeInTheDocument();
84
+ });
121
85
 
122
- closeDateLookup(view);
123
- });
86
+ it('switches to days', () => {
87
+ openDateLookup();
88
+ clickDateButton();
89
+ user.click(getActiveYearButton());
90
+ user.click(getActiveMonthButton());
124
91
 
125
- it('updates selected date and closes', async () => {
126
- const view = await setup();
127
- openDateLookup(view);
128
- const d = new Date(2018, 11, 28);
129
- const newDay = screen.getByText(d.getDate().toString());
130
- user.click(newDay);
92
+ expect(getActiveDayButton()).toHaveFocus();
93
+ });
131
94
 
132
- expect(handleChange).toHaveBeenCalledWith(d);
133
- expect(getOpenButton(view)).toHaveFocus();
95
+ it('has aria label for month', () => {
96
+ openDateLookup();
97
+ clickDateButton();
98
+ user.click(getActiveYearButton());
99
+ user.click(getActiveMonthButton());
134
100
 
135
- closeDateLookup(view);
136
- });
101
+ expect(getButtonByAriaLabel('next month')).toBeInTheDocument();
102
+ expect(getButtonByAriaLabel('previous month')).toBeInTheDocument();
103
+ });
137
104
 
138
- it('has aria label on selected date', async () => {
139
- const view = await setup();
140
- openDateLookup(view);
141
- const d = new Date(2018, 11, 28);
142
- const newDay = screen.getByText(d.getDate().toString());
143
- user.click(newDay);
144
- openDateLookup(view);
145
- expect(screen.getByRole('button', { name: /selected day/i })).toBeInTheDocument();
105
+ it('updates selected date and closes', () => {
106
+ openDateLookup();
107
+ const d = new Date(2018, 11, 28);
108
+ const newDay = screen.getByText(d.getDate().toString());
109
+ user.click(newDay);
146
110
 
147
- closeDateLookup(view);
148
- });
111
+ expect(props.onChange).toHaveBeenCalledWith(d);
112
+ expect(getOpenButton()).toHaveFocus();
113
+ });
149
114
 
150
- it('supports custom `aria-labelledby` attribute', async () => {
151
- const view = await setup();
152
- expect(screen.getByLabelText('Prioritized label')).toHaveClass('input-group');
115
+ it('has aria label on selected date', () => {
116
+ openDateLookup();
117
+ const d = new Date(2018, 11, 28);
118
+ const newDay = screen.getByText(d.getDate().toString());
119
+ user.click(newDay);
120
+ openDateLookup();
121
+ expect(screen.getByRole('button', { name: /selected day/i })).toBeInTheDocument();
122
+ });
153
123
 
154
- closeDateLookup(view);
155
- });
124
+ it('supports custom `aria-labelledby` attribute', () => {
125
+ expect(screen.getByLabelText('Prioritized label')).toHaveClass('input-group');
156
126
  });
157
127
 
158
128
  describe('when is clearable', () => {
159
- /** @satisfies {import('./DateLookup').DateLookupProps} */
160
- const props = {
161
- value: date,
162
- onChange: jest.fn(),
163
- clearable: true,
164
- };
165
-
166
- const setup = async () => {
167
- /** @type {import('@testing-library/react').RenderResult} */
168
- let view;
169
- await act(async () => {
170
- view = render(<DateLookup {...props} />);
171
- });
172
- return view;
173
- };
129
+ beforeEach(() => {
130
+ props = { value: date, onChange: jest.fn(), clearable: true };
131
+ ({ container, rerender } = render(<DateLookup {...props} />));
132
+ });
174
133
 
175
- it(`doesn't show clear button if disable is true`, async () => {
176
- const view = await setup();
177
- expect(getClearButton(view)).toBeInTheDocument();
134
+ it(`doesn't show clear button if disable is true`, () => {
135
+ expect(getClearButton()).toBeInTheDocument();
178
136
 
179
- view.rerender(<DateLookup {...props} disabled />);
137
+ rerender(<DateLookup {...props} disabled />);
180
138
 
181
- expect(getClearButton(view)).not.toBeInTheDocument();
139
+ expect(getClearButton()).not.toBeInTheDocument();
182
140
  });
183
141
 
184
- it('when user clicks on clear the focus returns to btn', async () => {
185
- const view = await setup();
186
- clickClearButton(view);
187
- expect(getOpenButton(view)).toHaveFocus();
142
+ it('when user clicks on clear the focus returns to btn', () => {
143
+ clickClearButton();
144
+ expect(getOpenButton()).toHaveFocus();
188
145
  });
189
146
 
190
- it('onChange gets called with null when reset button is clicked', async () => {
191
- const view = await setup();
192
- clickClearButton(view);
147
+ it('onChange gets called with null when reset button is clicked', () => {
148
+ clickClearButton();
193
149
  expect(props.onChange).toHaveBeenCalledWith(null);
194
150
  });
195
151
  });
196
152
 
197
- const openDateLookup = (/** @type {import('@testing-library/react').RenderResult} */ view) =>
198
- user.click(getOpenButton(view));
153
+ const openDateLookup = () => {
154
+ user.click(getOpenButton());
155
+ };
199
156
 
200
- const clickDateButton = (/** @type {import('@testing-library/react').RenderResult} */ view) =>
201
- user.click(getDateButton(view));
157
+ const clickDateButton = () => {
158
+ user.click(getDateButton());
159
+ };
202
160
 
203
161
  // Close dateLookup and removes events attached to documents.
204
- const closeDateLookup = (/** @type {import('@testing-library/react').RenderResult} */ view) =>
205
- user.click(view.container);
162
+ const closeDateLookup = () => {
163
+ user.click(container);
164
+ };
206
165
 
207
- const clickClearButton = (/** @type {import('@testing-library/react').RenderResult} */ view) =>
208
- user.click(getClearButton(view));
166
+ const clickClearButton = () => {
167
+ user.click(getClearButton());
168
+ };
209
169
 
210
- const getActiveYearButton = (
211
- /** @type {import('@testing-library/react').RenderResult} */ view,
212
- ) => {
213
- return view.container.querySelector('button.tw-date-lookup-year-option.active');
170
+ const getActiveYearButton = () => {
171
+ return container.querySelector('button.tw-date-lookup-year-option.active');
214
172
  };
215
173
 
216
- const getActiveMonthButton = (
217
- /** @type {import('@testing-library/react').RenderResult} */ view,
218
- ) => {
219
- return view.container.querySelector('button.tw-date-lookup-month-option.active');
174
+ const getActiveMonthButton = () => {
175
+ return container.querySelector('button.tw-date-lookup-month-option.active');
220
176
  };
221
177
 
222
- const getActiveDayButton = (
223
- /** @type {import('@testing-library/react').RenderResult} */ view,
224
- ) => {
225
- return view.container.querySelector('button.tw-date-lookup-day-option.active');
178
+ const getActiveDayButton = () => {
179
+ return container.querySelector('button.tw-date-lookup-day-option.active');
226
180
  };
227
181
 
228
- const getButtonByAriaLabel = (/** @type {string} */ ariaLabel) => {
182
+ const getButtonByAriaLabel = (ariaLabel) => {
229
183
  return screen.getByRole('button', { name: ariaLabel });
230
184
  };
231
- const getClearButton = (/** @type {import('@testing-library/react').RenderResult} */ view) =>
232
- view.container.querySelector('.clear-btn');
233
- const getOpenButton = (/** @type {import('@testing-library/react').RenderResult} */ view) =>
234
- view.container.querySelector('button.np-date-trigger');
235
- const getDateButton = (/** @type {import('@testing-library/react').RenderResult} */ view) =>
236
- view.container.querySelector('button.tw-date-lookup-header-current');
185
+ const getClearButton = () => container.querySelector('.clear-btn');
186
+ const getOpenButton = () => container.querySelector('button.np-date-trigger');
187
+ const getDateButton = () => container.querySelector('button.tw-date-lookup-header-current');
188
+ const getBottomSheet = () => container.querySelector('.np-bottom-sheet');
189
+ const getPanel = () => container.querySelector('.np-panel');
237
190
  });
@@ -1,6 +1,6 @@
1
+ import { useId } from '@radix-ui/react-id';
1
2
  import classNames from 'classnames';
2
3
  import PropTypes from 'prop-types';
3
- import { useId } from 'react';
4
4
 
5
5
  import { Position, Typography } from '../common';
6
6
  import { CloseButton } from '../common/closeButton';
@@ -56,12 +56,12 @@ Drawer.propTypes = {
56
56
  footerContent: PropTypes.node,
57
57
  /** The content to appear in the drawer header. */
58
58
  headerTitle: PropTypes.node,
59
+ /** The action to perform on close click. */
60
+ onClose: PropTypes.func,
59
61
  /** The status of Drawer either open or not. */
60
62
  open: PropTypes.bool,
61
63
  /** The placement of Drawer on the screen either left or right. On mobile it will default to bottom. */
62
64
  position: PropTypes.oneOf(['left', 'right', 'bottom']),
63
- /** The action to perform on close click. */
64
- onClose: PropTypes.func,
65
65
  };
66
66
 
67
67
  Drawer.defaultProps = {
@@ -1,5 +1,5 @@
1
+ import { useId } from '@radix-ui/react-id';
1
2
  import classNames from 'classnames';
2
- import { useId } from 'react';
3
3
 
4
4
  import { Sentiment } from '../common';
5
5
  import InlineAlert from '../inlineAlert/InlineAlert';
@@ -27,10 +27,10 @@ export const Field = ({ id, label, hint, error, className, children }: FieldProp
27
27
 
28
28
  const labelId = useId();
29
29
 
30
- const fallbackInputId = useId();
30
+ const fallbackInputId = useId(); // TODO: Use `React.useId()` when react>=18
31
31
  const inputId = id !== null ? id ?? fallbackInputId : undefined;
32
32
 
33
- const descriptionId = useId();
33
+ const descriptionId = useId(); // TODO: Use `React.useId()` when react>=18
34
34
 
35
35
  return (
36
36
  <FieldLabelIdContextProvider value={labelId}>
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ export type { ActionOptionProps } from './actionOption';
6
6
  export type { AlertAction, AlertProps, AlertType } from './alert';
7
7
  export type { AvatarProps } from './avatar';
8
8
  export type { BadgeProps } from './badge';
9
+ export type { CarouselProps } from './carousel';
9
10
  export type { CircularButtonProps } from './circularButton';
10
11
  export type {
11
12
  BodyTypes,
@@ -52,7 +53,6 @@ export type {
52
53
  export type { NavigationOptionListProps } from './navigationOptionsList';
53
54
  export type { PhoneNumberInputProps } from './phoneNumberInput/PhoneNumberInput';
54
55
  export type { PopoverProps } from './popover';
55
- export type { ProcessIndicatorProps } from './processIndicator';
56
56
  export type { ProgressProps } from './progress';
57
57
  export type { ProgressBarProps } from './progressBar';
58
58
  export type { DirectionProviderProps, LanguageProviderProps, ProviderProps } from './provider';
@@ -85,6 +85,7 @@ export { default as AvatarWrapper } from './avatarWrapper';
85
85
  export { default as Badge } from './badge';
86
86
  export { default as Body } from './body';
87
87
  export { default as Button } from './button';
88
+ export { default as Carousel } from './carousel';
88
89
  export { default as Card } from './card';
89
90
  export { default as Checkbox } from './checkbox';
90
91
  export { default as CheckboxButton } from './checkboxButton';
@@ -105,8 +106,8 @@ export { default as Display } from './display';
105
106
  export { default as Drawer } from './drawer';
106
107
  export { default as DropFade } from './dropFade';
107
108
  export { default as Emphasis } from './emphasis';
108
- export { Field } from './field/Field';
109
109
  export { default as FlowNavigation } from './flowNavigation/FlowNavigation';
110
+ export { Field } from './field/Field';
110
111
  export { default as Header } from './header';
111
112
  export { default as Image } from './image';
112
113
  export { default as Info } from './info';
@@ -140,7 +141,7 @@ export { default as Popover } from './popover';
140
141
  export { default as ProcessIndicator } from './processIndicator';
141
142
  export { default as Progress } from './progress';
142
143
  export { default as ProgressBar } from './progressBar';
143
- export { default as PromoCard, PromoCardGroup } from './promoCard';
144
+ export { PromoCardGroup, default as PromoCard } from './promoCard';
144
145
  export { DirectionProvider, LanguageProvider, default as Provider } from './provider';
145
146
  export { default as Radio } from './radio';
146
147
  export { default as RadioGroup } from './radioGroup';
@@ -1,8 +1,7 @@
1
1
  import { Input, type InputProps } from '../inputs/Input';
2
2
  import WithDisplayFormat, { type WithDisplayFormatProps } from '../withDisplayFormat';
3
3
 
4
- export interface InputWithDisplayFormatProps
5
- extends Omit<WithDisplayFormatProps<InputProps>, 'render'> {}
4
+ export interface InputWithDisplayFormatProps extends Omit<WithDisplayFormatProps, 'render'> {}
6
5
 
7
6
  const InputWithDisplayFormat = (props: InputWithDisplayFormatProps) => (
8
7
  <WithDisplayFormat<InputProps> {...props} render={(renderProps) => <Input {...renderProps} />} />
@@ -197,7 +197,6 @@ export const Currencies: Story<Currency> = {
197
197
 
198
198
  const input = screen.getByRole('searchbox');
199
199
 
200
- await userEvent.click(input);
201
200
  await userEvent.type(input, 'huf');
202
201
  await expect(
203
202
  within(screen.getByRole('listbox')).queryByRole('option'),
@@ -1,17 +1,9 @@
1
1
  import { Listbox as ListboxBase } from '@headlessui/react';
2
+ import { useId } from '@radix-ui/react-id';
2
3
  import { Check, ChevronDown, Cross, CrossCircle } from '@transferwise/icons';
3
4
  import classNames from 'classnames';
4
5
  import mergeProps from 'merge-props';
5
- import {
6
- createContext,
7
- forwardRef,
8
- useContext,
9
- useEffect,
10
- useId,
11
- useMemo,
12
- useRef,
13
- useState,
14
- } from 'react';
6
+ import { createContext, forwardRef, useContext, useEffect, useMemo, useRef, useState } from 'react';
15
7
  import { useIntl } from 'react-intl';
16
8
 
17
9
  import { useEffectEvent } from '../common/hooks/useEffectEvent';
package/src/main.css CHANGED
@@ -643,6 +643,141 @@ div.critical-comms .critical-comms-body {
643
643
  border-radius: 16px 16px 0 0;
644
644
  border-radius: var(--radius-medium) var(--radius-medium) 0 0;
645
645
  }
646
+ .carousel-wrapper {
647
+ overflow: hidden;
648
+ }
649
+ .carousel {
650
+ display: flex;
651
+ align-items: center;
652
+ overflow-x: scroll;
653
+ overflow-y: hidden;
654
+ scroll-snap-type: x mandatory;
655
+ scroll-behavior: smooth;
656
+ gap: 16px;
657
+ gap: var(--size-16);
658
+ padding: 8px;
659
+ padding: var(--size-8);
660
+ margin: 8px;
661
+ margin: var(--size-8);
662
+ }
663
+ @media (max-width: 767px) {
664
+ .carousel {
665
+ gap: 8px;
666
+ gap: var(--size-8);
667
+ }
668
+ }
669
+ .carousel__header {
670
+ display: flex;
671
+ align-items: center;
672
+ overflow: hidden;
673
+ min-height: 32px;
674
+ min-height: var(--size-32);
675
+ padding-bottom: 16px;
676
+ padding-bottom: var(--size-16);
677
+ }
678
+ .carousel__card,
679
+ .carousel__card:hover,
680
+ .carousel__card:focus,
681
+ .carousel__card:focus-within {
682
+ -webkit-text-decoration: none;
683
+ text-decoration: none;
684
+ transition: none !important;
685
+ box-shadow: none !important;
686
+ }
687
+ .carousel__card {
688
+ display: block;
689
+ position: relative;
690
+ text-align: left;
691
+ border: none;
692
+ overflow: hidden;
693
+ background: rgba(134,167,189,0.10196);
694
+ background: var(--color-background-neutral);
695
+ border-radius: 32px;
696
+ border-radius: var(--size-32);
697
+ scroll-snap-align: center;
698
+ -webkit-scroll-snap-align: center;
699
+ transition: all 0.4s !important;
700
+ }
701
+ @media (min-width: 1200px) {
702
+ .carousel__card {
703
+ min-width: 280px;
704
+ width: 280px;
705
+ height: 280px;
706
+ }
707
+ }
708
+ @media (max-width: 1199px) {
709
+ .carousel__card {
710
+ min-width: 242px;
711
+ width: 242px;
712
+ height: 242px;
713
+ }
714
+ }
715
+ @media (max-width: 767px) {
716
+ .carousel__card {
717
+ min-width: 336px;
718
+ width: 336px;
719
+ height: 336px;
720
+ scroll-snap-stop: always;
721
+ }
722
+ }
723
+ .carousel__card:focus,
724
+ .carousel__card:has(:focus-visible) {
725
+ outline: var(--ring-outline-color) solid var(--ring-outline-width) !important;
726
+ outline-offset: var(--ring-outline-offset) !important;
727
+ }
728
+ .carousel__card:hover {
729
+ background-color: var(--color-background-neutral-hover);
730
+ }
731
+ .carousel__card:focus {
732
+ background-color: var(--color-background-neutral-hover);
733
+ }
734
+ .carousel__card-content {
735
+ height: 100%;
736
+ font-weight: normal;
737
+ padding: 24px;
738
+ padding: var(--size-24);
739
+ }
740
+ .carousel__scroll-button {
741
+ width: 32px;
742
+ width: var(--size-32);
743
+ height: 32px;
744
+ height: var(--size-32);
745
+ align-items: center;
746
+ justify-content: center;
747
+ }
748
+ .carousel__indicators {
749
+ display: flex;
750
+ justify-content: center;
751
+ padding-top: 8px;
752
+ padding-top: var(--size-8);
753
+ gap: 8px;
754
+ gap: var(--size-8);
755
+ }
756
+ .carousel__indicator {
757
+ width: 12px;
758
+ width: var(--size-12);
759
+ height: 12px;
760
+ height: var(--size-12);
761
+ border-radius: 8px;
762
+ border-radius: var(--size-8);
763
+ background: #c9cbce;
764
+ background: var(--color-interactive-secondary);
765
+ border: none;
766
+ -webkit-appearance: none;
767
+ -moz-appearance: none;
768
+ appearance: none;
769
+ transition: all 0.1s;
770
+ }
771
+ .carousel__indicator:hover {
772
+ width: 16px;
773
+ width: var(--size-16);
774
+ }
775
+ .carousel__indicator--selected,
776
+ .carousel__indicator--selected:hover {
777
+ background: var(--color-interactive-primary);
778
+ width: 24px;
779
+ width: var(--size-24);
780
+ }
646
781
  .np-checkbox-button input[type="checkbox"] {
647
782
  position: absolute;
648
783
  width: 24px;
package/src/main.less CHANGED
@@ -5,6 +5,7 @@
5
5
  @import "./badge/Badge.less";
6
6
  @import "./button/Button.less";
7
7
  @import "./card/Card.less";
8
+ @import "./carousel/Carousel.less";
8
9
  @import "./checkboxButton/CheckboxButton.less";
9
10
  @import "./chips/Chip.less";
10
11
  @import "./circularButton/CircularButton.less";
@@ -1,5 +1,6 @@
1
+ import { useId } from '@radix-ui/react-id';
1
2
  import classNames from 'classnames';
2
- import { ReactNode, useId, useRef } from 'react';
3
+ import { ReactNode, useRef } from 'react';
3
4
  import { CSSTransition } from 'react-transition-group';
4
5
 
5
6
  import {