@transferwise/components 46.66.0 → 46.67.1
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/flowNavigation/animatedLabel/AnimatedLabel.js +2 -5
- package/build/flowNavigation/animatedLabel/AnimatedLabel.js.map +1 -1
- package/build/flowNavigation/animatedLabel/AnimatedLabel.mjs +2 -5
- package/build/flowNavigation/animatedLabel/AnimatedLabel.mjs.map +1 -1
- package/build/i18n/de.json +1 -0
- package/build/i18n/de.json.js +1 -0
- package/build/i18n/de.json.js.map +1 -1
- package/build/i18n/de.json.mjs +1 -0
- package/build/i18n/de.json.mjs.map +1 -1
- package/build/i18n/en.json +1 -0
- package/build/i18n/en.json.js +1 -0
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +1 -0
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/i18n/es.json +1 -0
- package/build/i18n/es.json.js +1 -0
- package/build/i18n/es.json.js.map +1 -1
- package/build/i18n/es.json.mjs +1 -0
- package/build/i18n/es.json.mjs.map +1 -1
- package/build/i18n/fr.json +1 -0
- package/build/i18n/fr.json.js +1 -0
- package/build/i18n/fr.json.js.map +1 -1
- package/build/i18n/fr.json.mjs +1 -0
- package/build/i18n/fr.json.mjs.map +1 -1
- package/build/i18n/hu.json +1 -0
- package/build/i18n/hu.json.js +1 -0
- package/build/i18n/hu.json.js.map +1 -1
- package/build/i18n/hu.json.mjs +1 -0
- package/build/i18n/hu.json.mjs.map +1 -1
- package/build/i18n/id.json +1 -0
- package/build/i18n/id.json.js +1 -0
- package/build/i18n/id.json.js.map +1 -1
- package/build/i18n/id.json.mjs +1 -0
- package/build/i18n/id.json.mjs.map +1 -1
- package/build/i18n/it.json +1 -0
- package/build/i18n/it.json.js +1 -0
- package/build/i18n/it.json.js.map +1 -1
- package/build/i18n/it.json.mjs +1 -0
- package/build/i18n/it.json.mjs.map +1 -1
- package/build/i18n/ja.json +1 -0
- package/build/i18n/ja.json.js +1 -0
- package/build/i18n/ja.json.js.map +1 -1
- package/build/i18n/ja.json.mjs +1 -0
- package/build/i18n/ja.json.mjs.map +1 -1
- package/build/i18n/pl.json +1 -0
- package/build/i18n/pl.json.js +1 -0
- package/build/i18n/pl.json.js.map +1 -1
- package/build/i18n/pl.json.mjs +1 -0
- package/build/i18n/pl.json.mjs.map +1 -1
- package/build/i18n/pt.json +1 -0
- package/build/i18n/pt.json.js +1 -0
- package/build/i18n/pt.json.js.map +1 -1
- package/build/i18n/pt.json.mjs +1 -0
- package/build/i18n/pt.json.mjs.map +1 -1
- package/build/i18n/ro.json +1 -0
- package/build/i18n/ro.json.js +1 -0
- package/build/i18n/ro.json.js.map +1 -1
- package/build/i18n/ro.json.mjs +1 -0
- package/build/i18n/ro.json.mjs.map +1 -1
- package/build/i18n/ru.json +1 -0
- package/build/i18n/ru.json.js +1 -0
- package/build/i18n/ru.json.js.map +1 -1
- package/build/i18n/ru.json.mjs +1 -0
- package/build/i18n/ru.json.mjs.map +1 -1
- package/build/i18n/th.json +1 -0
- package/build/i18n/th.json.js +1 -0
- package/build/i18n/th.json.js.map +1 -1
- package/build/i18n/th.json.mjs +1 -0
- package/build/i18n/th.json.mjs.map +1 -1
- package/build/i18n/tr.json +1 -0
- package/build/i18n/tr.json.js +1 -0
- package/build/i18n/tr.json.js.map +1 -1
- package/build/i18n/tr.json.mjs +1 -0
- package/build/i18n/tr.json.mjs.map +1 -1
- package/build/i18n/zh-CN.json +1 -0
- package/build/i18n/zh-CN.json.js +1 -0
- package/build/i18n/zh-CN.json.js.map +1 -1
- package/build/i18n/zh-CN.json.mjs +1 -0
- package/build/i18n/zh-CN.json.mjs.map +1 -1
- package/build/i18n/zh-HK.json +1 -0
- package/build/i18n/zh-HK.json.js +1 -0
- package/build/i18n/zh-HK.json.js.map +1 -1
- package/build/i18n/zh-HK.json.mjs +1 -0
- package/build/i18n/zh-HK.json.mjs.map +1 -1
- package/build/inputs/SelectInput.js +4 -0
- package/build/inputs/SelectInput.js.map +1 -1
- package/build/inputs/SelectInput.mjs +4 -0
- package/build/inputs/SelectInput.mjs.map +1 -1
- package/build/main.css +4 -24
- package/build/moneyInput/MoneyInput.js +9 -1
- package/build/moneyInput/MoneyInput.js.map +1 -1
- package/build/moneyInput/MoneyInput.messages.js +3 -0
- package/build/moneyInput/MoneyInput.messages.js.map +1 -1
- package/build/moneyInput/MoneyInput.messages.mjs +3 -0
- package/build/moneyInput/MoneyInput.messages.mjs.map +1 -1
- package/build/moneyInput/MoneyInput.mjs +9 -1
- 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/flowNavigation/FlowNavigation.css +4 -0
- package/build/styles/main.css +4 -24
- package/build/styles/stepper/Stepper.css +0 -24
- package/build/types/inputs/SelectInput.d.ts +3 -1
- 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 +5 -0
- 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/FlowNavigation.css +4 -0
- package/src/flowNavigation/FlowNavigation.less +4 -0
- package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +1 -2
- package/src/flowNavigation/animatedLabel/AnimatedLabel.tsx +2 -2
- package/src/i18n/de.json +1 -0
- package/src/i18n/en.json +1 -0
- package/src/i18n/es.json +1 -0
- package/src/i18n/fr.json +1 -0
- package/src/i18n/hu.json +1 -0
- package/src/i18n/id.json +1 -0
- package/src/i18n/it.json +1 -0
- package/src/i18n/ja.json +1 -0
- package/src/i18n/pl.json +1 -0
- package/src/i18n/pt.json +1 -0
- package/src/i18n/ro.json +1 -0
- package/src/i18n/ru.json +1 -0
- package/src/i18n/th.json +1 -0
- package/src/i18n/tr.json +1 -0
- package/src/i18n/zh-CN.json +1 -0
- package/src/i18n/zh-HK.json +1 -0
- package/src/inputs/SelectInput.tsx +8 -3
- package/src/main.css +4 -24
- package/src/moneyInput/MoneyInput.docs.mdx +34 -0
- package/src/moneyInput/MoneyInput.messages.ts +5 -0
- package/src/moneyInput/MoneyInput.rtl.spec.tsx +47 -0
- package/src/moneyInput/MoneyInput.spec.js +0 -11
- package/src/moneyInput/MoneyInput.story.tsx +10 -7
- package/src/moneyInput/MoneyInput.tsx +9 -1
- 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 +1 -0
package/src/i18n/ro.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"neptune.Label.optional": "(Opțional)",
|
|
22
22
|
"neptune.Link.opensInNewTab": "(se deschide într-o filă nouă)",
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "Selectează o opţiune...",
|
|
24
|
+
"neptune.MoneyInput.Select.selectCurrencyLabel": "Selectează moneda",
|
|
24
25
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "Selectează o opțiune...",
|
|
25
26
|
"neptune.Select.searchPlaceholder": "Caută...",
|
|
26
27
|
"neptune.SelectInput.noResultsFound": "Nu s-a găsit niciun rezultat",
|
package/src/i18n/ru.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"neptune.Label.optional": "(необязательно)",
|
|
22
22
|
"neptune.Link.opensInNewTab": "(откроется в новой вкладке)",
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "Выберите вариант...",
|
|
24
|
+
"neptune.MoneyInput.Select.selectCurrencyLabel": "Выберите валюту",
|
|
24
25
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "Выберите вариант...",
|
|
25
26
|
"neptune.Select.searchPlaceholder": "Поиск...",
|
|
26
27
|
"neptune.SelectInput.noResultsFound": "Ничего не найдено",
|
package/src/i18n/th.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"neptune.Label.optional": "(ไม่บังคับ)",
|
|
22
22
|
"neptune.Link.opensInNewTab": "(เปิดในแท็บใหม่)",
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "เลือกตัวเลือก...",
|
|
24
|
+
"neptune.MoneyInput.Select.selectCurrencyLabel": "เลือกสกุลเงิน",
|
|
24
25
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "เลือกตัวเลือก...",
|
|
25
26
|
"neptune.Select.searchPlaceholder": "ค้นหา...",
|
|
26
27
|
"neptune.SelectInput.noResultsFound": "ไม่พบผลลัพธ์",
|
package/src/i18n/tr.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"neptune.Label.optional": "(İsteğe bağlı)",
|
|
22
22
|
"neptune.Link.opensInNewTab": "(yeni sekmede açılır)",
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "Bir seçenek seçin...",
|
|
24
|
+
"neptune.MoneyInput.Select.selectCurrencyLabel": "Para birimi seçin",
|
|
24
25
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "Bir seçenek seçin...",
|
|
25
26
|
"neptune.Select.searchPlaceholder": "Ara...",
|
|
26
27
|
"neptune.SelectInput.noResultsFound": "Sonuç bulunamadı",
|
package/src/i18n/zh-CN.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"neptune.Label.optional": "(可选)",
|
|
22
22
|
"neptune.Link.opensInNewTab": "(在新标签页中打开)",
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "请选择...",
|
|
24
|
+
"neptune.MoneyInput.Select.selectCurrencyLabel": "选择货币",
|
|
24
25
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "选择其中一项...",
|
|
25
26
|
"neptune.Select.searchPlaceholder": "搜索",
|
|
26
27
|
"neptune.SelectInput.noResultsFound": "找不到结果",
|
package/src/i18n/zh-HK.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"neptune.Label.optional": "(可選)",
|
|
22
22
|
"neptune.Link.opensInNewTab": "(在新分頁中開啟)",
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "選擇一個選項…",
|
|
24
|
+
"neptune.MoneyInput.Select.selectCurrencyLabel": "選擇貨幣",
|
|
24
25
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "選擇其中一項…",
|
|
25
26
|
"neptune.Select.searchPlaceholder": "搜尋…",
|
|
26
27
|
"neptune.SelectInput.noResultsFound": "找不到任何結果",
|
|
@@ -165,7 +165,9 @@ export interface SelectInputProps<T = string, M extends boolean = false> {
|
|
|
165
165
|
disabled?: boolean;
|
|
166
166
|
size?: 'sm' | 'md' | 'lg';
|
|
167
167
|
className?: string;
|
|
168
|
-
UNSAFE_triggerButtonProps?: WithInputAttributesProps['inputAttributes']
|
|
168
|
+
UNSAFE_triggerButtonProps?: WithInputAttributesProps['inputAttributes'] & {
|
|
169
|
+
'aria-label'?: string;
|
|
170
|
+
};
|
|
169
171
|
onFilterChange?: (args: { query: string; queryNormalized: string | null }) => void;
|
|
170
172
|
onChange?: (value: M extends true ? T[] : T) => void;
|
|
171
173
|
onClose?: () => void;
|
|
@@ -258,7 +260,6 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
258
260
|
}: SelectInputProps<T, M>) {
|
|
259
261
|
const inputAttributes = useInputAttributes();
|
|
260
262
|
const id = idProp ?? inputAttributes.id;
|
|
261
|
-
|
|
262
263
|
const [open, setOpen] = useState(false);
|
|
263
264
|
|
|
264
265
|
const initialized = useRef(false);
|
|
@@ -387,6 +388,7 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
387
388
|
}}
|
|
388
389
|
>
|
|
389
390
|
<SelectInputOptions
|
|
391
|
+
id={`${id}Search`}
|
|
390
392
|
items={items}
|
|
391
393
|
renderValue={renderValue}
|
|
392
394
|
renderFooter={renderFooter}
|
|
@@ -488,7 +490,7 @@ const SelectInputOptionsContainer = forwardRef(function SelectInputOptionsContai
|
|
|
488
490
|
interface SelectInputOptionsProps<T = string>
|
|
489
491
|
extends Pick<
|
|
490
492
|
SelectInputProps<T>,
|
|
491
|
-
'items' | 'renderValue' | 'renderFooter' | 'filterable' | 'filterPlaceholder'
|
|
493
|
+
'items' | 'renderValue' | 'renderFooter' | 'filterable' | 'filterPlaceholder' | 'id'
|
|
492
494
|
> {
|
|
493
495
|
searchInputRef: React.MutableRefObject<HTMLInputElement | null>;
|
|
494
496
|
listboxRef: React.MutableRefObject<HTMLDivElement | null>;
|
|
@@ -497,6 +499,7 @@ interface SelectInputOptionsProps<T = string>
|
|
|
497
499
|
}
|
|
498
500
|
|
|
499
501
|
function SelectInputOptions<T = string>({
|
|
502
|
+
id,
|
|
500
503
|
items,
|
|
501
504
|
renderValue = String,
|
|
502
505
|
renderFooter,
|
|
@@ -609,9 +612,11 @@ function SelectInputOptions<T = string>({
|
|
|
609
612
|
<div className="np-select-input-query-container">
|
|
610
613
|
<SearchInput
|
|
611
614
|
ref={searchInputRef}
|
|
615
|
+
id={id}
|
|
612
616
|
role="combobox"
|
|
613
617
|
shape="rectangle"
|
|
614
618
|
placeholder={filterPlaceholder}
|
|
619
|
+
aria-label={filterPlaceholder}
|
|
615
620
|
defaultValue={filterQuery}
|
|
616
621
|
aria-autocomplete="list"
|
|
617
622
|
aria-expanded
|
package/src/main.css
CHANGED
|
@@ -2185,6 +2185,10 @@ html:not([dir="rtl"]) .np-flow-navigation__stepper {
|
|
|
2185
2185
|
.np-flow-navigation--xs-max .np-animated-label {
|
|
2186
2186
|
height: auto;
|
|
2187
2187
|
}
|
|
2188
|
+
.np-flow-navigation--xs-max .np-animated-label .tw-icon-chevron-down {
|
|
2189
|
+
margin-left: 4px;
|
|
2190
|
+
margin-left: var(--size-4);
|
|
2191
|
+
}
|
|
2188
2192
|
.np-flow-navigation--sm .np-flow-navigation__stepper {
|
|
2189
2193
|
min-height: 56px;
|
|
2190
2194
|
}
|
|
@@ -4368,35 +4372,11 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
4368
4372
|
padding: 0 ;
|
|
4369
4373
|
}
|
|
4370
4374
|
.progress-bar {
|
|
4371
|
-
float: left;
|
|
4372
4375
|
-webkit-backface-visibility: hidden;
|
|
4373
|
-
height: 100%;
|
|
4374
4376
|
background-color: var(--color-interactive-primary);
|
|
4375
|
-
border-top-left-radius: 1px;
|
|
4376
|
-
border-bottom-left-radius: 1px;
|
|
4377
4377
|
transition: width 0.6s ease-in-out;
|
|
4378
4378
|
will-change: width;
|
|
4379
4379
|
}
|
|
4380
|
-
[dir="rtl"] .progress-bar {
|
|
4381
|
-
float: right;
|
|
4382
|
-
}
|
|
4383
|
-
.progress-bar::after {
|
|
4384
|
-
float: right;
|
|
4385
|
-
width: 8px;
|
|
4386
|
-
height: 8px;
|
|
4387
|
-
margin-top: -3px;
|
|
4388
|
-
margin-right: -4px;
|
|
4389
|
-
content: "";
|
|
4390
|
-
border-radius: 4px;
|
|
4391
|
-
}
|
|
4392
|
-
[dir="rtl"] .progress-bar::after {
|
|
4393
|
-
float: left;
|
|
4394
|
-
}
|
|
4395
|
-
[dir="rtl"] .progress-bar::after {
|
|
4396
|
-
margin-left: -4px;
|
|
4397
|
-
margin-right: 0;
|
|
4398
|
-
margin-right: initial;
|
|
4399
|
-
}
|
|
4400
4380
|
.btn-unstyled {
|
|
4401
4381
|
background: none;
|
|
4402
4382
|
border: none;
|
|
@@ -0,0 +1,34 @@
|
|
|
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)
|
|
@@ -5,4 +5,9 @@ export default defineMessages({
|
|
|
5
5
|
id: 'neptune.MoneyInput.Select.placeholder',
|
|
6
6
|
defaultMessage: 'Select an option...',
|
|
7
7
|
},
|
|
8
|
+
selectCurrencyLabel: {
|
|
9
|
+
id: 'neptune.MoneyInput.Select.selectCurrencyLabel',
|
|
10
|
+
defaultMessage: 'Select currency',
|
|
11
|
+
description: 'Visually hidden label for the currency selector input.',
|
|
12
|
+
},
|
|
8
13
|
});
|
|
@@ -2,6 +2,7 @@ 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';
|
|
5
6
|
|
|
6
7
|
mockMatchMedia();
|
|
7
8
|
mockResizeObserver();
|
|
@@ -51,6 +52,7 @@ describe('MoneyInput', () => {
|
|
|
51
52
|
const props = {
|
|
52
53
|
currencies,
|
|
53
54
|
selectedCurrency: currencies[1],
|
|
55
|
+
searchPlaceholder: 'Type a currency / country',
|
|
54
56
|
amount: 1000,
|
|
55
57
|
onAmountChange: jest.fn(),
|
|
56
58
|
onCurrencyChange: jest.fn(),
|
|
@@ -90,4 +92,49 @@ describe('MoneyInput', () => {
|
|
|
90
92
|
);
|
|
91
93
|
expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Recipient gets/);
|
|
92
94
|
});
|
|
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
|
+
});
|
|
93
140
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { shallow } from 'enzyme';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
2
|
|
|
4
3
|
import { MoneyInput, Title, Input, SelectInput } from '..';
|
|
5
4
|
import { mockMatchMedia, mockResizeObserver } from '../test-utils';
|
|
@@ -818,14 +817,4 @@ describe('Money Input', () => {
|
|
|
818
817
|
});
|
|
819
818
|
});
|
|
820
819
|
});
|
|
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
|
-
});
|
|
831
820
|
});
|
|
@@ -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(args) {
|
|
12
|
+
render: function Render({ id, ...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 id={id}>
|
|
19
19
|
<MoneyInput
|
|
20
20
|
{...args}
|
|
21
21
|
selectedCurrency={selectedCurrency}
|
|
@@ -129,6 +129,7 @@ export const MultipleCurrencies: Story = {
|
|
|
129
129
|
},
|
|
130
130
|
selectedCurrency: exampleCurrency.usd,
|
|
131
131
|
searchPlaceholder: 'Type a currency / country',
|
|
132
|
+
id: 'moneyInput',
|
|
132
133
|
},
|
|
133
134
|
};
|
|
134
135
|
|
|
@@ -155,20 +156,22 @@ export const OpenedInput: Story = {
|
|
|
155
156
|
};
|
|
156
157
|
|
|
157
158
|
export const SmallInput: Story = {
|
|
158
|
-
render: (args) => {
|
|
159
|
+
render: ({ id, ...args }) => {
|
|
159
160
|
return (
|
|
160
161
|
<>
|
|
161
|
-
<Field
|
|
162
|
+
<Field label="Money inputs" required>
|
|
162
163
|
<MoneyInput {...args} {...SingleCurrency.args} />
|
|
163
164
|
</Field>
|
|
164
165
|
<br />
|
|
165
|
-
<
|
|
166
|
+
<Field label="Multiple currencies">
|
|
167
|
+
<MoneyInput {...args} {...MultipleCurrencies.args} />
|
|
168
|
+
</Field>
|
|
166
169
|
<hr />
|
|
167
|
-
<Field
|
|
170
|
+
<Field label="Error state" sentiment="negative" required>
|
|
168
171
|
<MoneyInput {...args} {...SingleCurrency.args} />
|
|
169
172
|
</Field>
|
|
170
173
|
<br />
|
|
171
|
-
<Field sentiment="negative">
|
|
174
|
+
<Field label="Multiple currencies: error state" sentiment="negative">
|
|
172
175
|
<MoneyInput {...args} {...MultipleCurrencies.args} />
|
|
173
176
|
</Field>
|
|
174
177
|
</>
|
|
@@ -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 = `${amountInputId}SelectedCurrency`;
|
|
317
|
+
const selectedCurrencyElementId = `${inputAttributes?.id ?? amountInputId}SelectedCurrency`;
|
|
318
318
|
|
|
319
319
|
return (
|
|
320
320
|
<div
|
|
@@ -381,12 +381,20 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
381
381
|
</div>
|
|
382
382
|
) : (
|
|
383
383
|
<div
|
|
384
|
+
translate="no"
|
|
384
385
|
className={clsx(
|
|
385
386
|
this.style('input-group-btn'),
|
|
386
387
|
this.style('amount-currency-select-btn'),
|
|
387
388
|
)}
|
|
388
389
|
>
|
|
389
390
|
<SelectInput
|
|
391
|
+
UNSAFE_triggerButtonProps={{
|
|
392
|
+
id: undefined,
|
|
393
|
+
'aria-labelledby': undefined,
|
|
394
|
+
'aria-describedby': undefined,
|
|
395
|
+
'aria-invalid': undefined,
|
|
396
|
+
'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel),
|
|
397
|
+
}}
|
|
390
398
|
id={selectedCurrencyElementId}
|
|
391
399
|
items={selectOptions}
|
|
392
400
|
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
|
);
|