@transferwise/components 0.0.0-experimental-eaf43c2 → 0.0.0-experimental-6730b89
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/avatarLayout/AvatarLayout.js.map +1 -1
- package/build/avatarLayout/AvatarLayout.mjs.map +1 -1
- package/build/avatarView/AvatarView.js +8 -4
- package/build/avatarView/AvatarView.js.map +1 -1
- package/build/avatarView/AvatarView.mjs +8 -4
- package/build/avatarView/AvatarView.mjs.map +1 -1
- package/build/avatarView/{NotificationDot.js → Dot.js} +14 -12
- package/build/avatarView/Dot.js.map +1 -0
- package/build/avatarView/{NotificationDot.mjs → Dot.mjs} +14 -12
- package/build/avatarView/Dot.mjs.map +1 -0
- package/build/i18n/en.json +0 -2
- package/build/i18n/en.json.js +0 -2
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +0 -2
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/index.js +0 -2
- package/build/index.js.map +1 -1
- package/build/index.mjs +0 -1
- package/build/index.mjs.map +1 -1
- package/build/main.css +17 -69
- package/build/styles/avatarView/AvatarView.css +17 -11
- package/build/styles/avatarView/Dot.css +26 -0
- package/build/styles/main.css +17 -69
- package/build/types/avatarLayout/AvatarLayout.d.ts +1 -1
- package/build/types/avatarLayout/AvatarLayout.d.ts.map +1 -1
- package/build/types/avatarView/AvatarView.d.ts +4 -1
- package/build/types/avatarView/AvatarView.d.ts.map +1 -1
- package/build/types/avatarView/Dot.d.ts +8 -0
- package/build/types/avatarView/Dot.d.ts.map +1 -0
- package/build/types/index.d.ts +0 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/test-utils/index.d.ts +0 -4
- package/build/types/test-utils/index.d.ts.map +1 -1
- package/package.json +2 -3
- package/src/avatarLayout/AvatarLayout.tsx +1 -1
- package/src/avatarView/AvatarView.css +17 -11
- package/src/avatarView/AvatarView.less +1 -1
- package/src/avatarView/AvatarView.story.tsx +37 -0
- package/src/avatarView/AvatarView.tsx +13 -6
- package/src/avatarView/Dot.css +26 -0
- package/src/avatarView/Dot.less +31 -0
- package/src/avatarView/Dot.tsx +42 -0
- package/src/i18n/en.json +0 -2
- package/src/index.ts +0 -2
- package/src/listItem/AvatarView/ListItemAvatarView.story.tsx +69 -2
- package/src/main.css +17 -69
- package/src/main.less +0 -1
- package/src/ssr.spec.tsx +0 -1
- package/build/avatarView/NotificationDot.js.map +0 -1
- package/build/avatarView/NotificationDot.mjs.map +0 -1
- package/build/moneyInputField/AmountInput.js +0 -284
- package/build/moneyInputField/AmountInput.js.map +0 -1
- package/build/moneyInputField/AmountInput.mjs +0 -282
- package/build/moneyInputField/AmountInput.mjs.map +0 -1
- package/build/moneyInputField/AnimatedNumber.js +0 -50
- package/build/moneyInputField/AnimatedNumber.js.map +0 -1
- package/build/moneyInputField/AnimatedNumber.mjs +0 -48
- package/build/moneyInputField/AnimatedNumber.mjs.map +0 -1
- package/build/moneyInputField/Chevron.js +0 -33
- package/build/moneyInputField/Chevron.js.map +0 -1
- package/build/moneyInputField/Chevron.mjs +0 -31
- package/build/moneyInputField/Chevron.mjs.map +0 -1
- package/build/moneyInputField/CurrencySelector.js +0 -160
- package/build/moneyInputField/CurrencySelector.js.map +0 -1
- package/build/moneyInputField/CurrencySelector.mjs +0 -157
- package/build/moneyInputField/CurrencySelector.mjs.map +0 -1
- package/build/moneyInputField/MoneyInputField.js +0 -113
- package/build/moneyInputField/MoneyInputField.js.map +0 -1
- package/build/moneyInputField/MoneyInputField.messages.js +0 -17
- package/build/moneyInputField/MoneyInputField.messages.js.map +0 -1
- package/build/moneyInputField/MoneyInputField.messages.mjs +0 -13
- package/build/moneyInputField/MoneyInputField.messages.mjs.map +0 -1
- package/build/moneyInputField/MoneyInputField.mjs +0 -109
- package/build/moneyInputField/MoneyInputField.mjs.map +0 -1
- package/build/moneyInputField/useFocus.js +0 -37
- package/build/moneyInputField/useFocus.js.map +0 -1
- package/build/moneyInputField/useFocus.mjs +0 -35
- package/build/moneyInputField/useFocus.mjs.map +0 -1
- package/build/moneyInputField/useInputStyle.js +0 -71
- package/build/moneyInputField/useInputStyle.js.map +0 -1
- package/build/moneyInputField/useInputStyle.mjs +0 -69
- package/build/moneyInputField/useInputStyle.mjs.map +0 -1
- package/build/moneyInputField/utils.js +0 -87
- package/build/moneyInputField/utils.js.map +0 -1
- package/build/moneyInputField/utils.mjs +0 -78
- package/build/moneyInputField/utils.mjs.map +0 -1
- package/build/styles/avatarView/NotificationDot.css +0 -20
- package/build/styles/moneyInputField/AmountInput.css +0 -32
- package/build/styles/moneyInputField/Chevron.css +0 -12
- package/build/styles/moneyInputField/CurrencySelector.css +0 -6
- package/build/styles/moneyInputField/MoneyInputField.css +0 -58
- package/build/types/avatarView/NotificationDot.d.ts +0 -8
- package/build/types/avatarView/NotificationDot.d.ts.map +0 -1
- package/build/types/moneyInputField/AmountInput.d.ts +0 -13
- package/build/types/moneyInputField/AmountInput.d.ts.map +0 -1
- package/build/types/moneyInputField/AnimatedNumber.d.ts +0 -9
- package/build/types/moneyInputField/AnimatedNumber.d.ts.map +0 -1
- package/build/types/moneyInputField/Chevron.d.ts +0 -6
- package/build/types/moneyInputField/Chevron.d.ts.map +0 -1
- package/build/types/moneyInputField/CurrencySelector.d.ts +0 -30
- package/build/types/moneyInputField/CurrencySelector.d.ts.map +0 -1
- package/build/types/moneyInputField/MoneyInputField.d.ts +0 -30
- package/build/types/moneyInputField/MoneyInputField.d.ts.map +0 -1
- package/build/types/moneyInputField/MoneyInputField.messages.d.ts +0 -12
- package/build/types/moneyInputField/MoneyInputField.messages.d.ts.map +0 -1
- package/build/types/moneyInputField/index.d.ts +0 -3
- package/build/types/moneyInputField/index.d.ts.map +0 -1
- package/build/types/moneyInputField/useFocus.d.ts +0 -7
- package/build/types/moneyInputField/useFocus.d.ts.map +0 -1
- package/build/types/moneyInputField/useInputStyle.d.ts +0 -10
- package/build/types/moneyInputField/useInputStyle.d.ts.map +0 -1
- package/build/types/moneyInputField/useSelectionRange.d.ts +0 -10
- package/build/types/moneyInputField/useSelectionRange.d.ts.map +0 -1
- package/build/types/moneyInputField/utils.d.ts +0 -22
- package/build/types/moneyInputField/utils.d.ts.map +0 -1
- package/src/avatarView/NotificationDot.css +0 -20
- package/src/avatarView/NotificationDot.less +0 -24
- package/src/avatarView/NotificationDot.tsx +0 -35
- package/src/moneyInputField/AmountInput.css +0 -32
- package/src/moneyInputField/AmountInput.less +0 -43
- package/src/moneyInputField/AmountInput.tsx +0 -355
- package/src/moneyInputField/AnimatedNumber.tsx +0 -40
- package/src/moneyInputField/Chevron.css +0 -12
- package/src/moneyInputField/Chevron.less +0 -13
- package/src/moneyInputField/Chevron.tsx +0 -35
- package/src/moneyInputField/CurrencySelector.css +0 -6
- package/src/moneyInputField/CurrencySelector.less +0 -7
- package/src/moneyInputField/CurrencySelector.tsx +0 -219
- package/src/moneyInputField/MoneyInputField.css +0 -58
- package/src/moneyInputField/MoneyInputField.less +0 -13
- package/src/moneyInputField/MoneyInputField.messages.ts +0 -13
- package/src/moneyInputField/MoneyInputField.story.tsx +0 -188
- package/src/moneyInputField/MoneyInputField.tsx +0 -123
- package/src/moneyInputField/index.ts +0 -2
- package/src/moneyInputField/useFocus.ts +0 -35
- package/src/moneyInputField/useInputStyle.ts +0 -85
- package/src/moneyInputField/useSelectionRange.ts +0 -23
- package/src/moneyInputField/utils.spec.ts +0 -114
- package/src/moneyInputField/utils.ts +0 -116
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
.wds-amount-input-container {
|
|
2
|
-
width: 100%;
|
|
3
|
-
}
|
|
4
|
-
.wds-amount-input-input-container {
|
|
5
|
-
display: flex;
|
|
6
|
-
justify-content: right;
|
|
7
|
-
width: 100%;
|
|
8
|
-
transition: font-size 0.4s cubic-bezier(0.3, 0, 0.1, 1), height 0.4s cubic-bezier(0.3, 0, 0.1, 1), margin-top 0.4s cubic-bezier(0.3, 0, 0.1, 1), color 0.4s ease;
|
|
9
|
-
color: var(--color-interactive-primary);
|
|
10
|
-
overflow: hidden;
|
|
11
|
-
margin-bottom: 0 !important;
|
|
12
|
-
}
|
|
13
|
-
@media (prefers-reduced-motion: reduce) {
|
|
14
|
-
.wds-amount-input-input-container {
|
|
15
|
-
transition: none;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
.wds-amount-input-input {
|
|
19
|
-
border: none;
|
|
20
|
-
outline: none;
|
|
21
|
-
flex-grow: 1;
|
|
22
|
-
text-align: right;
|
|
23
|
-
background-color: transparent;
|
|
24
|
-
}
|
|
25
|
-
.wds-amount-input-input:focus-visible {
|
|
26
|
-
outline: none;
|
|
27
|
-
}
|
|
28
|
-
.wds-amount-input-placeholder {
|
|
29
|
-
flex-grow: 0;
|
|
30
|
-
display: flex;
|
|
31
|
-
align-items: center;
|
|
32
|
-
}
|
|
33
|
-
.wds-currency-selector:disabled {
|
|
34
|
-
opacity: 1 !important;
|
|
35
|
-
cursor: auto !important;
|
|
36
|
-
cursor: initial !important;
|
|
37
|
-
mix-blend-mode: initial !important;
|
|
38
|
-
}
|
|
39
|
-
.wds-chevron-container {
|
|
40
|
-
width: 32px;
|
|
41
|
-
width: var(--size-32);
|
|
42
|
-
overflow: hidden;
|
|
43
|
-
color: var(--color-interactive-primary);
|
|
44
|
-
margin-left: 8px;
|
|
45
|
-
margin-left: var(--size-8);
|
|
46
|
-
transition: width 0.3s ease;
|
|
47
|
-
}
|
|
48
|
-
.wds-chevron-hidden {
|
|
49
|
-
width: 0;
|
|
50
|
-
}
|
|
51
|
-
.wds-money-input-field-currency-selector {
|
|
52
|
-
flex-shrink: 0;
|
|
53
|
-
margin-right: 24px;
|
|
54
|
-
margin-right: var(--size-24);
|
|
55
|
-
}
|
|
56
|
-
.wds-money-input-field-chevron {
|
|
57
|
-
transform: translateY(-5%);
|
|
58
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
@import "./AmountInput.less";
|
|
2
|
-
@import "./CurrencySelector.less";
|
|
3
|
-
@import "./Chevron.less";
|
|
4
|
-
|
|
5
|
-
.wds-money-input-field {
|
|
6
|
-
&-currency-selector {
|
|
7
|
-
flex-shrink: 0;
|
|
8
|
-
margin-right: var(--size-24);
|
|
9
|
-
}
|
|
10
|
-
&-chevron {
|
|
11
|
-
transform: translateY(-5%);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from 'react-intl';
|
|
2
|
-
|
|
3
|
-
export default defineMessages({
|
|
4
|
-
currencySelectorSearchPlaceholder: {
|
|
5
|
-
id: 'neptune.MoneyInputField.currency.search.placeholder',
|
|
6
|
-
defaultMessage: 'Type a currency / country',
|
|
7
|
-
},
|
|
8
|
-
|
|
9
|
-
currencySelectorSelectCurrency: {
|
|
10
|
-
id: 'neptune.MoneyInputField.currency.select.currency',
|
|
11
|
-
defaultMessage: 'Select currency',
|
|
12
|
-
},
|
|
13
|
-
});
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/* eslint-disable jsx-a11y/anchor-is-valid, no-console, jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
|
|
2
|
-
import { Meta } from '@storybook/react-webpack5';
|
|
3
|
-
import MoneyInputField, { Props as MoneyInputFieldProps } from './MoneyInputField';
|
|
4
|
-
import { lorem10 } from '../test-utils';
|
|
5
|
-
import { Sentiment } from '../common';
|
|
6
|
-
import Image from '../image';
|
|
7
|
-
import Link from '../link';
|
|
8
|
-
import Money from '../money';
|
|
9
|
-
import React from 'react';
|
|
10
|
-
|
|
11
|
-
export default {
|
|
12
|
-
title: 'Forms/MoneyInputField',
|
|
13
|
-
component: MoneyInputField,
|
|
14
|
-
} as Meta;
|
|
15
|
-
|
|
16
|
-
const props: MoneyInputFieldProps = {
|
|
17
|
-
label: 'You send',
|
|
18
|
-
currency: 'GBP',
|
|
19
|
-
amount: 1234.56,
|
|
20
|
-
onAmountChange: (amount) => {
|
|
21
|
-
console.log('Amount changed', amount);
|
|
22
|
-
},
|
|
23
|
-
currencySelector: {
|
|
24
|
-
addons: [
|
|
25
|
-
{ asset: <Image src="../avatar-square-dude.webp" alt="" /> },
|
|
26
|
-
{ profileName: 'Test Test' },
|
|
27
|
-
],
|
|
28
|
-
options: [
|
|
29
|
-
{
|
|
30
|
-
title: 'Popular',
|
|
31
|
-
currencies: [
|
|
32
|
-
{ code: 'USD', label: 'US Dollar', keywords: ['dollar', 'us'] },
|
|
33
|
-
{ code: 'AUD', label: 'Australia Dollar', keywords: ['dollar', 'us'] },
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
title: 'Others',
|
|
38
|
-
currencies: [
|
|
39
|
-
{ code: 'GBP', label: 'Pound', keywords: ['british'] },
|
|
40
|
-
{ code: 'EUR', label: 'Euro', keywords: ['euro'] },
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
onOpen: () => {
|
|
45
|
-
console.log('Currency selector opened');
|
|
46
|
-
},
|
|
47
|
-
onSearchChange: (payload) => {
|
|
48
|
-
console.log('Search changed', payload);
|
|
49
|
-
},
|
|
50
|
-
onChange: (currency) => {
|
|
51
|
-
console.log('Currency changed', currency);
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
loading: false,
|
|
55
|
-
inlinePrompt: { message: lorem10, sentiment: Sentiment.POSITIVE },
|
|
56
|
-
showChevron: true,
|
|
57
|
-
autoFocus: true,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const NullAmount = {
|
|
61
|
-
args: props,
|
|
62
|
-
render: (args: MoneyInputFieldProps) => (
|
|
63
|
-
<MoneyInputField
|
|
64
|
-
label={args.label}
|
|
65
|
-
amount={null}
|
|
66
|
-
currency="EUR"
|
|
67
|
-
onAmountChange={args.onAmountChange}
|
|
68
|
-
/>
|
|
69
|
-
),
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const WithInitAmount = {
|
|
73
|
-
args: props,
|
|
74
|
-
render: (args: MoneyInputFieldProps) => {
|
|
75
|
-
const availableBalance = 1500;
|
|
76
|
-
return (
|
|
77
|
-
<MoneyInputField
|
|
78
|
-
label={args.label}
|
|
79
|
-
amount={availableBalance}
|
|
80
|
-
currency="EUR"
|
|
81
|
-
onAmountChange={args.onAmountChange}
|
|
82
|
-
/>
|
|
83
|
-
);
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export const WithLoading = {
|
|
88
|
-
args: props,
|
|
89
|
-
render: (args: MoneyInputFieldProps) => {
|
|
90
|
-
const availableBalance = 1500;
|
|
91
|
-
return (
|
|
92
|
-
<MoneyInputField
|
|
93
|
-
label={args.label}
|
|
94
|
-
amount={availableBalance}
|
|
95
|
-
currency="EUR"
|
|
96
|
-
loading
|
|
97
|
-
onAmountChange={args.onAmountChange}
|
|
98
|
-
/>
|
|
99
|
-
);
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export const WithoutChevron = {
|
|
104
|
-
args: props,
|
|
105
|
-
render: (args: MoneyInputFieldProps) => {
|
|
106
|
-
const availableBalance = 1500;
|
|
107
|
-
return (
|
|
108
|
-
<MoneyInputField
|
|
109
|
-
label={args.label}
|
|
110
|
-
amount={availableBalance}
|
|
111
|
-
currency="EUR"
|
|
112
|
-
showChevron={false}
|
|
113
|
-
onAmountChange={args.onAmountChange}
|
|
114
|
-
/>
|
|
115
|
-
);
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
export const WithCurrencySelector = {
|
|
120
|
-
args: props,
|
|
121
|
-
render: (args: MoneyInputFieldProps) => {
|
|
122
|
-
const availableBalance = 1500;
|
|
123
|
-
return (
|
|
124
|
-
<MoneyInputField
|
|
125
|
-
label={args.label}
|
|
126
|
-
amount={availableBalance}
|
|
127
|
-
currency="EUR"
|
|
128
|
-
currencySelector={args.currencySelector}
|
|
129
|
-
onAmountChange={args.onAmountChange}
|
|
130
|
-
/>
|
|
131
|
-
);
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export const WithInlinePromptNoSentiment = {
|
|
136
|
-
args: props,
|
|
137
|
-
render: (args: MoneyInputFieldProps) => {
|
|
138
|
-
const availableBalance = 1500;
|
|
139
|
-
const [sourceAmount, setSourceAmount] = React.useState(args.amount);
|
|
140
|
-
return (
|
|
141
|
-
<MoneyInputField
|
|
142
|
-
label={args.label}
|
|
143
|
-
amount={sourceAmount}
|
|
144
|
-
currency="EUR"
|
|
145
|
-
currencySelector={args.currencySelector}
|
|
146
|
-
inlinePrompt={{
|
|
147
|
-
message: (
|
|
148
|
-
<>
|
|
149
|
-
{`Available balance `}
|
|
150
|
-
<Link
|
|
151
|
-
onClick={() => {
|
|
152
|
-
setSourceAmount(availableBalance);
|
|
153
|
-
}}
|
|
154
|
-
>
|
|
155
|
-
<Money amount={availableBalance} currency={args.currency} />
|
|
156
|
-
</Link>
|
|
157
|
-
</>
|
|
158
|
-
),
|
|
159
|
-
}}
|
|
160
|
-
onAmountChange={args.onAmountChange}
|
|
161
|
-
/>
|
|
162
|
-
);
|
|
163
|
-
},
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
export const WithInlinePromptSentiment = {
|
|
167
|
-
args: props,
|
|
168
|
-
render: (args: MoneyInputFieldProps) => {
|
|
169
|
-
const availableBalance = 1500;
|
|
170
|
-
return (
|
|
171
|
-
<MoneyInputField
|
|
172
|
-
label={args.label}
|
|
173
|
-
amount={availableBalance}
|
|
174
|
-
currency="EUR"
|
|
175
|
-
currencySelector={args.currencySelector}
|
|
176
|
-
inlinePrompt={args.inlinePrompt}
|
|
177
|
-
onAmountChange={args.onAmountChange}
|
|
178
|
-
/>
|
|
179
|
-
);
|
|
180
|
-
},
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
export const Autofocus = {
|
|
184
|
-
args: props,
|
|
185
|
-
render: (args: MoneyInputFieldProps) => (
|
|
186
|
-
<MoneyInputField {...args} currency="MXN" inlinePrompt={undefined} />
|
|
187
|
-
),
|
|
188
|
-
};
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { Body, Label } from '..';
|
|
2
|
-
import { clsx } from 'clsx';
|
|
3
|
-
import { AnimatePresence, motion } from 'framer-motion';
|
|
4
|
-
import { useId, type ReactNode } from 'react';
|
|
5
|
-
|
|
6
|
-
import { type Props as CurrencySelectorProps, CurrencySelector } from './CurrencySelector';
|
|
7
|
-
import { CommonProps } from '../common';
|
|
8
|
-
import { AmountInput } from './AmountInput';
|
|
9
|
-
import { Chevron } from './Chevron';
|
|
10
|
-
import { InlinePrompt, type InlinePromptProps } from '../prompt/InlinePrompt';
|
|
11
|
-
|
|
12
|
-
type AmountType = number | null;
|
|
13
|
-
export type CurrencyType = string;
|
|
14
|
-
|
|
15
|
-
type DefaultCurrencySelectorInstanceType = Pick<
|
|
16
|
-
CurrencySelectorProps,
|
|
17
|
-
'addons' | 'options' | 'onChange' | 'onOpen' | 'onSearchChange'
|
|
18
|
-
>;
|
|
19
|
-
type CustomCurrencySelectorInstanceType = (props: { id: string; labelId: string }) => ReactNode;
|
|
20
|
-
type CurrencySelectorType =
|
|
21
|
-
| DefaultCurrencySelectorInstanceType
|
|
22
|
-
| CustomCurrencySelectorInstanceType;
|
|
23
|
-
|
|
24
|
-
export type Props = {
|
|
25
|
-
label?: ReactNode;
|
|
26
|
-
currencySelector?: CurrencySelectorType;
|
|
27
|
-
amount?: AmountType;
|
|
28
|
-
currency: CurrencyType;
|
|
29
|
-
inlinePrompt?: {
|
|
30
|
-
sentiment?: InlinePromptProps['sentiment'];
|
|
31
|
-
message: InlinePromptProps['children'];
|
|
32
|
-
};
|
|
33
|
-
showChevron?: boolean;
|
|
34
|
-
autoFocus?: boolean;
|
|
35
|
-
loading?: boolean;
|
|
36
|
-
onAmountChange: (amount: AmountType) => void;
|
|
37
|
-
onFocusChange?: (focused: boolean) => void;
|
|
38
|
-
} & CommonProps;
|
|
39
|
-
|
|
40
|
-
export default function MoneyInputField({
|
|
41
|
-
label,
|
|
42
|
-
currency,
|
|
43
|
-
currencySelector = { options: [] } as DefaultCurrencySelectorInstanceType,
|
|
44
|
-
amount,
|
|
45
|
-
onAmountChange,
|
|
46
|
-
className,
|
|
47
|
-
inlinePrompt,
|
|
48
|
-
showChevron,
|
|
49
|
-
autoFocus,
|
|
50
|
-
loading,
|
|
51
|
-
onFocusChange,
|
|
52
|
-
}: Props) {
|
|
53
|
-
const inputId = useId();
|
|
54
|
-
const labelId = useId();
|
|
55
|
-
const customAlertId = useId();
|
|
56
|
-
const currencyId = useId();
|
|
57
|
-
|
|
58
|
-
const selector =
|
|
59
|
-
typeof currencySelector === 'function' ? (
|
|
60
|
-
currencySelector({ id: currencyId, labelId })
|
|
61
|
-
) : (
|
|
62
|
-
<CurrencySelector
|
|
63
|
-
id={currencyId}
|
|
64
|
-
labelId={labelId}
|
|
65
|
-
currency={currency}
|
|
66
|
-
{...currencySelector}
|
|
67
|
-
/>
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<div className={clsx('wds-money-input-field', className)}>
|
|
72
|
-
<Label id={labelId} htmlFor={inputId} className={clsx('m-b-1', 'font-weight-normal')}>
|
|
73
|
-
{label}
|
|
74
|
-
</Label>
|
|
75
|
-
<div
|
|
76
|
-
className={clsx('d-flex')}
|
|
77
|
-
role="group"
|
|
78
|
-
aria-labelledby={labelId}
|
|
79
|
-
{...(inlinePrompt ? { 'aria-describedby': customAlertId } : {})}
|
|
80
|
-
>
|
|
81
|
-
<div className="wds-money-input-field-currency-selector">{selector}</div>
|
|
82
|
-
<AmountInput
|
|
83
|
-
id={inputId}
|
|
84
|
-
describedById={currencyId}
|
|
85
|
-
amount={amount}
|
|
86
|
-
currency={currency}
|
|
87
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
88
|
-
autoFocus={autoFocus}
|
|
89
|
-
loading={loading}
|
|
90
|
-
onChange={onAmountChange}
|
|
91
|
-
onFocusChange={onFocusChange}
|
|
92
|
-
/>
|
|
93
|
-
<div className={clsx('d-flex align-items-center', 'wds-money-input-field-chevron')}>
|
|
94
|
-
<Chevron shouldShow={Boolean(showChevron)} />
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
<AnimatePresence initial={false}>
|
|
98
|
-
{inlinePrompt && (
|
|
99
|
-
<div className={clsx('d-flex justify-content-end', inlinePrompt && 'm-t-1')}>
|
|
100
|
-
<motion.div
|
|
101
|
-
key={customAlertId}
|
|
102
|
-
initial={{ opacity: 0, height: 0 }}
|
|
103
|
-
animate={{
|
|
104
|
-
opacity: 1,
|
|
105
|
-
height: 'auto',
|
|
106
|
-
transition: { delay: 0.75, duration: 0.3 },
|
|
107
|
-
}}
|
|
108
|
-
exit={{ opacity: 0, height: 0 }}
|
|
109
|
-
>
|
|
110
|
-
{inlinePrompt.sentiment ? (
|
|
111
|
-
<InlinePrompt id={customAlertId} sentiment={inlinePrompt.sentiment}>
|
|
112
|
-
{inlinePrompt.message}
|
|
113
|
-
</InlinePrompt>
|
|
114
|
-
) : (
|
|
115
|
-
<Body>{inlinePrompt.message}</Body>
|
|
116
|
-
)}
|
|
117
|
-
</motion.div>
|
|
118
|
-
</div>
|
|
119
|
-
)}
|
|
120
|
-
</AnimatePresence>
|
|
121
|
-
</div>
|
|
122
|
-
);
|
|
123
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
const focusTimeout = 5 * 1000;
|
|
4
|
-
|
|
5
|
-
export const useFocus = () => {
|
|
6
|
-
const [focus, setFocus] = useState(false);
|
|
7
|
-
const [visualFocus, setVisualFocus] = useState(false);
|
|
8
|
-
const [counter, setCounter] = useState(0);
|
|
9
|
-
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
if (focus) {
|
|
12
|
-
const timeout = setTimeout(() => {
|
|
13
|
-
setVisualFocus(false);
|
|
14
|
-
}, focusTimeout);
|
|
15
|
-
return () => clearTimeout(timeout);
|
|
16
|
-
}
|
|
17
|
-
}, [focus, counter]);
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
focus,
|
|
21
|
-
setFocus: (value: boolean) => {
|
|
22
|
-
setFocus(value);
|
|
23
|
-
if (value) {
|
|
24
|
-
setVisualFocus(true);
|
|
25
|
-
}
|
|
26
|
-
// any call to setFocus should reset the timeout, even if the input was already in focus
|
|
27
|
-
// updating the counter will trigger the useEffect to reset the timeout
|
|
28
|
-
setCounter((prev) => prev + 1);
|
|
29
|
-
},
|
|
30
|
-
visualFocus,
|
|
31
|
-
setVisualFocus: (value: boolean) => {
|
|
32
|
-
setVisualFocus(value);
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
};
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { type CSSProperties, useEffect, useLayoutEffect, useState } from 'react';
|
|
2
|
-
import { Props as MoneyInputFieldProps } from './MoneyInputField';
|
|
3
|
-
|
|
4
|
-
type InputStyleObject = {
|
|
5
|
-
value: string;
|
|
6
|
-
focus: boolean;
|
|
7
|
-
inputElement: HTMLInputElement | null;
|
|
8
|
-
} & Pick<MoneyInputFieldProps, 'loading'>;
|
|
9
|
-
|
|
10
|
-
export const useInputStyle = ({ value, focus, inputElement, loading }: InputStyleObject) => {
|
|
11
|
-
const initialRender = !useTimeout(300);
|
|
12
|
-
const inputWidth = useFirstDefinedValue(inputElement?.clientWidth, [inputElement, value]);
|
|
13
|
-
|
|
14
|
-
const getStyle = (): CSSProperties => {
|
|
15
|
-
const fontSize = getFontSize(value, focus, inputWidth);
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
fontSize,
|
|
19
|
-
height: fontSize,
|
|
20
|
-
// aligns the top of the digit with the currency button
|
|
21
|
-
marginTop: fontSize * -0.19,
|
|
22
|
-
// if the input loads with a pre-filled value, we don't want to animate the font-size immediately
|
|
23
|
-
transition: initialRender ? 'none' : undefined,
|
|
24
|
-
color: loading ? 'var(--color-interactive-secondary)' : undefined,
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const [style, setStyle] = useState(getStyle());
|
|
29
|
-
|
|
30
|
-
useLayoutEffect(() => {
|
|
31
|
-
setStyle(getStyle());
|
|
32
|
-
}, [value, focus, loading, inputWidth]);
|
|
33
|
-
|
|
34
|
-
return style;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
function getFontSize(inputValue: string, isFocused: boolean, inputWidth: number | undefined) {
|
|
38
|
-
const defaultFontSize = 52;
|
|
39
|
-
const focusFontSize = 90;
|
|
40
|
-
const minimumFontSize = 34;
|
|
41
|
-
|
|
42
|
-
let fontSize = isFocused ? focusFontSize : defaultFontSize;
|
|
43
|
-
|
|
44
|
-
if (typeof inputWidth === 'undefined') {
|
|
45
|
-
return fontSize;
|
|
46
|
-
}
|
|
47
|
-
const textLength = inputValue.length;
|
|
48
|
-
const maxCharactersWithoutShrinking = Math.floor(inputWidth / 40);
|
|
49
|
-
|
|
50
|
-
if (textLength > maxCharactersWithoutShrinking) {
|
|
51
|
-
const adjustedSize = Math.round((inputWidth / textLength) * 1.9);
|
|
52
|
-
fontSize = Math.min(fontSize, adjustedSize);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return Math.max(fontSize, minimumFontSize);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const useFirstDefinedValue = (newValue: number | undefined, dependencies: unknown[]) => {
|
|
59
|
-
const [value, setValue] = useState<number | undefined>(newValue);
|
|
60
|
-
|
|
61
|
-
useLayoutEffect(() => {
|
|
62
|
-
if (typeof newValue !== 'undefined' && typeof value === 'undefined') {
|
|
63
|
-
setValue(newValue);
|
|
64
|
-
}
|
|
65
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
|
-
}, [...dependencies, value]);
|
|
67
|
-
|
|
68
|
-
return value;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const useTimeout = (delay: number) => {
|
|
72
|
-
const [ready, setReady] = useState(false);
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
const timeout = setTimeout(() => {
|
|
76
|
-
setReady(true);
|
|
77
|
-
}, delay);
|
|
78
|
-
|
|
79
|
-
return () => {
|
|
80
|
-
clearTimeout(timeout);
|
|
81
|
-
};
|
|
82
|
-
}, [delay]);
|
|
83
|
-
|
|
84
|
-
return ready;
|
|
85
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { type SyntheticEvent, useRef } from 'react';
|
|
2
|
-
|
|
3
|
-
export const useSelectionRange = () => {
|
|
4
|
-
const selection = useRef<{
|
|
5
|
-
selectionStart: number | null;
|
|
6
|
-
selectionEnd: number | null;
|
|
7
|
-
}>();
|
|
8
|
-
|
|
9
|
-
const handleSelect = (e: SyntheticEvent<HTMLInputElement>) => {
|
|
10
|
-
const input = e.target as HTMLInputElement;
|
|
11
|
-
const { selectionStart, selectionEnd } = input;
|
|
12
|
-
selection.current = { selectionStart, selectionEnd };
|
|
13
|
-
};
|
|
14
|
-
const handleSelectionBlur = () => {
|
|
15
|
-
selection.current = undefined;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
selection: selection.current,
|
|
20
|
-
handleSelect,
|
|
21
|
-
handleSelectionBlur,
|
|
22
|
-
};
|
|
23
|
-
};
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getDecimalSeparator,
|
|
3
|
-
getFormattedString,
|
|
4
|
-
getGroupSeparator,
|
|
5
|
-
getUnformattedNumber,
|
|
6
|
-
} from './utils';
|
|
7
|
-
|
|
8
|
-
describe('utils', () => {
|
|
9
|
-
describe('getDecimalSeparator', () => {
|
|
10
|
-
it('gets decimal separator for Spanish', () => {
|
|
11
|
-
expect(getDecimalSeparator('EUR', 'es')).toBe(',');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('gets decimal separator for English', () => {
|
|
15
|
-
expect(getDecimalSeparator('EUR', 'en')).toBe('.');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('gets decimal separator for Spanish in HUF', () => {
|
|
19
|
-
expect(getDecimalSeparator('HUF', 'es')).toBe('');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('gets decimal separator for English in HUF', () => {
|
|
23
|
-
expect(getDecimalSeparator('HUF', 'en')).toBe('');
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('getGroupSeparator', () => {
|
|
28
|
-
it('gets group separator for Spanish', () => {
|
|
29
|
-
expect(getGroupSeparator('EUR', 'es')).toBe('.');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('gets group separator for English', () => {
|
|
33
|
-
expect(getGroupSeparator('EUR', 'en')).toBe(',');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('gets group separator for French', () => {
|
|
37
|
-
expect(getGroupSeparator('EUR', 'fr')).toBe(' ');
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe('getUnformattedNumber', () => {
|
|
42
|
-
it('can turn a Spanish string into a number', () => {
|
|
43
|
-
expect(
|
|
44
|
-
getUnformattedNumber({
|
|
45
|
-
value: '123.456,00',
|
|
46
|
-
currency: 'EUR',
|
|
47
|
-
locale: 'es',
|
|
48
|
-
}),
|
|
49
|
-
).toBe(123456);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('can turn a French string into a number', () => {
|
|
53
|
-
expect(
|
|
54
|
-
getUnformattedNumber({
|
|
55
|
-
value: '1 234 567,45',
|
|
56
|
-
currency: 'EUR',
|
|
57
|
-
locale: 'fr',
|
|
58
|
-
}),
|
|
59
|
-
).toBe(1234567.45);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('can turn a English string into a number', () => {
|
|
63
|
-
expect(
|
|
64
|
-
getUnformattedNumber({
|
|
65
|
-
value: '123,456.78',
|
|
66
|
-
currency: 'EUR',
|
|
67
|
-
locale: 'en',
|
|
68
|
-
}),
|
|
69
|
-
).toBe(123456.78);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('can turn a Magyar string into a number', () => {
|
|
73
|
-
expect(
|
|
74
|
-
getUnformattedNumber({
|
|
75
|
-
value: '11 000 000',
|
|
76
|
-
currency: 'HUF',
|
|
77
|
-
locale: 'hu',
|
|
78
|
-
}),
|
|
79
|
-
).toBe(11000000);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('getFormattedString', () => {
|
|
84
|
-
it('can turn a number into a Spanish string', () => {
|
|
85
|
-
expect(
|
|
86
|
-
getFormattedString({
|
|
87
|
-
value: 123456.45,
|
|
88
|
-
currency: 'EUR',
|
|
89
|
-
locale: 'es',
|
|
90
|
-
}),
|
|
91
|
-
).toBe('123.456,45');
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('can turn a number into a French string', () => {
|
|
95
|
-
expect(
|
|
96
|
-
getFormattedString({
|
|
97
|
-
value: 1234567.45,
|
|
98
|
-
currency: 'EUR',
|
|
99
|
-
locale: 'fr',
|
|
100
|
-
}),
|
|
101
|
-
).toBe('1 234 567,45');
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('can turn a number into a English string', () => {
|
|
105
|
-
expect(
|
|
106
|
-
getFormattedString({
|
|
107
|
-
value: 123456.78,
|
|
108
|
-
currency: 'EUR',
|
|
109
|
-
locale: 'en',
|
|
110
|
-
}),
|
|
111
|
-
).toBe('123,456.78');
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
});
|