@transferwise/components 0.0.0-experimental-99925cd → 0.0.0-experimental-97a0d5e

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 (41) hide show
  1. package/build/alert/Alert.js +1 -1
  2. package/build/alert/Alert.mjs +1 -1
  3. package/build/button/legacyUtils/legacyUtils.js +1 -1
  4. package/build/button/legacyUtils/legacyUtils.mjs +1 -1
  5. package/build/drawer/Drawer.js +1 -1
  6. package/build/drawer/Drawer.mjs +1 -1
  7. package/build/inputs/SelectInput.js +4 -33
  8. package/build/inputs/SelectInput.js.map +1 -1
  9. package/build/inputs/SelectInput.mjs +4 -33
  10. package/build/inputs/SelectInput.mjs.map +1 -1
  11. package/build/markdown/Markdown.js +1 -1
  12. package/build/markdown/Markdown.mjs +1 -1
  13. package/build/popover/Popover.js +1 -1
  14. package/build/popover/Popover.mjs +1 -1
  15. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  16. package/build/types/test-utils/style-mock.d.ts +1 -0
  17. package/build/types/test-utils/style-mock.d.ts.map +1 -0
  18. package/build/types/utilities/deprecatedProperty/deprecatedProperty.d.ts +8 -6
  19. package/build/types/utilities/deprecatedProperty/deprecatedProperty.d.ts.map +1 -1
  20. package/build/types/utilities/deprecatedProperty/index.d.ts +1 -1
  21. package/build/types/utilities/deprecatedProperty/index.d.ts.map +1 -1
  22. package/build/types/utilities/index.d.ts +2 -2
  23. package/build/types/utilities/index.d.ts.map +1 -1
  24. package/build/types/utilities/logActionRequired.d.ts +2 -2
  25. package/build/types/utilities/logActionRequired.d.ts.map +1 -1
  26. package/build/utilities/logActionRequired.js.map +1 -1
  27. package/build/utilities/logActionRequired.mjs.map +1 -1
  28. package/package.json +3 -3
  29. package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.tsx +78 -0
  30. package/src/inputs/SelectInput.spec.tsx +1 -80
  31. package/src/inputs/SelectInput.story.tsx +2 -2
  32. package/src/inputs/SelectInput.tsx +2 -39
  33. package/src/moneyInput/MoneyInput.rtl.spec.tsx +0 -9
  34. package/src/utilities/deprecatedProperty/{deprecatedProperty.spec.js → deprecatedProperty.spec.ts} +7 -13
  35. package/src/utilities/deprecatedProperty/{deprecatedProperty.js → deprecatedProperty.ts} +23 -4
  36. package/src/utilities/{logActionRequired.js → logActionRequired.ts} +2 -2
  37. package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.js +0 -85
  38. package/src/inputs/SelectInput.docs.mdx +0 -21
  39. /package/src/test-utils/{style-mock.js → style-mock.ts} +0 -0
  40. /package/src/utilities/deprecatedProperty/{index.js → index.ts} +0 -0
  41. /package/src/utilities/{index.js → index.ts} +0 -0
@@ -20,7 +20,7 @@ import {
20
20
  } from './SelectInput';
21
21
 
