@transferwise/components 0.0.0-experimental-4ba8514 → 0.0.0-experimental-11855a1
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.
- package/build/i18n/en.json +0 -1
- package/build/i18n/en.json.js +0 -1
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +0 -1
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/inputs/SelectInput.js +0 -4
- package/build/inputs/SelectInput.js.map +1 -1
- package/build/inputs/SelectInput.mjs +0 -4
- package/build/inputs/SelectInput.mjs.map +1 -1
- package/build/main.css +0 -24
- package/build/moneyInput/MoneyInput.js +1 -8
- package/build/moneyInput/MoneyInput.js.map +1 -1
- package/build/moneyInput/MoneyInput.messages.js +0 -3
- package/build/moneyInput/MoneyInput.messages.js.map +1 -1
- package/build/moneyInput/MoneyInput.messages.mjs +0 -3
- package/build/moneyInput/MoneyInput.messages.mjs.map +1 -1
- package/build/moneyInput/MoneyInput.mjs +1 -8
- package/build/moneyInput/MoneyInput.mjs.map +1 -1
- package/build/stepper/Stepper.js +12 -1
- package/build/stepper/Stepper.js.map +1 -1
- package/build/stepper/Stepper.mjs +12 -1
- package/build/stepper/Stepper.mjs.map +1 -1
- package/build/styles/main.css +0 -24
- package/build/styles/stepper/Stepper.css +0 -24
- package/build/types/inputs/SelectInput.d.ts +1 -3
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.messages.d.ts +0 -5
- package/build/types/moneyInput/MoneyInput.messages.d.ts.map +1 -1
- package/build/types/stepper/Stepper.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +1 -2
- package/src/i18n/en.json +0 -1
- package/src/inputs/SelectInput.tsx +3 -8
- package/src/main.css +0 -24
- package/src/moneyInput/MoneyInput.messages.ts +0 -5
- package/src/moneyInput/MoneyInput.rtl.spec.tsx +0 -47
- package/src/moneyInput/MoneyInput.spec.js +11 -0
- package/src/moneyInput/MoneyInput.story.tsx +7 -10
- package/src/moneyInput/MoneyInput.tsx +1 -8
- package/src/stepper/Stepper.css +0 -24
- package/src/stepper/Stepper.less +0 -17
- package/src/stepper/Stepper.spec.js +11 -5
- package/src/stepper/Stepper.tsx +13 -2
- package/src/withId/withId.story.tsx +0 -1
- package/src/moneyInput/MoneyInput.docs.mdx +0 -34
|
@@ -2,7 +2,6 @@ import { Field } from '../field/Field';
|
|
|
2
2
|
import { mockMatchMedia, mockResizeObserver, render, screen, userEvent } from '../test-utils';
|
|
3
3
|
|
|
4
4
|
import MoneyInput from './MoneyInput';
|
|
5
|
-
import messages from './MoneyInput.messages';
|
|
6
5
|
|
|
7
6
|
mockMatchMedia();
|
|
8
7
|
mockResizeObserver();
|
|
@@ -52,7 +51,6 @@ describe('MoneyInput', () => {
|
|
|
52
51
|
const props = {
|
|
53
52
|
currencies,
|
|
54
53
|
selectedCurrency: currencies[1],
|
|
55
|
-
searchPlaceholder: 'Type a currency / country',
|
|
56
54
|
amount: 1000,
|
|
57
55
|
onAmountChange: jest.fn(),
|
|
58
56
|
onCurrencyChange: jest.fn(),
|
|
@@ -92,49 +90,4 @@ describe('MoneyInput', () => {
|
|
|
92
90
|
);
|
|
93
91
|
expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Recipient gets/);
|
|
94
92
|
});
|
|
95
|
-
|
|
96
|
-
describe('ids', () => {
|
|
97
|
-
it('should guarantee id and connect the input with the selected currency via withId HoC', () => {
|
|
98
|
-
render(<MoneyInput {...props} />);
|
|
99
|
-
const input = screen.getByRole('textbox');
|
|
100
|
-
const button = screen.getByRole('combobox');
|
|
101
|
-
expect(input.getAttribute('id')).toBeTruthy();
|
|
102
|
-
expect(input).toHaveAttribute('aria-describedby', button.getAttribute('id'));
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('should have unique id for the select filter with predefined id', async () => {
|
|
106
|
-
const fieldId = 'myFieldId';
|
|
107
|
-
render(
|
|
108
|
-
<Field label="Multiple currencies" id={fieldId}>
|
|
109
|
-
<MoneyInput {...props} />
|
|
110
|
-
</Field>,
|
|
111
|
-
);
|
|
112
|
-
await userEvent.click(screen.getByRole('combobox'));
|
|
113
|
-
expect(screen.getByLabelText(props.searchPlaceholder)).toHaveAttribute(
|
|
114
|
-
'id',
|
|
115
|
-
`${fieldId}SelectedCurrencySearch`,
|
|
116
|
-
);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should have unique id for the select filter without predefined id', async () => {
|
|
120
|
-
render(
|
|
121
|
-
<Field label="Multiple currencies">
|
|
122
|
-
<MoneyInput {...props} />
|
|
123
|
-
</Field>,
|
|
124
|
-
);
|
|
125
|
-
await userEvent.click(screen.getByRole('combobox'));
|
|
126
|
-
expect(screen.getByLabelText(props.searchPlaceholder)).toHaveAttribute(
|
|
127
|
-
'id',
|
|
128
|
-
expect.stringMatching(/^:.*?:SelectedCurrencySearch$/),
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should have AT label for the currency dropdown', () => {
|
|
134
|
-
render(<MoneyInput {...props} />);
|
|
135
|
-
expect(screen.getByRole('combobox')).toHaveAttribute(
|
|
136
|
-
'aria-label',
|
|
137
|
-
messages.selectCurrencyLabel.defaultMessage,
|
|
138
|
-
);
|
|
139
|
-
});
|
|
140
93
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { shallow } from 'enzyme';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
2
3
|
|
|
3
4
|
import { MoneyInput, Title, Input, SelectInput } from '..';
|
|
4
5
|
import { mockMatchMedia, mockResizeObserver } from '../test-utils';
|
|
@@ -817,4 +818,14 @@ describe('Money Input', () => {
|
|
|
817
818
|
});
|
|
818
819
|
});
|
|
819
820
|
});
|
|
821
|
+
|
|
822
|
+
describe('withId', () => {
|
|
823
|
+
it('should guarantee id and connect the input with the selected currency', () => {
|
|
824
|
+
render(<MoneyInput {...props} />);
|
|
825
|
+
const input = screen.getByRole('textbox');
|
|
826
|
+
const button = screen.getByRole('combobox');
|
|
827
|
+
expect(input.getAttribute('id')).toBeTruthy();
|
|
828
|
+
expect(input).toHaveAttribute('aria-describedby', button.getAttribute('id'));
|
|
829
|
+
});
|
|
830
|
+
});
|
|
820
831
|
});
|
|
@@ -9,13 +9,13 @@ import { Field } from '../field/Field';
|
|
|
9
9
|
export default {
|
|
10
10
|
component: MoneyInput,
|
|
11
11
|
title: 'Forms/MoneyInput',
|
|
12
|
-
render: function Render(
|
|
12
|
+
render: function Render(args) {
|
|
13
13
|
const [selectedCurrency, setSelectedCurrency] = useState(args.selectedCurrency);
|
|
14
14
|
|
|
15
15
|
const handleOnCurrencyChange = (value: CurrencyOptionItem) => setSelectedCurrency(value);
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
|
-
<Field label="Editable money input label" required
|
|
18
|
+
<Field label="Editable money input label" required>
|
|
19
19
|
<MoneyInput
|
|
20
20
|
{...args}
|
|
21
21
|
selectedCurrency={selectedCurrency}
|
|
@@ -129,7 +129,6 @@ export const MultipleCurrencies: Story = {
|
|
|
129
129
|
},
|
|
130
130
|
selectedCurrency: exampleCurrency.usd,
|
|
131
131
|
searchPlaceholder: 'Type a currency / country',
|
|
132
|
-
id: 'moneyInput',
|
|
133
132
|
},
|
|
134
133
|
};
|
|
135
134
|
|
|
@@ -156,22 +155,20 @@ export const OpenedInput: Story = {
|
|
|
156
155
|
};
|
|
157
156
|
|
|
158
157
|
export const SmallInput: Story = {
|
|
159
|
-
render: (
|
|
158
|
+
render: (args) => {
|
|
160
159
|
return (
|
|
161
160
|
<>
|
|
162
|
-
<Field label="Money inputs" required>
|
|
161
|
+
<Field id={args.id} label="Money inputs" required>
|
|
163
162
|
<MoneyInput {...args} {...SingleCurrency.args} />
|
|
164
163
|
</Field>
|
|
165
164
|
<br />
|
|
166
|
-
<
|
|
167
|
-
<MoneyInput {...args} {...MultipleCurrencies.args} />
|
|
168
|
-
</Field>
|
|
165
|
+
<MoneyInput {...args} {...MultipleCurrencies.args} />
|
|
169
166
|
<hr />
|
|
170
|
-
<Field label="Error
|
|
167
|
+
<Field id={args.id} label="Error states" sentiment="negative" required>
|
|
171
168
|
<MoneyInput {...args} {...SingleCurrency.args} />
|
|
172
169
|
</Field>
|
|
173
170
|
<br />
|
|
174
|
-
<Field
|
|
171
|
+
<Field sentiment="negative">
|
|
175
172
|
<MoneyInput {...args} {...MultipleCurrencies.args} />
|
|
176
173
|
</Field>
|
|
177
174
|
</>
|
|
@@ -314,7 +314,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
314
314
|
|
|
315
315
|
const isFixedCurrency = (!this.state.searchQuery && hasSingleCurrency()) || !onCurrencyChange;
|
|
316
316
|
const disabled = !this.props.onAmountChange;
|
|
317
|
-
const selectedCurrencyElementId = `${
|
|
317
|
+
const selectedCurrencyElementId = `${amountInputId}SelectedCurrency`;
|
|
318
318
|
|
|
319
319
|
return (
|
|
320
320
|
<div
|
|
@@ -387,13 +387,6 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
387
387
|
)}
|
|
388
388
|
>
|
|
389
389
|
<SelectInput
|
|
390
|
-
UNSAFE_triggerButtonProps={{
|
|
391
|
-
id: undefined,
|
|
392
|
-
'aria-labelledby': undefined,
|
|
393
|
-
'aria-describedby': undefined,
|
|
394
|
-
'aria-invalid': undefined,
|
|
395
|
-
'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel),
|
|
396
|
-
}}
|
|
397
390
|
id={selectedCurrencyElementId}
|
|
398
391
|
items={selectOptions}
|
|
399
392
|
value={selectedCurrency}
|
package/src/stepper/Stepper.css
CHANGED
|
@@ -70,35 +70,11 @@
|
|
|
70
70
|
padding: 0 ;
|
|
71
71
|
}
|
|
72
72
|
.progress-bar {
|
|
73
|
-
float: left;
|
|
74
73
|
-webkit-backface-visibility: hidden;
|
|
75
|
-
height: 100%;
|
|
76
74
|
background-color: var(--color-interactive-primary);
|
|
77
|
-
border-top-left-radius: 1px;
|
|
78
|
-
border-bottom-left-radius: 1px;
|
|
79
75
|
transition: width 0.6s ease-in-out;
|
|
80
76
|
will-change: width;
|
|
81
77
|
}
|
|
82
|
-
[dir="rtl"] .progress-bar {
|
|
83
|
-
float: right;
|
|
84
|
-
}
|
|
85
|
-
.progress-bar::after {
|
|
86
|
-
float: right;
|
|
87
|
-
width: 8px;
|
|
88
|
-
height: 8px;
|
|
89
|
-
margin-top: -3px;
|
|
90
|
-
margin-right: -4px;
|
|
91
|
-
content: "";
|
|
92
|
-
border-radius: 4px;
|
|
93
|
-
}
|
|
94
|
-
[dir="rtl"] .progress-bar::after {
|
|
95
|
-
float: left;
|
|
96
|
-
}
|
|
97
|
-
[dir="rtl"] .progress-bar::after {
|
|
98
|
-
margin-left: -4px;
|
|
99
|
-
margin-right: 0;
|
|
100
|
-
margin-right: initial;
|
|
101
|
-
}
|
|
102
78
|
.btn-unstyled {
|
|
103
79
|
background: none;
|
|
104
80
|
border: none;
|
package/src/stepper/Stepper.less
CHANGED
|
@@ -78,27 +78,10 @@
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
.progress-bar {
|
|
81
|
-
.float(left);
|
|
82
|
-
|
|
83
81
|
-webkit-backface-visibility: hidden;
|
|
84
|
-
height: 100%;
|
|
85
82
|
background-color: var(--color-interactive-primary);
|
|
86
|
-
border-top-left-radius: 1px;
|
|
87
|
-
border-bottom-left-radius: 1px;
|
|
88
83
|
transition: width 0.6s ease-in-out;
|
|
89
84
|
will-change: width;
|
|
90
|
-
|
|
91
|
-
&::after {
|
|
92
|
-
.float(right);
|
|
93
|
-
|
|
94
|
-
width: 8px;
|
|
95
|
-
height: 8px;
|
|
96
|
-
margin-top: -3px;
|
|
97
|
-
.margin(right, -4px);
|
|
98
|
-
|
|
99
|
-
content: "";
|
|
100
|
-
border-radius: 4px;
|
|
101
|
-
}
|
|
102
85
|
}
|
|
103
86
|
|
|
104
87
|
.btn-unstyled {
|
|
@@ -40,15 +40,21 @@ describe('Stepper', () => {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
it('sets the widths of the progress bar to match where you are in the flow', () => {
|
|
43
|
-
expect(totalWidth()).toBe('
|
|
43
|
+
expect(totalWidth()).toBe('0px');
|
|
44
44
|
activeStep(2);
|
|
45
|
-
expect(totalWidth()).toBe(
|
|
45
|
+
expect(totalWidth()).toBe(
|
|
46
|
+
'calc(100% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))',
|
|
47
|
+
);
|
|
46
48
|
steps(5);
|
|
47
|
-
expect(totalWidth()).toBe(
|
|
49
|
+
expect(totalWidth()).toBe(
|
|
50
|
+
'calc(50% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))',
|
|
51
|
+
);
|
|
48
52
|
activeStep(10000);
|
|
49
|
-
expect(totalWidth()).toBe(
|
|
53
|
+
expect(totalWidth()).toBe(
|
|
54
|
+
'calc(100% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))',
|
|
55
|
+
);
|
|
50
56
|
activeStep(-10);
|
|
51
|
-
expect(totalWidth()).toBe('
|
|
57
|
+
expect(totalWidth()).toBe('0px');
|
|
52
58
|
});
|
|
53
59
|
});
|
|
54
60
|
|
package/src/stepper/Stepper.tsx
CHANGED
|
@@ -38,6 +38,18 @@ const Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {
|
|
|
38
38
|
const stepPercentage = 1 / (steps.length - 1);
|
|
39
39
|
const percentageCompleted = activeStepIndex / (steps.length - 1);
|
|
40
40
|
|
|
41
|
+
const getProgressWidth = (): string => {
|
|
42
|
+
if (percentageCompleted === 0) {
|
|
43
|
+
return '0px';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Progress bar starts with left/right (depends on rtl) shift `--progress-bar-start-shift` for hiding Progress bar's left and right borders
|
|
47
|
+
* which are used for progress vertical delimiter.
|
|
48
|
+
* When progress is completed, we need to add `--progress-bar-border-width` to the width to allow the right border be outside of the progress area.
|
|
49
|
+
*/
|
|
50
|
+
return `calc(${percentageCompleted * 100}% + var(--progress-bar-start-shift) + var(--progress-bar-border-width))`;
|
|
51
|
+
};
|
|
52
|
+
|
|
41
53
|
const renderStep = (step: Step, index: number) => {
|
|
42
54
|
const active = index === activeStepIndex;
|
|
43
55
|
const clickable = step.onClick && !active;
|
|
@@ -85,9 +97,8 @@ const Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {
|
|
|
85
97
|
return (
|
|
86
98
|
<div className={clsx('tw-stepper', className)}>
|
|
87
99
|
<div className="progress">
|
|
88
|
-
<div className="progress-bar" style={{ width:
|
|
100
|
+
<div className="progress-bar" style={{ width: getProgressWidth() }} />
|
|
89
101
|
</div>
|
|
90
|
-
|
|
91
102
|
<ol className="tw-stepper-steps p-t-1 m-b-0">{steps.map(renderStep)}</ol>
|
|
92
103
|
</div>
|
|
93
104
|
);
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Meta } from '@storybook/blocks';
|
|
2
|
-
|
|
3
|
-
<Meta title="Forms/MoneyInput/Known issues" />
|
|
4
|
-
|
|
5
|
-
# Known accessibility issues
|
|
6
|
-
|
|
7
|
-
There are few issues reported by Axe that are not fixable or safe to ignore at this point in time.
|
|
8
|
-
|
|
9
|
-
## Form elements should have a visible label / Form elements must have labels
|
|
10
|
-
|
|
11
|
-
While this requirement is normally considered as very serious, it's missing the fact that the input is wrapped by a labelled element with `role="group"`. We’ve tested it in NVDA on Windows and VoiceOver on MacOS, and discovered that if we were to satisfy Axe’s requirements, the screen reader would read out the label twice, something similar to `{Label Text} group, {Label Text} editable` (depending on the SR and the browser) which would result in an unnecessary noise. While the rule is valid, in this particular case the group label seems sufficient.
|
|
12
|
-
|
|
13
|
-
#### Further resources
|
|
14
|
-
|
|
15
|
-
- [Deque reference 1](https://dequeuniversity.com/rules/axe/4.9/label?application=axeAPI)
|
|
16
|
-
- [Deque reference 2](https://dequeuniversity.com/rules/axe/4.9/label-title-only?application=axeAPI)
|
|
17
|
-
- ['Group Labels Do Not Guarantee… Uniquity?' by Adrian Roselli](https://adrianroselli.com/2019/06/group-labels-do-not-guarantee-uniquity.html)
|
|
18
|
-
|
|
19
|
-
## Buttons must have discernible text
|
|
20
|
-
|
|
21
|
-
This affects HTML buttons with `role="combobox"` and deeply nested label text, not being discoverable by Axe. It is a known false-positive.
|
|
22
|
-
|
|
23
|
-
#### Further resources
|
|
24
|
-
|
|
25
|
-
- [Deque reference](https://dequeuniversity.com/rules/axe/4.9/button-name?application=axeAPI)
|
|
26
|
-
- [axe-core github issue](https://github.com/dequelabs/axe-core/issues/4472)
|
|
27
|
-
|
|
28
|
-
## ARIA hidden element must not be focusable or contain focusable elements
|
|
29
|
-
|
|
30
|
-
This is a genuine problem – according to the accessibility guidelines, no element with `aria-hidden="true"` should have any focusable children. This issue is caused by the `SelectInput`'s third party dependency (`Headless UI`) and, by extension, is visible in few other places. Work is planned to address it.
|
|
31
|
-
|
|
32
|
-
#### Further resources
|
|
33
|
-
|
|
34
|
-
- [Deque reference](https://dequeuniversity.com/rules/axe/4.9/aria-hidden-focus?application=axeAPI)
|