@transferwise/components 45.25.1 → 45.25.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/select/Select.js"],"names":[],"mappings":"AA8EA;;;;;;;;;;;;;;;;;;;;;;gCAkeC"}
1
+ {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/select/Select.js"],"names":[],"mappings":"AA8EA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;gCAkeC"}
@@ -1,2 +1,3 @@
1
1
  export declare function mockMatchMedia(): void;
2
+ export declare function mockResizeObserver(): void;
2
3
  //# sourceMappingURL=window-mock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"window-mock.d.ts","sourceRoot":"","sources":["../../../src/test-utils/window-mock.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,SAkB7B"}
1
+ {"version":3,"file":"window-mock.d.ts","sourceRoot":"","sources":["../../../src/test-utils/window-mock.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,SAkB7B;AAED,wBAAgB,kBAAkB,SASjC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "45.25.1",
3
+ "version": "45.25.2",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import { useState } from 'react';
4
4
  import { useIntl } from 'react-intl';
5
5
 
6
- import { Select, Input } from '..';
6
+ import { Input, SelectInput, SelectInputOptionContent } from '..';
7
7
  import { Size, DateMode, MonthFormat } from '../common';
8
8
  import { getMonthNames, isDateValid, isMonthAndYearFormat } from '../common/dateUtils';
9
9
 
@@ -87,19 +87,19 @@ const DateInput = ({
87
87
  };
88
88
 
89
89
  const getSelectElement = () => {
90
- const months = getMonthNames(locale, monthFormat);
90
+ const monthOptions = getMonthsOptions();
91
91
 
92
92
  return (
93
- <label>
93
+ <label className="d-flex flex-column">
94
94
  <span className="sr-only">{monthLabel}</span>
95
- <Select
96
- id={id ? `${id}-select` : undefined}
95
+ <SelectInput
97
96
  name="month"
98
97
  disabled={disabled}
99
98
  placeholder={placeholders.month}
100
- options={getMonthsOptions()}
99
+ items={monthOptions}
101
100
  size={size}
102
- selected={month === null ? null : { value: month, label: months[month] }}
101
+ value={monthOptions.find((item) => item.value.value === month)?.value}
102
+ renderValue={({ label }) => <SelectInputOptionContent title={label} />}
103
103
  onChange={(selectedValue) => handleMonthChange(selectedValue)}
104
104
  {...selectProps}
105
105
  />
@@ -112,7 +112,7 @@ const DateInput = ({
112
112
  const months = getMonthNames(locale, monthFormat);
113
113
 
114
114
  months.forEach((label, index) => {
115
- options.push({ value: index, label });
115
+ options.push({ type: 'option', value: { label, value: index } });
116
116
  });
117
117
  return options;
118
118
  };
@@ -2,7 +2,7 @@ import { shallow, mount } from 'enzyme';
2
2
  import { useIntl } from 'react-intl';
3
3
 
4
4
  import { DateInput, Input } from '..';
5
- import { fakeEvent } from '../common/fakeEvents';
5
+ import { mockMatchMedia, mockResizeObserver } from '../test-utils';
6
6
 
7
7
  const MONTHS_FR = [
8
8
  'janvier',
@@ -41,10 +41,10 @@ const LOCALES = {
41
41
 
42
42
  const DEFAULT_LOCALE = 'en-GB';
43
43
 
44
- const FEBRUARY_OPTION = { value: 1, label: MONTHS_EN[1] };
44
+ const FEBRUARY_OPTION = { value: MONTHS_EN[1] };
45
45
 
46
46
  const DAY_SELECTOR = 'ForwardRef(Input)[name="day"]';
47
- const MONTH_SELECTOR = 'Select';
47
+ const MONTH_SELECTOR = 'SelectInput';
48
48
  const YEAR_SELECTOR = 'ForwardRef(Input)[name="year"]';
49
49
 
50
50
  jest.mock('./DateInput.messages', () => ({
@@ -78,6 +78,8 @@ describe('Date Input Component', () => {
78
78
  const props = { onChange: jest.fn() };
79
79
 
80
80
  beforeEach(() => {
81
+ mockMatchMedia();
82
+ mockResizeObserver();
81
83
  useIntl.mockReturnValue({
82
84
  locale: DEFAULT_LOCALE,
83
85
  formatMessage: (message) => message.defaultMessage,
@@ -99,7 +101,7 @@ describe('Date Input Component', () => {
99
101
  });
100
102
 
101
103
  it('sets month field to 0', () => {
102
- expect(selectMonth.props().selected).toBeNull();
104
+ expect(selectMonth.props().value).toBeUndefined();
103
105
  });
104
106
 
105
107
  it('sets year field to empty', () => {
@@ -131,7 +133,7 @@ describe('Date Input Component', () => {
131
133
  inputYear = component.find(YEAR_SELECTOR);
132
134
 
133
135
  expect(inputDay.prop('value')).toBe(1);
134
- expect(selectMonth.prop('selected')).toStrictEqual(FEBRUARY_OPTION);
136
+ expect(selectMonth.prop('value').label).toBe(FEBRUARY_OPTION.value);
135
137
  expect(inputYear.prop('value')).toBe(1971);
136
138
  });
137
139
  });
@@ -145,7 +147,7 @@ describe('Date Input Component', () => {
145
147
  inputYear = component.find(YEAR_SELECTOR);
146
148
 
147
149
  expect(inputDay.prop('value')).toBe(22);
148
- expect(selectMonth.prop('selected')).toStrictEqual({ label: MONTHS_EN[7], value: 7 });
150
+ expect(selectMonth.prop('value').label).toBe(MONTHS_EN[7]);
149
151
  expect(inputYear.prop('value')).toBe(1990);
150
152
  });
151
153
  });
@@ -159,7 +161,7 @@ describe('Date Input Component', () => {
159
161
  inputYear = component.find(YEAR_SELECTOR);
160
162
 
161
163
  expect(inputDay.prop('value')).toBe('');
162
- expect(selectMonth.prop('selected')).toStrictEqual({ label: MONTHS_EN[7], value: 7 });
164
+ expect(selectMonth.prop('value').label).toBe(MONTHS_EN[7]);
163
165
  expect(inputYear.prop('value')).toBe(1990);
164
166
  });
165
167
  });
@@ -173,7 +175,7 @@ describe('Date Input Component', () => {
173
175
  inputYear = component.find(YEAR_SELECTOR);
174
176
 
175
177
  expect(inputDay.prop('value')).toBe(28);
176
- expect(selectMonth.prop('selected')).toStrictEqual(FEBRUARY_OPTION);
178
+ expect(selectMonth.prop('value').label).toBe(FEBRUARY_OPTION.value);
177
179
  expect(inputYear.prop('value')).toBe(1990);
178
180
  });
179
181
  });
@@ -216,7 +218,7 @@ describe('Date Input Component', () => {
216
218
  component = shallow(<DateInput {...props} />);
217
219
  selectMonth = component.find(MONTH_SELECTOR);
218
220
 
219
- expect(selectMonth.props().options[0].label).toStrictEqual(MONTHS_FR[0]);
221
+ expect(selectMonth.props().items[0].value.label).toStrictEqual(MONTHS_FR[0]);
220
222
  });
221
223
 
222
224
  it('shows day before month if locale not US', () => {
@@ -240,26 +242,6 @@ describe('Date Input Component', () => {
240
242
  });
241
243
  });
242
244
 
243
- describe('when id is provided', () => {
244
- it('renders Select component with id', () => {
245
- component = mount(<DateInput id="mock-id" {...props} />);
246
-
247
- const select = component.find('Select');
248
-
249
- expect(select.prop('id')).toBe('mock-id-select');
250
- });
251
- });
252
-
253
- describe('when id is not provided', () => {
254
- it('renders Select component with no id', () => {
255
- component = mount(<DateInput {...props} />);
256
-
257
- const select = component.find('Select');
258
-
259
- expect(select.prop('id')).toBeUndefined();
260
- });
261
- });
262
-
263
245
  describe('when initialised', () => {
264
246
  describe('without an initial value', () => {
265
247
  it(`doesn't call the onChange callback`, () => {
@@ -334,19 +316,6 @@ describe('Date Input Component', () => {
334
316
 
335
317
  describe('when user interacts', () => {
336
318
  describe('with an empty date input', () => {
337
- it('calls onChange with null if day is not entered', () => {
338
- component = mount(<DateInput {...props} />);
339
-
340
- // Select February
341
- simulateSelectChange(2);
342
-
343
- inputYear = component.find(YEAR_SELECTOR);
344
-
345
- inputYear.simulate('change', { target: { value: '1990' } });
346
-
347
- expect(props.onChange).toHaveBeenLastCalledWith(null);
348
- });
349
-
350
319
  it('calls onChange with null if month is not selected', () => {
351
320
  component = mount(<DateInput {...props} />);
352
321
 
@@ -360,36 +329,6 @@ describe('Date Input Component', () => {
360
329
 
361
330
  expect(props.onChange).toHaveBeenLastCalledWith(null);
362
331
  });
363
-
364
- it('calls onChange with null if year is not entered', () => {
365
- component = mount(<DateInput {...props} />);
366
-
367
- inputDay = component.find(DAY_SELECTOR);
368
-
369
- inputDay.simulate('change', { target: { value: '12' } });
370
-
371
- // Select February
372
- simulateSelectChange(2);
373
-
374
- expect(props.onChange).toHaveBeenLastCalledWith(null);
375
- });
376
-
377
- it('returns a valid date if all three fields are entered', () => {
378
- component = mount(<DateInput {...props} />);
379
-
380
- inputDay = component.find(DAY_SELECTOR);
381
-
382
- inputDay.simulate('change', { target: { value: '12' } });
383
-
384
- // Select February
385
- simulateSelectChange(2);
386
-
387
- inputYear = component.find(YEAR_SELECTOR);
388
-
389
- inputYear.simulate('change', { target: { value: '1990' } });
390
-
391
- expect(props.onChange).toHaveBeenLastCalledWith('1990-02-12');
392
- });
393
332
  });
394
333
 
395
334
  describe('with day input', () => {
@@ -434,26 +373,6 @@ describe('Date Input Component', () => {
434
373
  expect(props.onChange).toHaveBeenCalledWith('1990-01-01');
435
374
  });
436
375
  });
437
-
438
- describe('with month select', () => {
439
- it('returns correct value for correct input', () => {
440
- component = mount(<DateInput {...props} value="2001-01-01" />);
441
-
442
- // Selects March
443
- simulateSelectChange(3);
444
-
445
- expect(props.onChange).toHaveBeenCalledWith('2001-03-01');
446
- });
447
-
448
- it('returns null when de-selecting month', () => {
449
- component = mount(<DateInput {...props} value="2001-01-01" />);
450
-
451
- // De-selects Month
452
- simulateSelectChange(0);
453
-
454
- expect(props.onChange).toHaveBeenLastCalledWith(null);
455
- });
456
- });
457
376
  });
458
377
 
459
378
  describe('with day input and year input', () => {
@@ -515,38 +434,6 @@ describe('Date Input Component', () => {
515
434
  expect(component.find(DAY_SELECTOR).prop('value')).toBe(28);
516
435
  });
517
436
 
518
- it('corrects days too high in February', () => {
519
- component = mount(<DateInput {...props} />);
520
-
521
- inputDay = component.find(DAY_SELECTOR);
522
- inputYear = component.find(YEAR_SELECTOR);
523
-
524
- inputDay.simulate('change', { target: { value: 29 } });
525
- // Selects February
526
- simulateSelectChange(2);
527
- inputYear.simulate('change', { target: { value: 2001 } });
528
-
529
- expect(component.find(DAY_SELECTOR).prop('value')).toBe(28);
530
- });
531
-
532
- it("doesn't correct days in leap years February", () => {
533
- component = mount(<DateInput {...props} value="2000-03-29" />);
534
-
535
- // Selects February
536
- simulateSelectChange(2);
537
-
538
- expect(component.find(DAY_SELECTOR).prop('value')).toBe(29);
539
- });
540
-
541
- it('corrects days too high for selected months', () => {
542
- component = mount(<DateInput {...props} value="2001-01-31" />);
543
-
544
- // Selects April
545
- simulateSelectChange(4);
546
-
547
- expect(component.find(DAY_SELECTOR).prop('value')).toBe(30);
548
- });
549
-
550
437
  it('lowers days if value entered too high', () => {
551
438
  const comp = shallow(<DateInput {...props} />);
552
439
 
@@ -582,12 +469,6 @@ describe('Date Input Component', () => {
582
469
  expect(component.exists(MONTH_SELECTOR)).toBe(true);
583
470
  expect(component.exists(DAY_SELECTOR)).toBe(false);
584
471
  });
585
-
586
- it('should produce MM-YYYY date string', () => {
587
- // Selects March
588
- simulateSelectChange(3);
589
- expect(props.onChange).toHaveBeenCalledWith('2001-03');
590
- });
591
472
  });
592
473
 
593
474
  describe('when selectProps is provided', () => {
@@ -605,16 +486,11 @@ describe('Date Input Component', () => {
605
486
  });
606
487
 
607
488
  it('renders Select component with expected props', () => {
608
- const select = component.find('Select');
489
+ const select = component.find(MONTH_SELECTOR);
609
490
 
610
491
  expect(select.prop('buttonProps')).toStrictEqual({
611
492
  'aria-label': 'mock-button-label',
612
493
  });
613
494
  });
614
495
  });
615
-
616
- const simulateSelectChange = (n) => {
617
- component.find('button.np-dropdown-toggle').simulate('click', fakeEvent());
618
- component.find('li').at(n).simulate('click', fakeEvent());
619
- };
620
496
  });
@@ -1,7 +1,7 @@
1
1
  import { Meta, StoryObj } from '@storybook/react';
2
2
 
3
3
  import { DateInput, Info, InlineAlert, Title, Typography } from '..';
4
- import { lorem10, storyConfig } from '../test-utils';
4
+ import { lorem10, storyConfig, userEvent, within } from '../test-utils';
5
5
 
6
6
  export default {
7
7
  component: DateInput,
@@ -25,6 +25,11 @@ type Story = StoryObj<typeof DateInput>;
25
25
 
26
26
  export const Basic: Story = {};
27
27
 
28
+ Basic.play = ({ canvasElement }) => {
29
+ const canvas = within(canvasElement);
30
+ userEvent.click(canvas.getByRole('button'));
31
+ };
32
+
28
33
  export const WithLabel: Story = {
29
34
  render: (args) => {
30
35
  const id1 = 'date-input-group-label-1';
@@ -1,36 +1,12 @@
1
1
  import { act, screen, within } from '@testing-library/react';
2
2
  import userEvent, { specialChars } from '@testing-library/user-event';
3
3
 
4
- import { render } from '../test-utils';
4
+ import { render, mockMatchMedia, mockResizeObserver } from '../test-utils';
5
5
 
6
6
  import { SelectInput } from './SelectInput';
7
7
 
8
- Object.defineProperty(window, 'matchMedia', {
9
- writable: true,
10
- value: jest.fn((query: string) => {
11
- const matches = /^\(min-width: ([0-9]+)px\)$/.exec(query);
12
- const minWidth = matches != null ? Number(matches[1]) : undefined;
13
- return {
14
- matches: minWidth != null ? window.innerWidth >= minWidth : false,
15
- media: query,
16
- onchange: null,
17
- addListener: jest.fn(), // deprecated
18
- removeListener: jest.fn(), // deprecated
19
- addEventListener: jest.fn(),
20
- removeEventListener: jest.fn(),
21
- dispatchEvent: jest.fn(),
22
- };
23
- }),
24
- });
25
-
26
- Object.defineProperty(window, 'ResizeObserver', {
27
- writable: true,
28
- value: jest.fn(() => ({
29
- observe: jest.fn(),
30
- unobserve: jest.fn(),
31
- disconnect: jest.fn(),
32
- })),
33
- });
8
+ mockMatchMedia();
9
+ mockResizeObserver();
34
10
 
35
11
  describe('SelectInput', () => {
36
12
  it('renders placeholder', () => {
@@ -1,28 +1,14 @@
1
1
  import { shallow, mount } from 'enzyme';
2
2
  import { useIntl } from 'react-intl';
3
3
 
4
+ import { mockMatchMedia, mockResizeObserver } from '../test-utils';
5
+
4
6
  import PhoneNumberInput from '.';
5
7
 
6
8
  jest.mock('react-intl');
7
9
 
8
- Object.defineProperty(window, 'matchMedia', {
9
- writable: true,
10
- value: jest.fn().mockImplementation((query) => ({
11
- matches: false,
12
- media: query,
13
- onchange: null,
14
- addListener: jest.fn(), // Deprecated
15
- removeListener: jest.fn(), // Deprecated
16
- addEventListener: jest.fn(),
17
- removeEventListener: jest.fn(),
18
- dispatchEvent: jest.fn(),
19
- })),
20
- });
21
-
22
- class ResizeObserver {
23
- observe() {}
24
- unobserve() {}
25
- }
10
+ mockMatchMedia();
11
+ mockResizeObserver();
26
12
 
27
13
  const simulatePaste = (element, value) =>
28
14
  element.simulate('paste', { nativeEvent: { clipboardData: { getData: () => value } } });
@@ -112,8 +98,6 @@ describe('Given a telephone number component', () => {
112
98
  });
113
99
 
114
100
  describe('when pasting', () => {
115
- window.ResizeObserver = ResizeObserver;
116
-
117
101
  beforeEach(() => {
118
102
  component = mount(<PhoneNumberInput {...props} initialValue="+39123456789" />);
119
103
  select = () => component.find(PREFIX_SELECT_SELECTOR);
@@ -76,6 +76,9 @@ const getUniqueIdForOption = (parentId = '', option) => {
76
76
  return `option-${parentId}-${uniqueOptionId}`;
77
77
  };
78
78
 
79
+ /**
80
+ * @deprecated Use `SelectInput` instead (https://neptune.wise.design/blog/2023-11-28-adopting-our-new-selectinput)
81
+ */
79
82
  export default function Select({
80
83
  placeholder,
81
84
  id,
@@ -17,3 +17,14 @@ export function mockMatchMedia() {
17
17
  }),
18
18
  });
19
19
  }
20
+
21
+ export function mockResizeObserver() {
22
+ // mock ResizeObserver because it's not implemented in jsdoc lib
23
+ // https://github.com/jsdom/jsdom/issues/3368
24
+ // eslint-disable-next-line compat/compat
25
+ window.ResizeObserver = class ResizeObserver {
26
+ observe = jest.fn();
27
+ unobserve = jest.fn();
28
+ disconnect = jest.fn();
29
+ };
30
+ }