@transferwise/components 46.141.0 → 46.142.0
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 +15 -1
- package/build/avatarLayout/AvatarLayout.js.map +1 -1
- package/build/avatarLayout/AvatarLayout.mjs +15 -1
- package/build/avatarLayout/AvatarLayout.mjs.map +1 -1
- package/build/avatarView/AvatarView.js +6 -2
- package/build/avatarView/AvatarView.js.map +1 -1
- package/build/avatarView/AvatarView.mjs +6 -2
- package/build/avatarView/AvatarView.mjs.map +1 -1
- package/build/avatarView/Dot.js +8 -0
- package/build/avatarView/Dot.js.map +1 -1
- package/build/avatarView/Dot.mjs +8 -0
- package/build/avatarView/Dot.mjs.map +1 -1
- package/build/common/circle/Circle.js +6 -2
- package/build/common/circle/Circle.js.map +1 -1
- package/build/common/circle/Circle.mjs +6 -2
- package/build/common/circle/Circle.mjs.map +1 -1
- package/build/expressiveMoneyInput/amountInput/AmountInput.js +1 -1
- package/build/expressiveMoneyInput/amountInput/AmountInput.js.map +1 -1
- package/build/expressiveMoneyInput/amountInput/AmountInput.mjs +1 -1
- package/build/expressiveMoneyInput/amountInput/AmountInput.mjs.map +1 -1
- package/build/field/Field.js +63 -32
- package/build/field/Field.js.map +1 -1
- package/build/field/Field.messages.js +14 -0
- package/build/field/Field.messages.js.map +1 -0
- package/build/field/Field.messages.mjs +10 -0
- package/build/field/Field.messages.mjs.map +1 -0
- package/build/field/Field.mjs +65 -34
- package/build/field/Field.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/inputs/TextArea.js +5 -0
- package/build/inputs/TextArea.js.map +1 -1
- package/build/inputs/TextArea.mjs +6 -1
- package/build/inputs/TextArea.mjs.map +1 -1
- package/build/inputs/contexts.js +16 -0
- package/build/inputs/contexts.js.map +1 -1
- package/build/inputs/contexts.mjs +16 -2
- package/build/inputs/contexts.mjs.map +1 -1
- package/build/main.css +42 -8
- package/build/styles/avatarView/AvatarView.css +4 -4
- package/build/styles/avatarView/Dot.css +4 -4
- package/build/styles/css/neptune.css +15 -1
- package/build/styles/expressiveMoneyInput/ExpressiveMoneyInput.css +2 -0
- package/build/styles/expressiveMoneyInput/amountInput/AmountInput.css +2 -0
- package/build/styles/field/Field.css +19 -3
- package/build/styles/main.css +42 -8
- package/build/styles/styles/less/neptune.css +15 -1
- package/build/types/avatarView/AvatarView.d.ts +1 -1
- package/build/types/avatarView/AvatarView.d.ts.map +1 -1
- package/build/types/avatarView/Dot.d.ts.map +1 -1
- package/build/types/common/circle/Circle.d.ts +1 -1
- package/build/types/common/circle/Circle.d.ts.map +1 -1
- package/build/types/field/Field.d.ts.map +1 -1
- package/build/types/field/Field.messages.d.ts +8 -0
- package/build/types/field/Field.messages.d.ts.map +1 -0
- package/build/types/inputs/TextArea.d.ts.map +1 -1
- package/build/types/inputs/contexts.d.ts +6 -0
- package/build/types/inputs/contexts.d.ts.map +1 -1
- package/build/types/test-utils/index.d.ts +2 -0
- package/build/types/test-utils/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/avatarLayout/AvatarLayout.story.tsx +1 -1
- package/src/avatarLayout/AvatarLayout.tsx +4 -0
- package/src/avatarView/AvatarView.css +4 -4
- package/src/avatarView/AvatarView.story.tsx +17 -13
- package/src/avatarView/AvatarView.tsx +5 -1
- package/src/avatarView/Dot.css +4 -4
- package/src/avatarView/Dot.less +6 -6
- package/src/avatarView/Dot.tsx +2 -0
- package/src/common/circle/Circle.tsx +5 -1
- package/src/expressiveMoneyInput/ExpressiveMoneyInput.css +2 -0
- package/src/expressiveMoneyInput/ExpressiveMoneyInput.test.story.tsx +43 -0
- package/src/expressiveMoneyInput/amountInput/AmountInput.css +2 -0
- package/src/expressiveMoneyInput/amountInput/AmountInput.less +2 -0
- package/src/expressiveMoneyInput/amountInput/AmountInput.tsx +1 -1
- package/src/field/Field.css +19 -3
- package/src/field/Field.less +17 -3
- package/src/field/Field.messages.ts +8 -0
- package/src/field/Field.story.tsx +5 -1
- package/src/field/Field.test.tsx +90 -0
- package/src/field/Field.tsx +84 -37
- package/src/i18n/en.json +1 -0
- package/src/inputs/TextArea.story.tsx +97 -0
- package/src/inputs/TextArea.test.story.tsx +142 -0
- package/src/inputs/TextArea.tsx +7 -2
- package/src/inputs/contexts.tsx +18 -1
- package/src/main.css +42 -8
- package/src/styles/less/core/_typography.less +28 -6
- package/src/styles/less/neptune.css +15 -1
- package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.story.tsx +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/test-utils/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAM,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,MAAM,EAAc,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAMxD;;;;GAIG;AACH,iBAAS,YAAY,CACnB,EAAE,EAAE,YAAY,EAChB,EAAE,MAAuB,EAAE,QAAa,EAAE,GAAG,aAAa,EAAE
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/test-utils/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAM,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,MAAM,EAAc,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAMxD;;;;GAIG;AACH,iBAAS,YAAY,CACnB,EAAE,EAAE,YAAY,EAChB,EAAE,MAAuB,EAAE,QAAa,EAAE,GAAG,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAK,GAChE,UAAU,CAAC,OAAO,MAAM,CAAC,CAK3B;AAED;;;GAGG;AACH,iBAAS,gBAAgB,CACvB,QAAQ,EAAE,MAAM,OAAO,EACvB,EAAE,MAAuB,EAAE,QAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAK,uEAKhD;AAED,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,YAAY,IAAI,MAAM,EAAE,gBAAgB,IAAI,UAAU,EAAE,SAAS,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "46.
|
|
3
|
+
"version": "46.142.0",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"storybook-addon-tag-badges": "^3.1.0",
|
|
92
92
|
"storybook-addon-test-codegen": "^3.0.1",
|
|
93
93
|
"@transferwise/less-config": "3.1.2",
|
|
94
|
-
"@transferwise/neptune-css": "14.27.
|
|
94
|
+
"@transferwise/neptune-css": "14.27.2",
|
|
95
95
|
"@wise/components-theming": "1.10.2",
|
|
96
96
|
"@wise/wds-configs": "0.0.0"
|
|
97
97
|
},
|
|
@@ -13,7 +13,7 @@ export default {
|
|
|
13
13
|
|
|
14
14
|
type Story = StoryObj<typeof AvatarLayout>;
|
|
15
15
|
|
|
16
|
-
const sizes: AvatarLayoutProps['size'][] = [16, 24, 32, 40, 48, 56, 72];
|
|
16
|
+
const sizes: AvatarLayoutProps['size'][] = [16, 24, 32, 40, 48, 56, 72, 88, 96];
|
|
17
17
|
|
|
18
18
|
export const Diagonal: Story = {
|
|
19
19
|
render: () => (
|
|
@@ -94,6 +94,8 @@ const DIAGONAL_LAYOUT_STYLE_CONFIG = {
|
|
|
94
94
|
48: { avatarSize: 30, offset: 3.5, fontSize: 14, iconSize: 16.87 },
|
|
95
95
|
56: { avatarSize: 34, offset: 5, fontSize: 14, iconSize: 19.12 },
|
|
96
96
|
72: { avatarSize: 44, offset: 6, fontSize: 22, iconSize: 22 },
|
|
97
|
+
88: { avatarSize: 54, offset: 7, fontSize: 26, iconSize: 27 },
|
|
98
|
+
96: { avatarSize: 58, offset: 8, fontSize: 28, iconSize: 29 },
|
|
97
99
|
};
|
|
98
100
|
|
|
99
101
|
/** Horizontal layout have custom offset between avatars */
|
|
@@ -105,4 +107,6 @@ const HORIZONTAL_LAYOUT_OFFSET = {
|
|
|
105
107
|
48: 4,
|
|
106
108
|
56: 6,
|
|
107
109
|
72: 8,
|
|
110
|
+
88: 10,
|
|
111
|
+
96: 10,
|
|
108
112
|
};
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
display: inline-block;
|
|
5
5
|
}
|
|
6
6
|
.np-dot-mask {
|
|
7
|
-
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
8
|
-
mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
9
|
-
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
10
|
-
mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
7
|
+
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
8
|
+
mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
9
|
+
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
10
|
+
mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
11
11
|
}
|
|
12
12
|
.np-dot-badge {
|
|
13
13
|
position: absolute;
|
|
@@ -30,7 +30,7 @@ type Story = StoryObj<typeof AvatarView>;
|
|
|
30
30
|
|
|
31
31
|
const profileName1 = 'Wolter White';
|
|
32
32
|
const profileName2 = 'Tyler Durden';
|
|
33
|
-
const sizes: AvatarViewProps['size'][] = [16, 24, 32, 40, 48, 56, 72];
|
|
33
|
+
const sizes: AvatarViewProps['size'][] = [16, 24, 32, 40, 48, 56, 72, 88, 96];
|
|
34
34
|
|
|
35
35
|
const withComponentGrid = (Story: () => JSX.Element) => (
|
|
36
36
|
<div
|
|
@@ -97,15 +97,19 @@ export const Badge: Story = {
|
|
|
97
97
|
gap: '1em',
|
|
98
98
|
display: 'grid',
|
|
99
99
|
justifyContent: 'space-between',
|
|
100
|
-
gridTemplate:
|
|
100
|
+
gridTemplate: `auto auto / repeat(${sizes.length}, min-content)`,
|
|
101
101
|
}}
|
|
102
102
|
>
|
|
103
103
|
{sizes.map((size) => (
|
|
104
104
|
<Body type="body-large-bold">{size}</Body>
|
|
105
105
|
))}
|
|
106
106
|
{sizes.map((size, index) => (
|
|
107
|
-
<AvatarView
|
|
108
|
-
{
|
|
107
|
+
<AvatarView
|
|
108
|
+
key={size}
|
|
109
|
+
size={size}
|
|
110
|
+
badge={{ flagCode: currencies[index % currencies.length] }}
|
|
111
|
+
>
|
|
112
|
+
{icons[index % icons.length]}
|
|
109
113
|
</AvatarView>
|
|
110
114
|
))}
|
|
111
115
|
|
|
@@ -129,43 +133,43 @@ export const Badge: Story = {
|
|
|
129
133
|
|
|
130
134
|
{sizes.map((size, index) => (
|
|
131
135
|
<AvatarView key={size} size={size} badge={{ imgSrc: '../tapestry-01.png' }}>
|
|
132
|
-
{icons[index]}
|
|
136
|
+
{icons[index % icons.length]}
|
|
133
137
|
</AvatarView>
|
|
134
138
|
))}
|
|
135
139
|
|
|
136
140
|
{sizes.map((size, index) => (
|
|
137
141
|
<AvatarView key={size} size={size} badge={{ status: 'warning' }}>
|
|
138
|
-
{icons[index]}
|
|
142
|
+
{icons[index % icons.length]}
|
|
139
143
|
</AvatarView>
|
|
140
144
|
))}
|
|
141
145
|
|
|
142
146
|
{sizes.map((size, index) => (
|
|
143
147
|
<AvatarView key={size} size={size} badge={{ status: 'neutral' }}>
|
|
144
|
-
{icons[index]}
|
|
148
|
+
{icons[index % icons.length]}
|
|
145
149
|
</AvatarView>
|
|
146
150
|
))}
|
|
147
151
|
|
|
148
152
|
{sizes.map((size, index) => (
|
|
149
153
|
<AvatarView key={size} size={size} badge={{ status: 'negative' }}>
|
|
150
|
-
{icons[index]}
|
|
154
|
+
{icons[index % icons.length]}
|
|
151
155
|
</AvatarView>
|
|
152
156
|
))}
|
|
153
157
|
|
|
154
158
|
{sizes.map((size, index) => (
|
|
155
159
|
<AvatarView key={size} size={size} badge={{ icon: <FastFlag /> }}>
|
|
156
|
-
{icons[index]}
|
|
160
|
+
{icons[index % icons.length]}
|
|
157
161
|
</AvatarView>
|
|
158
162
|
))}
|
|
159
163
|
|
|
160
164
|
{sizes.map((size, index) => (
|
|
161
165
|
<AvatarView key={size} size={size} badge={{ type: 'reference' }}>
|
|
162
|
-
{icons[index]}
|
|
166
|
+
{icons[index % icons.length]}
|
|
163
167
|
</AvatarView>
|
|
164
168
|
))}
|
|
165
169
|
|
|
166
170
|
{sizes.map((size, index) => (
|
|
167
171
|
<AvatarView key={size} size={size} badge={{ type: 'action' }}>
|
|
168
|
-
{icons[index]}
|
|
172
|
+
{icons[index % icons.length]}
|
|
169
173
|
</AvatarView>
|
|
170
174
|
))}
|
|
171
175
|
|
|
@@ -322,7 +326,7 @@ export const Images: Story = {
|
|
|
322
326
|
gap: '1em',
|
|
323
327
|
display: 'grid',
|
|
324
328
|
justifyContent: 'space-between',
|
|
325
|
-
gridTemplate:
|
|
329
|
+
gridTemplate: `auto auto / repeat(${sizes.length}, min-content)`,
|
|
326
330
|
}}
|
|
327
331
|
>
|
|
328
332
|
{sizes.map((size) => (
|
|
@@ -376,7 +380,7 @@ export const Profiles: Story = {
|
|
|
376
380
|
gap: '1em',
|
|
377
381
|
display: 'grid',
|
|
378
382
|
justifyContent: 'space-between',
|
|
379
|
-
gridTemplate:
|
|
383
|
+
gridTemplate: `auto auto / repeat(${sizes.length}, min-content)`,
|
|
380
384
|
}}
|
|
381
385
|
>
|
|
382
386
|
{sizes.map((size) => (
|
|
@@ -25,7 +25,7 @@ export type Props = {
|
|
|
25
25
|
*/
|
|
26
26
|
profileName?: string | null;
|
|
27
27
|
profileType?: ProfileTypeBusiness | ProfileTypePersonal;
|
|
28
|
-
size?: 16 | 24 | 32 | 40 | 48 | 56 | 72;
|
|
28
|
+
size?: 16 | 24 | 32 | 40 | 48 | 56 | 72 | 88 | 96;
|
|
29
29
|
badge?: AvatarViewBadgeProps;
|
|
30
30
|
interactive?: boolean;
|
|
31
31
|
selected?: boolean;
|
|
@@ -92,6 +92,8 @@ const MAP_BADGE_ASSET_SIZE = {
|
|
|
92
92
|
48: 16,
|
|
93
93
|
56: 24,
|
|
94
94
|
72: 24,
|
|
95
|
+
88: 24,
|
|
96
|
+
96: 24,
|
|
95
97
|
} satisfies Record<number, BadgeAssetsProps['size']>;
|
|
96
98
|
|
|
97
99
|
/** Border width for `selected` state determined by avatar size */
|
|
@@ -103,6 +105,8 @@ const MAP_SELECTED_BORDER_WIDTH = {
|
|
|
103
105
|
48: 2,
|
|
104
106
|
56: 2,
|
|
105
107
|
72: 2,
|
|
108
|
+
88: 2,
|
|
109
|
+
96: 2,
|
|
106
110
|
};
|
|
107
111
|
|
|
108
112
|
/** Certain sizes of AvatarView has a custom offset for badge */
|
package/src/avatarView/Dot.css
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
display: inline-block;
|
|
5
5
|
}
|
|
6
6
|
.np-dot-mask {
|
|
7
|
-
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
8
|
-
mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
9
|
-
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
10
|
-
mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black 0);
|
|
7
|
+
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
8
|
+
mask-image: radial-gradient(circle at bottom calc(100% - (var(--np-dot-size) / 2)) left calc(100% - (var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
9
|
+
-webkit-mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
10
|
+
mask-image: radial-gradient(circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left calc(100% - calc(var(--np-dot-size) / 2)), transparent 0, transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)), black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px));
|
|
11
11
|
}
|
|
12
12
|
.np-dot-badge {
|
|
13
13
|
position: absolute;
|
package/src/avatarView/Dot.less
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
&-mask {
|
|
7
7
|
mask-image: radial-gradient(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
circle at bottom calc(100% - calc(var(--np-dot-size) / 2)) left
|
|
9
|
+
calc(100% - calc(var(--np-dot-size) / 2)),
|
|
10
|
+
transparent 0,
|
|
11
|
+
transparent calc(var(--np-dot-size) / 2 + var(--np-dot-offset)),
|
|
12
|
+
black calc(var(--np-dot-size) / 2 + var(--np-dot-offset) + 0.5px)
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
height: var(--np-dot-size);
|
|
20
20
|
border-radius: var(--radius-full);
|
|
21
21
|
right: 0;
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
&-notification {
|
|
24
24
|
background-color: var(--color-sentiment-negative);
|
|
25
25
|
}
|
package/src/avatarView/Dot.tsx
CHANGED
|
@@ -18,6 +18,8 @@ const MAP_STYLE_CONFIG = {
|
|
|
18
18
|
48: { size: 14, offset: 2 },
|
|
19
19
|
56: { size: 16, offset: 3 },
|
|
20
20
|
72: { size: 20, offset: 3 },
|
|
21
|
+
88: { size: 24, offset: 4 },
|
|
22
|
+
96: { size: 24, offset: 4 },
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
export default function Dot({ children, avatarSize = 48, variant = 'notification' }: DotProps) {
|
|
@@ -3,7 +3,7 @@ import { clsx } from 'clsx';
|
|
|
3
3
|
import { useMedia } from '../hooks/useMedia';
|
|
4
4
|
import { Breakpoint } from '../propsValues/breakpoint';
|
|
5
5
|
|
|
6
|
-
export type ShapeSize = 16 | 24 | 32 | 40 | 48 | 56 | 72;
|
|
6
|
+
export type ShapeSize = 16 | 24 | 32 | 40 | 48 | 56 | 72 | 88 | 96;
|
|
7
7
|
|
|
8
8
|
export type Props = {
|
|
9
9
|
/**
|
|
@@ -33,6 +33,8 @@ const MAP_ICON_SIZE = {
|
|
|
33
33
|
48: 24,
|
|
34
34
|
56: 28,
|
|
35
35
|
72: 36,
|
|
36
|
+
88: 44,
|
|
37
|
+
96: 48,
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
/**
|
|
@@ -48,6 +50,8 @@ const MAP_FONT_SIZE = {
|
|
|
48
50
|
48: 22,
|
|
49
51
|
56: 26,
|
|
50
52
|
72: 30,
|
|
53
|
+
88: 36,
|
|
54
|
+
96: 40,
|
|
51
55
|
};
|
|
52
56
|
|
|
53
57
|
const Circle = forwardRef(function Circle(
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
flex-grow: 1;
|
|
22
22
|
text-align: right;
|
|
23
23
|
background-color: transparent;
|
|
24
|
+
line-height: inherit;
|
|
24
25
|
}
|
|
25
26
|
.wds-amount-input-input:focus-visible {
|
|
26
27
|
outline: none;
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
flex-grow: 0;
|
|
30
31
|
display: flex;
|
|
31
32
|
align-items: center;
|
|
33
|
+
line-height: inherit;
|
|
32
34
|
}
|
|
33
35
|
.wds-currency-selector:disabled {
|
|
34
36
|
opacity: 1 !important;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { fn } from 'storybook/test';
|
|
2
3
|
import ExpressiveMoneyInput, { Props as ExpressiveMoneyInputProps } from './ExpressiveMoneyInput';
|
|
3
4
|
|
|
4
5
|
const meta: Meta<typeof ExpressiveMoneyInput> = {
|
|
@@ -21,3 +22,45 @@ export const WithAutofocus: Story = {
|
|
|
21
22
|
autoFocus: true,
|
|
22
23
|
},
|
|
23
24
|
};
|
|
25
|
+
|
|
26
|
+
const locales = [
|
|
27
|
+
{ lang: 'en', label: 'English', currency: 'GBP' },
|
|
28
|
+
{ lang: 'cs', label: 'Czech', currency: 'CZK' },
|
|
29
|
+
{ lang: 'de', label: 'German', currency: 'EUR' },
|
|
30
|
+
{ lang: 'es', label: 'Spanish', currency: 'EUR' },
|
|
31
|
+
{ lang: 'fr', label: 'French', currency: 'EUR' },
|
|
32
|
+
{ lang: 'hu', label: 'Hungarian', currency: 'HUF', supportsDecimals: false },
|
|
33
|
+
{ lang: 'id', label: 'Indonesian', currency: 'IDR', supportsDecimals: false },
|
|
34
|
+
{ lang: 'it', label: 'Italian', currency: 'EUR' },
|
|
35
|
+
{ lang: 'ja', label: 'Japanese', currency: 'JPY', supportsDecimals: false },
|
|
36
|
+
{ lang: 'nl', label: 'Dutch', currency: 'EUR' },
|
|
37
|
+
{ lang: 'pl', label: 'Polish', currency: 'PLN' },
|
|
38
|
+
{ lang: 'pt', label: 'Portuguese', currency: 'EUR' },
|
|
39
|
+
{ lang: 'ro', label: 'Romanian', currency: 'RON' },
|
|
40
|
+
{ lang: 'ru', label: 'Russian', currency: 'RUB' },
|
|
41
|
+
{ lang: 'th', label: 'Thai', currency: 'THB' },
|
|
42
|
+
{ lang: 'tr', label: 'Turkish', currency: 'TRY' },
|
|
43
|
+
{ lang: 'uk', label: 'Ukrainian', currency: 'UAH' },
|
|
44
|
+
{ lang: 'zh-CN', label: 'Simplified Chinese', currency: 'CNY' },
|
|
45
|
+
{ lang: 'zh-HK', label: 'Traditional Chinese', currency: 'HKD' },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Verifies that the .wds-text-display--forced class correctly overrides locale-specific
|
|
50
|
+
* font restrictions (ja, zh-HK, zh-CN, th) so amounts render in Wise Sans across all
|
|
51
|
+
* supported locales. Each row represents a different language context.
|
|
52
|
+
*/
|
|
53
|
+
export const LocaleFontOverride = () => (
|
|
54
|
+
<>
|
|
55
|
+
{locales.map(({ lang, label, currency, supportsDecimals = true }) => (
|
|
56
|
+
<div key={lang} lang={lang} className="m-b-4">
|
|
57
|
+
<ExpressiveMoneyInput
|
|
58
|
+
label={`${label} locale (${lang})`}
|
|
59
|
+
currency={currency}
|
|
60
|
+
amount={supportsDecimals ? 1234.56 : 123456}
|
|
61
|
+
onAmountChange={fn()}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
))}
|
|
65
|
+
</>
|
|
66
|
+
);
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
flex-grow: 1;
|
|
22
22
|
text-align: right;
|
|
23
23
|
background-color: transparent;
|
|
24
|
+
line-height: inherit;
|
|
24
25
|
}
|
|
25
26
|
.wds-amount-input-input:focus-visible {
|
|
26
27
|
outline: none;
|
|
@@ -29,4 +30,5 @@
|
|
|
29
30
|
flex-grow: 0;
|
|
30
31
|
display: flex;
|
|
31
32
|
align-items: center;
|
|
33
|
+
line-height: inherit;
|
|
32
34
|
}
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
flex-grow: 1;
|
|
30
30
|
text-align: right;
|
|
31
31
|
background-color: transparent;
|
|
32
|
+
line-height: inherit;
|
|
32
33
|
|
|
33
34
|
&:focus-visible {
|
|
34
35
|
outline: none;
|
|
@@ -39,5 +40,6 @@
|
|
|
39
40
|
flex-grow: 0;
|
|
40
41
|
display: flex;
|
|
41
42
|
align-items: center;
|
|
43
|
+
line-height: inherit;
|
|
42
44
|
}
|
|
43
45
|
}
|
|
@@ -298,7 +298,7 @@ export const AmountInput = ({
|
|
|
298
298
|
return (
|
|
299
299
|
<div className="wds-amount-input-container">
|
|
300
300
|
<div
|
|
301
|
-
className={clsx('wds-amount-input-input-container', 'np-text-display-large')}
|
|
301
|
+
className={clsx('wds-amount-input-input-container', 'np-text-display-large--forced')}
|
|
302
302
|
style={style}
|
|
303
303
|
>
|
|
304
304
|
<input
|
package/src/field/Field.css
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
|
-
.np-field-control
|
|
2
|
-
.np-field__prompt {
|
|
1
|
+
.np-field-control {
|
|
3
2
|
margin-top: 4px;
|
|
4
3
|
margin-top: var(--size-4);
|
|
5
4
|
}
|
|
5
|
+
.np-field-validation {
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: flex-start;
|
|
8
|
+
margin-top: 4px;
|
|
9
|
+
margin-top: var(--size-4);
|
|
10
|
+
gap: 8px;
|
|
11
|
+
gap: var(--size-8);
|
|
12
|
+
}
|
|
13
|
+
.np-field-textarea-char-counter {
|
|
14
|
+
min-width: 55px;
|
|
15
|
+
text-align: right;
|
|
16
|
+
margin-left: auto;
|
|
17
|
+
padding: 4px 0;
|
|
18
|
+
padding: var(--size-4) 0;
|
|
19
|
+
color: #768e9c;
|
|
20
|
+
color: var(--color-content-tertiary);
|
|
21
|
+
}
|
|
6
22
|
.np-field .form-group--typeahead[class],
|
|
7
23
|
.np-field .np-checkbox-label[class] {
|
|
8
24
|
margin-bottom: 0;
|
|
9
25
|
}
|
|
10
|
-
.np-field:has(.wds-radio-group) .np-
|
|
26
|
+
.np-field:has(.wds-radio-group) .np-field-validation {
|
|
11
27
|
margin-top: 12px;
|
|
12
28
|
margin-top: var(--size-12);
|
|
13
29
|
}
|
package/src/field/Field.less
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
.np-field {
|
|
2
|
-
&-control
|
|
3
|
-
&__prompt {
|
|
2
|
+
&-control {
|
|
4
3
|
margin-top: var(--size-4);
|
|
5
4
|
}
|
|
6
5
|
|
|
6
|
+
&-validation {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: flex-start;
|
|
9
|
+
margin-top: var(--size-4);
|
|
10
|
+
gap: var(--size-8);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&-textarea-char-counter {
|
|
14
|
+
min-width: 55px;
|
|
15
|
+
text-align: right;
|
|
16
|
+
margin-left: auto;
|
|
17
|
+
padding: var(--size-4) 0;
|
|
18
|
+
color: var(--color-content-tertiary);
|
|
19
|
+
}
|
|
20
|
+
|
|
7
21
|
// @FIXME space between individual fields should be 24px, while some older inputs
|
|
8
22
|
// inject extraneous space.
|
|
9
23
|
.form-group--typeahead[class],
|
|
10
24
|
.np-checkbox-label[class] {
|
|
11
25
|
margin-bottom: 0;
|
|
12
26
|
}
|
|
13
|
-
&:has(.wds-radio-group)
|
|
27
|
+
&:has(.wds-radio-group) &-validation {
|
|
14
28
|
margin-top: var(--size-12);
|
|
15
29
|
}
|
|
16
30
|
}
|
|
@@ -84,7 +84,11 @@ export const Basic = (args: FieldProps) => {
|
|
|
84
84
|
messageIconLabel={args.messageIconLabel}
|
|
85
85
|
messageLoading={args.messageLoading}
|
|
86
86
|
>
|
|
87
|
-
<TextArea
|
|
87
|
+
<TextArea
|
|
88
|
+
maxLength={200}
|
|
89
|
+
value={value}
|
|
90
|
+
onChange={({ target }) => setValue(target.value)}
|
|
91
|
+
/>
|
|
88
92
|
</Field>
|
|
89
93
|
|
|
90
94
|
<Field
|
package/src/field/Field.test.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Info from '../info/Info';
|
|
2
2
|
import { Input } from '../inputs/Input';
|
|
3
|
+
import { TextArea } from '../inputs/TextArea';
|
|
3
4
|
import { mockMatchMedia, render, screen, userEvent } from '../test-utils';
|
|
4
5
|
|
|
5
6
|
import { Field } from './Field';
|
|
@@ -163,4 +164,93 @@ describe('Field', () => {
|
|
|
163
164
|
expect(screen.getByTestId('InlinePrompt_ProcessIndicator')).toBeInTheDocument();
|
|
164
165
|
expect(screen.getByText('Processing your request')).toBeInTheDocument();
|
|
165
166
|
});
|
|
167
|
+
|
|
168
|
+
describe('TextArea character count', () => {
|
|
169
|
+
it('renders counter when TextArea has maxLength', () => {
|
|
170
|
+
render(
|
|
171
|
+
<Field label="Message">
|
|
172
|
+
<TextArea maxLength={200} value="hello" onChange={() => {}} />
|
|
173
|
+
</Field>,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(screen.getByText('5/200')).toBeInTheDocument();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('does not render counter when TextArea has no maxLength', () => {
|
|
180
|
+
render(
|
|
181
|
+
<Field label="Message">
|
|
182
|
+
<TextArea value="hello" onChange={() => {}} />
|
|
183
|
+
</Field>,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
expect(screen.queryByText(/\/\d+/)).not.toBeInTheDocument();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('includes counter id in aria-describedby of the textarea', () => {
|
|
190
|
+
render(
|
|
191
|
+
<Field label="Message">
|
|
192
|
+
<TextArea maxLength={200} value="hello" onChange={() => {}} />
|
|
193
|
+
</Field>,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const textarea = screen.getByRole('textbox');
|
|
197
|
+
const counter = screen.getByText('5/200');
|
|
198
|
+
expect(textarea).toHaveAttribute('aria-describedby', expect.stringContaining(counter.id));
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('does not have role=status below 80% threshold', () => {
|
|
202
|
+
render(
|
|
203
|
+
<Field label="Message">
|
|
204
|
+
<TextArea maxLength={200} value="short" onChange={() => {}} />
|
|
205
|
+
</Field>,
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const counter = screen.getByText('5/200');
|
|
209
|
+
expect(counter).not.toHaveAttribute('role');
|
|
210
|
+
expect(counter).not.toHaveAttribute('aria-live');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('has role=status and aria-live=polite at 80% threshold', () => {
|
|
214
|
+
const value = 'x'.repeat(160);
|
|
215
|
+
render(
|
|
216
|
+
<Field label="Message">
|
|
217
|
+
<TextArea maxLength={200} value={value} onChange={() => {}} />
|
|
218
|
+
</Field>,
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const counter = screen.getByText('160/200');
|
|
222
|
+
expect(counter).toHaveAttribute('role', 'status');
|
|
223
|
+
expect(counter).toHaveAttribute('aria-live', 'polite');
|
|
224
|
+
expect(counter).toHaveAttribute('aria-atomic', 'true');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('updates counter when text changes', () => {
|
|
228
|
+
const { rerender } = render(
|
|
229
|
+
<Field label="Message">
|
|
230
|
+
<TextArea maxLength={200} value="hi" onChange={() => {}} />
|
|
231
|
+
</Field>,
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
expect(screen.getByText('2/200')).toBeInTheDocument();
|
|
235
|
+
|
|
236
|
+
rerender(
|
|
237
|
+
<Field label="Message">
|
|
238
|
+
<TextArea maxLength={200} value="hello world" onChange={() => {}} />
|
|
239
|
+
</Field>,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
expect(screen.getByText('11/200')).toBeInTheDocument();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('provides accessible aria-label on the counter', () => {
|
|
246
|
+
render(
|
|
247
|
+
<Field label="Message">
|
|
248
|
+
<TextArea maxLength={200} value="hello" onChange={() => {}} />
|
|
249
|
+
</Field>,
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
const counter = screen.getByText('5/200');
|
|
253
|
+
expect(counter).toHaveAttribute('aria-label', '5 of 200 characters used');
|
|
254
|
+
});
|
|
255
|
+
});
|
|
166
256
|
});
|