22
22
  const meta = {
23
- title: 'Forms/SelectInput',
23
+ title: 'components/SelectInput',
24
24
  component: SelectInput,
25
25
  tags: ['autodocs'],
26
26
  parameters: { actions: { argTypesRegex: '' } },
@@ -347,7 +347,7 @@ export const WithinField = {
347
347
  args: Months.args,
348
348
  decorators: [
349
349
  (Story) => (
350
- <Field message="Something went wrong" sentiment="negative" label="Month">
350
+ <Field message="Something went wrong" sentiment="negative">
351
351
  <Story />
352
352
  </Field>
353
353
  ),
@@ -258,9 +258,8 @@ export function SelectInput<T = string, M extends boolean = false>({
258
258
  onClose,
259
259
  onClear,
260
260
  }: SelectInputProps<T, M>) {
261
- const inputAttributes = useInputAttributes({ nonLabelable: true });
261
+ const inputAttributes = useInputAttributes();
262
262
  const id = idProp ?? inputAttributes.id;
263
-
264
263
  const [open, setOpen] = useState(false);
265
264
 
266
265
  const initialized = useRef(false);
@@ -296,35 +295,6 @@ export function SelectInput<T = string, M extends boolean = false>({
296
295
  const listboxRef = useRef<HTMLDivElement>(null);
297
296
  const controllerRef = filterable ? searchInputRef : listboxRef;
298
297
 
299
- /**
300
- * Attempts to resolve the `listbox` label
301
- * @see https://storybook.wise.design/?path=/docs/forms-selectinput-accessibility--docs#labelling
302
- */
303
- const getListBoxLabelProps = (): {
304
- listBoxLabel?: string;
305
- listBoxLabelledBy?: string;
306
- } => {
307
- if (UNSAFE_triggerButtonProps?.['aria-label']) {
308
- return {
309
- listBoxLabel: UNSAFE_triggerButtonProps['aria-label'],
310
- };
311
- }
312
-
313
- if (UNSAFE_triggerButtonProps?.['aria-labelledby']) {
314
- return {
315
- listBoxLabelledBy: UNSAFE_triggerButtonProps['aria-labelledby'],
316
- };
317
- }
318
-
319
- if (inputAttributes['aria-labelledby']) {
320
- return {
321
- listBoxLabelledBy: inputAttributes['aria-labelledby'],
322
- };
323
- }
324
-
325
- return {};
326
- };
327
-
328
298
  return (
329
299
  <ListboxBase
330
300
  name={name}
@@ -418,7 +388,7 @@ export function SelectInput<T = string, M extends boolean = false>({
418
388
  }}
419
389
  >
420
390
  <SelectInputOptions
421
- id={id ? `${id}Search` : undefined}
391
+ id={`${id}Search`}
422
392
  items={items}
423
393
  renderValue={renderValue}
424
394
  renderFooter={renderFooter}
@@ -428,7 +398,6 @@ export function SelectInput<T = string, M extends boolean = false>({
428
398
  listboxRef={listboxRef}
429
399
  filterQuery={deferredFilterQuery}
430
400
  onFilterChange={setFilterQuery}
431
- {...getListBoxLabelProps()}
432
401
  />
433
402
  </OptionsOverlay>
434
403
  );
@@ -527,8 +496,6 @@ interface SelectInputOptionsProps<T = string>
527
496
  listboxRef: React.MutableRefObject<HTMLDivElement | null>;
528
497
  filterQuery: string;
529
498
  onFilterChange: (query: string) => void;
530
- listBoxLabel?: string;
531
- listBoxLabelledBy?: string;
532
499
  }
533
500
 
534
501
  function SelectInputOptions<T = string>({
@@ -542,8 +509,6 @@ function SelectInputOptions<T = string>({
542
509
  listboxRef,
543
510
  filterQuery,
544
511
  onFilterChange,
545
- listBoxLabel,
546
- listBoxLabelledBy,
547
512
  }: SelectInputOptionsProps<T>) {
548
513
  const intl = useIntl();
549
514
 
@@ -697,8 +662,6 @@ function SelectInputOptions<T = string>({
697
662
  id={listboxId}
698
663
  role="listbox"
699
664
  aria-orientation="vertical"
700
- aria-label={listBoxLabel}
701
- aria-labelledby={listBoxLabelledBy}
702
665
  tabIndex={0}
703
666
  className="np-select-input-listbox"
704
667
  >
@@ -137,13 +137,4 @@ describe('MoneyInput', () => {
137
137
  messages.selectCurrencyLabel.defaultMessage,
138
138
  );
139
139
  });
140
-
141
- it('should have a listbox label', async () => {
142
- render(<MoneyInput {...props} />);
143
- const trigger = screen.getByRole('combobox');
144
- await userEvent.click(trigger);
145
- const triggerLabel = trigger.getAttribute('aria-label');
146
- expect(triggerLabel).toBeTruthy();
147
- expect(screen.getByRole('listbox', { name: triggerLabel ?? '' })).toBeInTheDocument();
148
- });
149
140
  });
@@ -5,6 +5,7 @@ const props = { prop1: 'prop1', prop2: 'prop2' };
5
5
  const validator = jest.fn();
6
6
 
7
7
  describe('deprecated', () => {
8
+ const component = 'Test';
8
9
  const origWarn = console.warn;
9
10
  let mockedWarn;
10
11
 
@@ -22,11 +23,10 @@ describe('deprecated', () => {
22
23
  });
23
24
 
24
25
  describe('if prop has been listed as deprecated', () => {
26
+ const propertyName = 'prop1';
27
+
25
28
  it('calls console.warn with the correct message', () => {
26
- const component = 'Test';
27
29
  const newProperty = 'newProp';
28
- const propertyName = 'prop1';
29
-
30
30
  const expiryDate = new Date('01-01-2000');
31
31
  const expiryDateString = expiryDate.toLocaleString('en-GB', {
32
32
  year: 'numeric',
@@ -42,10 +42,6 @@ describe('deprecated', () => {
42
42
  });
43
43
 
44
44
  it('calls console.warn with correct message if newProp is not provided', () => {
45
- const component = 'Test';
46
-
47
- const propertyName = 'prop1';
48
-
49
45
  const expiryDate = new Date('01-01-2000');
50
46
  const expiryDateString = expiryDate.toLocaleString('en-GB', {
51
47
  year: 'numeric',
@@ -61,8 +57,6 @@ describe('deprecated', () => {
61
57
  });
62
58
 
63
59
  it('calls console.warn with correct message if message is provided', () => {
64
- const component = 'Test';
65
- const propertyName = 'prop1';
66
60
  const message = 'Some custom message.';
67
61
 
68
62
  deprecated(validator, { component, message })(props, propertyName);
@@ -74,15 +68,15 @@ describe('deprecated', () => {
74
68
  });
75
69
 
76
70
  describe('if prop has not been listed as deprecated', () => {
71
+ const propertyName = 'prop3';
72
+
77
73
  it('calls validator with props', () => {
78
- const propertyName = 'prop3';
79
- deprecated(validator, {})(props, propertyName);
74
+ deprecated(validator, { component })(props, propertyName);
80
75
  expect(console.warn).not.toHaveBeenCalled();
81
76
  });
82
77
 
83
78
  it('calls validator with expected args', () => {
84
- const propertyName = 'prop3';
85
- deprecated(validator, {})(props, propertyName);
79
+ deprecated(validator, { component })(props, propertyName);
86
80
  expect(validator).toHaveBeenCalledWith({ prop1: 'prop1', prop2: 'prop2' }, 'prop3');
87
81
  });
88
82
  });
@@ -1,6 +1,22 @@
1
1
  import { logActionRequired } from '../logActionRequired';
2
2
 
3
- const deprecatedMessage = ({ component, propName, message, expiryDate }) => {
3
+ type DeprecatedMessageType = {
4
+ component: string;
5
+ propName: string;
6
+ message: string;
7
+ expiryDate?: Date;
8
+ };
9
+
10
+ type ValidatorType = (props: Record<string, any>, propName: string, ...rest: any[]) => Error | null;
11
+
12
+ type DeprecatedOptionsType = {
13
+ component: string;
14
+ message?: string;
15
+ newProp?: string;
16
+ expiryDate?: Date;
17
+ };
18
+
19
+ const deprecatedMessage = ({ component, propName, message, expiryDate }: DeprecatedMessageType) => {
4
20
  const messages = [`${component} has deprecated the use of ${propName}.`];
5
21
 
6
22
  if (message) {
@@ -21,11 +37,14 @@ const deprecatedMessage = ({ component, propName, message, expiryDate }) => {
21
37
  };
22
38
 
23
39
  const deprecated =
24
- (validator, { component, message = '', newProp: newProperty = null, expiryDate = null }) =>
25
- (props, propertyName, ...rest) => {
40
+ (
41
+ validator: ValidatorType,
42
+ { component, message = '', newProp: newProperty, expiryDate }: DeprecatedOptionsType,
43
+ ) =>
44
+ (props: Record<string, any>, propertyName: string, ...rest: any[]) => {
26
45
  const newPropertyMessage = newProperty ? `Please use ${newProperty} instead.` : message;
27
46
 
28
- if (props[propertyName] != null && typeof props[propertyName] !== 'undefined') {
47
+ if (props[propertyName] !== null && props[propertyName] !== undefined) {
29
48
  logActionRequired(
30
49
  deprecatedMessage({
31
50
  component,
@@ -1,11 +1,11 @@
1
- export function logActionRequired(message) {
1
+ export function logActionRequired(message: string) {
2
2
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
3
3
  // eslint-disable-next-line no-console
4
4
  console.warn(message);
5
5
  }
6
6
  }
7
7
 
8
- export function logActionRequiredIf(message, conditional) {
8
+ export function logActionRequiredIf(message: string, conditional: boolean) {
9
9
  if (conditional) {
10
10
  logActionRequired(message);
11
11
  }
@@ -1,85 +0,0 @@
1
- import { text } from '@storybook/addon-knobs';
2
- import { userEvent, within } from '@storybook/test';
3
-
4
- import InputWithDisplayFormat from '.';
5
- import { Field } from '../field/Field';
6
-
7
- export default {
8
- component: InputWithDisplayFormat,
9
- title: 'Forms/InputWithDisplayFormat',
10
- };
11
-
12
- export const Basic = () => {
13
- const placeholder = text('Placeholder', '**-**-**');
14
- const displayPattern = text('DisplayPattern', '**-**-**');
15
-
16
- return (
17
- <Field label="Display pattern is controlled via knobs" id="Basic">
18
- <InputWithDisplayFormat
19
- id="Basic"
20
- placeholder={placeholder}
21
- displayPattern={displayPattern}
22
- className="form-control"
23
- onChange={(v) => console.log(v)}
24
- onBlur={(v) => console.log(v)}
25
- onFocus={(v) => console.log(v)}
26
- />
27
- </Field>
28
- );
29
- };
30
-
31
- const Template = (args) => {
32
- const placeholder = args.pattern;
33
- const displayPattern = args.pattern;
34
- const label = args.label;
35
- const id = label.replaceAll(' ', '-').toLowerCase();
36
-
37
- return (
38
- <Field label={label} id={id}>
39
- <InputWithDisplayFormat
40
- id={id}
41
- placeholder={placeholder}
42
- displayPattern={displayPattern}
43
- className="form-control"
44
- onChange={(v) => console.log(v)}
45
- onBlur={(v) => console.log(v)}
46
- onFocus={(v) => console.log(v)}
47
- />
48
- </Field>
49
- );
50
- };
51
-
52
- export const CardNumber = Template.bind({});
53
- CardNumber.args = {
54
- label: 'Card Number',
55
- pattern: '**** **** **** **** ***',
56
- };
57
-
58
- export const CVC = Template.bind({});
59
- CVC.args = {
60
- label: 'CVC',
61
- pattern: '***',
62
- };
63
-
64
- export const ExpiryDate = Template.bind({});
65
- ExpiryDate.args = {
66
- label: 'Expiry Date',
67
- pattern: '** / **',
68
- };
69
-
70
- export const SecurityPin = Template.bind({});
71
- SecurityPin.args = {
72
- label: 'Security Pin',
73
- pattern: '*-*-*-*-*-*',
74
- };
75
-
76
- export const SecurityPinPlay = Template.bind({});
77
- SecurityPinPlay.args = {
78
- label: 'Security Pin',
79
- pattern: '*-*-*-*-*-*',
80
- };
81
-
82
- SecurityPinPlay.play = async ({ canvasElement }) => {
83
- const canvas = within(canvasElement);
84
- await userEvent.type(canvas.getByPlaceholderText('*-*-*-*-*-*'), '123456');
85
- };
@@ -1,21 +0,0 @@
1
- import { Meta } from '@storybook/blocks';
2
- import { MoneyInput } from '..';
3
-
4
- <Meta title="Forms/SelectInput/Accessibility" />
5
-
6
- # Accessibility
7
-
8
- ## Labelling
9
-
10
- In order for the `<SelectInput />` to be considered accessible, it must be provided with a matching label, preferably via the <a href="/?path=/docs/field--docs">Field</a> component.
11
-
12
- Additionally, the `listbox` container that holds all the options is also expected to have its own label, which the component will attempt to resolve by looking in the following places:
13
-
14
- 1. `UNSAFE_triggerButtonProps['aria-label']` prop, which reuses the custom label provided for the trigger button.
15
- <br /> A good example of this strategy is the `<MoneyInput />` component, internally setting
16
- `"Select currency"` as a trigger button label, which then gets automatically applied to the
17
- `listbox`.
18
- 2. `UNSAFE_triggerButtonProps['aria-labelledby']` prop, which holds the id of the element labelling the trigger button.
19
- 3. Correctly paired input `<label />` text, ideally via the `Field` component.
20
-
21
- > Using option group heading is possible but complicated as we can have multiple groups, and those are not necessarily rendered consistently if search or virtualisation are enabled.
File without changes
File without changes