@transferwise/components 46.71.2 → 46.71.4
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/avatar/Avatar.js +7 -2
- package/build/avatar/Avatar.js.map +1 -1
- package/build/avatar/Avatar.mjs +7 -2
- package/build/avatar/Avatar.mjs.map +1 -1
- package/build/badge/Badge.js +13 -2
- package/build/badge/Badge.js.map +1 -1
- package/build/badge/Badge.mjs +13 -2
- package/build/badge/Badge.mjs.map +1 -1
- package/build/circularButton/CircularButton.js +10 -2
- package/build/circularButton/CircularButton.js.map +1 -1
- package/build/circularButton/CircularButton.mjs +10 -2
- package/build/circularButton/CircularButton.mjs.map +1 -1
- package/build/common/circle/Circle.js +29 -0
- package/build/common/circle/Circle.js.map +1 -0
- package/build/common/circle/Circle.mjs +27 -0
- package/build/common/circle/Circle.mjs.map +1 -0
- package/build/inputs/SelectInput.js +38 -5
- package/build/inputs/SelectInput.js.map +1 -1
- package/build/inputs/SelectInput.mjs +38 -5
- package/build/inputs/SelectInput.mjs.map +1 -1
- package/build/main.css +7 -114
- package/build/moneyInput/MoneyInput.js +1 -1
- package/build/moneyInput/MoneyInput.js.map +1 -1
- package/build/moneyInput/MoneyInput.mjs +1 -1
- package/build/moneyInput/MoneyInput.mjs.map +1 -1
- package/build/statusIcon/StatusIcon.js +16 -3
- package/build/statusIcon/StatusIcon.js.map +1 -1
- package/build/statusIcon/StatusIcon.mjs +16 -3
- package/build/statusIcon/StatusIcon.mjs.map +1 -1
- package/build/styles/avatar/Avatar.css +0 -29
- package/build/styles/badge/Badge.css +0 -10
- package/build/styles/circularButton/CircularButton.css +0 -37
- package/build/styles/common/circle/Circle.css +7 -0
- package/build/styles/main.css +7 -114
- package/build/styles/statusIcon/StatusIcon.css +0 -33
- package/build/types/avatar/Avatar.d.ts.map +1 -1
- package/build/types/badge/Badge.d.ts +9 -2
- package/build/types/badge/Badge.d.ts.map +1 -1
- package/build/types/circularButton/CircularButton.d.ts.map +1 -1
- package/build/types/common/circle/Circle.d.ts +34 -0
- package/build/types/common/circle/Circle.d.ts.map +1 -0
- package/build/types/common/circle/index.d.ts +3 -0
- package/build/types/common/circle/index.d.ts.map +1 -0
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/alert/Alert.spec.tsx +3 -1
- package/src/avatar/Avatar.css +0 -29
- package/src/avatar/Avatar.less +0 -12
- package/src/avatar/Avatar.tsx +9 -4
- package/src/avatarWrapper/AvatarWrapper.spec.tsx +3 -1
- package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +22 -11
- package/src/badge/Badge.css +0 -10
- package/src/badge/Badge.less +0 -13
- package/src/badge/Badge.tsx +23 -3
- package/src/checkbox/Checkbox.spec.tsx +3 -1
- package/src/circularButton/CircularButton.css +0 -37
- package/src/circularButton/CircularButton.less +0 -27
- package/src/circularButton/CircularButton.spec.tsx +3 -1
- package/src/circularButton/CircularButton.tsx +10 -3
- package/src/circularButton/__snapshots__/CircularButton.spec.tsx.snap +20 -10
- package/src/common/circle/Circle.css +7 -0
- package/src/common/circle/Circle.less +6 -0
- package/src/common/circle/Circle.story.tsx +86 -0
- package/src/common/circle/Circle.tsx +46 -0
- package/src/common/circle/index.ts +2 -0
- package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +8 -4
- package/src/inlineAlert/InlineAlert.spec.tsx +3 -1
- package/src/inputs/SelectInput.docs.mdx +21 -0
- package/src/inputs/SelectInput.spec.tsx +94 -1
- package/src/inputs/SelectInput.story.tsx +4 -4
- package/src/inputs/SelectInput.tsx +45 -4
- package/src/main.css +7 -114
- package/src/main.less +1 -0
- package/src/moneyInput/MoneyInput.rtl.spec.tsx +10 -1
- package/src/moneyInput/MoneyInput.tsx +1 -1
- package/src/overlayHeader/__snapshots__/OverlayHeader.spec.tsx.snap +4 -2
- package/src/radio/__snapshots__/Radio.rtl.spec.tsx.snap +4 -2
- package/src/statusIcon/StatusIcon.css +0 -33
- package/src/statusIcon/StatusIcon.less +0 -24
- package/src/statusIcon/StatusIcon.spec.tsx +5 -3
- package/src/statusIcon/StatusIcon.tsx +17 -6
- package/src/summary/Summary.spec.tsx +3 -1
- package/src/typeahead/Typeahead.spec.js +3 -0
- package/src/upload/Upload.spec.js +3 -0
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`FlowNavigationAvatar with a name AND profileType FlowNavigationAvatar with a name AND profileType AND avatar url renders the image 1`] = `
|
|
4
4
|
<div
|
|
5
|
-
class="tw-avatar tw-avatar--48 tw-avatar--thumbnail"
|
|
5
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--thumbnail"
|
|
6
|
+
style="--circle-size: 48px;"
|
|
6
7
|
>
|
|
7
8
|
<div
|
|
8
|
-
class="tw-avatar__content"
|
|
9
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
10
|
+
style="--circle-size: 48px;"
|
|
9
11
|
>
|
|
10
12
|
<img
|
|
11
13
|
alt=""
|
|
@@ -17,10 +19,12 @@ exports[`FlowNavigationAvatar with a name AND profileType FlowNavigationAvatar w
|
|
|
17
19
|
|
|
18
20
|
exports[`FlowNavigationAvatar with a name AND profileType FlowNavigationAvatar with a name AND profileType renders as BUSINESS profile type with an icon 1`] = `
|
|
19
21
|
<div
|
|
20
|
-
class="tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
22
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
23
|
+
style="--circle-size: 48px;"
|
|
21
24
|
>
|
|
22
25
|
<div
|
|
23
|
-
class="tw-avatar__content"
|
|
26
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
27
|
+
style="--circle-size: 48px;"
|
|
24
28
|
>
|
|
25
29
|
<span
|
|
26
30
|
class="tw-icon tw-icon-briefcase "
|
|
@@ -46,10 +50,12 @@ exports[`FlowNavigationAvatar with a name AND profileType FlowNavigationAvatar w
|
|
|
46
50
|
|
|
47
51
|
exports[`FlowNavigationAvatar with a name AND profileType FlowNavigationAvatar with a name AND profileType renders as PERSONAL profile type with an icon 1`] = `
|
|
48
52
|
<div
|
|
49
|
-
class="tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
53
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
54
|
+
style="--circle-size: 48px;"
|
|
50
55
|
>
|
|
51
56
|
<div
|
|
52
|
-
class="tw-avatar__content"
|
|
57
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
58
|
+
style="--circle-size: 48px;"
|
|
53
59
|
>
|
|
54
60
|
<span
|
|
55
61
|
class="tw-icon tw-icon-person "
|
|
@@ -81,10 +87,12 @@ exports[`FlowNavigationAvatar with a name AND profileType with a badge url passe
|
|
|
81
87
|
class="tw-badge__children"
|
|
82
88
|
>
|
|
83
89
|
<div
|
|
84
|
-
class="tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
90
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
91
|
+
style="--circle-size: 48px;"
|
|
85
92
|
>
|
|
86
93
|
<div
|
|
87
|
-
class="tw-avatar__content"
|
|
94
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
95
|
+
style="--circle-size: 48px;"
|
|
88
96
|
>
|
|
89
97
|
<span
|
|
90
98
|
class="tw-icon tw-icon-person "
|
|
@@ -108,7 +116,8 @@ exports[`FlowNavigationAvatar with a name AND profileType with a badge url passe
|
|
|
108
116
|
</div>
|
|
109
117
|
</div>
|
|
110
118
|
<div
|
|
111
|
-
class="tw-badge__content"
|
|
119
|
+
class="np-circle d-flex align-items-center justify-content-center tw-badge__content"
|
|
120
|
+
style="--circle-size: 24px;"
|
|
112
121
|
>
|
|
113
122
|
<img
|
|
114
123
|
alt="badge alt text"
|
|
@@ -120,10 +129,12 @@ exports[`FlowNavigationAvatar with a name AND profileType with a badge url passe
|
|
|
120
129
|
|
|
121
130
|
exports[`FlowNavigationAvatar with a name AND profileType with nothing passed renders a personal icon 1`] = `
|
|
122
131
|
<div
|
|
123
|
-
class="tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
132
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--icon"
|
|
133
|
+
style="--circle-size: 48px;"
|
|
124
134
|
>
|
|
125
135
|
<div
|
|
126
|
-
class="tw-avatar__content"
|
|
136
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
137
|
+
style="--circle-size: 48px;"
|
|
127
138
|
>
|
|
128
139
|
<span
|
|
129
140
|
class="tw-icon tw-icon-person "
|
package/src/badge/Badge.css
CHANGED
|
@@ -6,10 +6,6 @@
|
|
|
6
6
|
--badge-mask-offset: calc(var(--badge-size) / 2);
|
|
7
7
|
--badge-border-color: rgba(255, 255, 255, 0.08);
|
|
8
8
|
}
|
|
9
|
-
.tw-badge.tw-badge-md {
|
|
10
|
-
--badge-size: 20px;
|
|
11
|
-
--badge-mask: 2px;
|
|
12
|
-
}
|
|
13
9
|
.tw-badge.tw-badge-lg {
|
|
14
10
|
--badge-size: 24px;
|
|
15
11
|
--badge-mask: 3px;
|
|
@@ -27,16 +23,10 @@
|
|
|
27
23
|
}
|
|
28
24
|
.tw-badge > .tw-badge__content {
|
|
29
25
|
position: absolute;
|
|
30
|
-
width: var(--badge-size);
|
|
31
|
-
height: var(--badge-size);
|
|
32
26
|
bottom: 0;
|
|
33
27
|
right: 0;
|
|
34
28
|
box-sizing: border-box;
|
|
35
|
-
border-radius: 50%;
|
|
36
29
|
text-align: center;
|
|
37
|
-
display: flex;
|
|
38
|
-
align-items: center;
|
|
39
|
-
justify-content: center;
|
|
40
30
|
overflow: hidden;
|
|
41
31
|
-webkit-user-select: none;
|
|
42
32
|
-moz-user-select: none;
|
package/src/badge/Badge.less
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
@import (reference) "../../node_modules/@transferwise/neptune-css/src/less/mixins/_logical-properties.less";
|
|
2
2
|
|
|
3
3
|
@badge-size-sm: 16px;
|
|
4
|
-
@badge-size-md: 20px;
|
|
5
4
|
@badge-size-lg: 24px;
|
|
6
5
|
|
|
7
6
|
@badge-mask-sm: 2px;
|
|
8
|
-
@badge-mask-md: 2px;
|
|
9
7
|
@badge-mask-lg: 3px;
|
|
10
8
|
|
|
11
9
|
@badge-border-light: rgba(255, 255, 255, 0.08);
|
|
@@ -20,11 +18,6 @@
|
|
|
20
18
|
--badge-mask-offset: calc(var(--badge-size) / 2);
|
|
21
19
|
--badge-border-color: @badge-border-light;
|
|
22
20
|
|
|
23
|
-
&.tw-badge-md {
|
|
24
|
-
--badge-size: @badge-size-md;
|
|
25
|
-
--badge-mask: @badge-mask-md;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
21
|
&.tw-badge-lg {
|
|
29
22
|
--badge-size: @badge-size-lg;
|
|
30
23
|
--badge-mask: @badge-mask-lg;
|
|
@@ -59,17 +52,11 @@
|
|
|
59
52
|
|
|
60
53
|
& > &__content {
|
|
61
54
|
position: absolute;
|
|
62
|
-
width: var(--badge-size);
|
|
63
|
-
height: var(--badge-size);
|
|
64
55
|
bottom: 0;
|
|
65
56
|
.right(0);
|
|
66
57
|
|
|
67
58
|
box-sizing: border-box;
|
|
68
|
-
border-radius: 50%;
|
|
69
59
|
text-align: center;
|
|
70
|
-
display: flex;
|
|
71
|
-
align-items: center;
|
|
72
|
-
justify-content: center;
|
|
73
60
|
overflow: hidden;
|
|
74
61
|
user-select: none;
|
|
75
62
|
|
package/src/badge/Badge.tsx
CHANGED
|
@@ -11,23 +11,41 @@ import {
|
|
|
11
11
|
ThemeLight,
|
|
12
12
|
CommonProps,
|
|
13
13
|
} from '../common';
|
|
14
|
+
import Circle, { CircleProps } from '../common/circle';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use `SizeSmall` or `SizeLarge` instead.
|
|
18
|
+
*/
|
|
19
|
+
type DeprecatedSizes = SizeMedium;
|
|
14
20
|
|
|
15
21
|
export type BadgeProps = {
|
|
16
22
|
badge: ReactNode;
|
|
17
23
|
children: ReactNode;
|
|
18
|
-
|
|
24
|
+
/**
|
|
25
|
+
* `md` is deprecated, it will fallback to `sm` instead.
|
|
26
|
+
*/
|
|
27
|
+
size?: SizeSmall | DeprecatedSizes | SizeLarge;
|
|
19
28
|
border?: ThemeDark | ThemeLight;
|
|
20
29
|
'aria-label'?: string;
|
|
21
30
|
} & CommonProps;
|
|
22
31
|
|
|
32
|
+
const mapLegacySize = {
|
|
33
|
+
[String(Size.SMALL)]: 16,
|
|
34
|
+
// medium is deprecated, so we map it to small
|
|
35
|
+
[String(Size.MEDIUM)]: 16,
|
|
36
|
+
[String(Size.LARGE)]: 24,
|
|
37
|
+
} satisfies Record<string, CircleProps['size']>;
|
|
38
|
+
|
|
23
39
|
const Badge = ({
|
|
24
40
|
badge,
|
|
25
41
|
className = undefined,
|
|
26
|
-
size = Size.SMALL,
|
|
42
|
+
size: sizeProp = Size.SMALL,
|
|
27
43
|
border = Theme.LIGHT,
|
|
28
44
|
'aria-label': ariaLabel,
|
|
29
45
|
children,
|
|
30
46
|
}: BadgeProps) => {
|
|
47
|
+
// medium is deprecated, so we map it to small
|
|
48
|
+
const size = sizeProp === Size.MEDIUM ? Size.SMALL : sizeProp;
|
|
31
49
|
const classes: string = clsx(
|
|
32
50
|
'tw-badge',
|
|
33
51
|
{
|
|
@@ -40,7 +58,9 @@ const Badge = ({
|
|
|
40
58
|
return (
|
|
41
59
|
<div aria-label={ariaLabel} className={classes}>
|
|
42
60
|
<div className="tw-badge__children">{children}</div>
|
|
43
|
-
<
|
|
61
|
+
<Circle size={mapLegacySize[size]} fixedSize className="tw-badge__content">
|
|
62
|
+
{badge}
|
|
63
|
+
</Circle>
|
|
44
64
|
</div>
|
|
45
65
|
);
|
|
46
66
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { render, fireEvent, screen } from '
|
|
1
|
+
import { render, fireEvent, screen, mockMatchMedia } from '../test-utils';
|
|
2
2
|
|
|
3
3
|
import Checkbox, { CheckboxProps } from '.';
|
|
4
4
|
import { Field } from '../field/Field';
|
|
5
5
|
|
|
6
|
+
mockMatchMedia();
|
|
7
|
+
|
|
6
8
|
describe('Checkbox', () => {
|
|
7
9
|
let props: CheckboxProps;
|
|
8
10
|
|
|
@@ -6,36 +6,6 @@
|
|
|
6
6
|
cursor: pointer;
|
|
7
7
|
position: relative;
|
|
8
8
|
}
|
|
9
|
-
.np-circular-btn input[type="button"] {
|
|
10
|
-
min-height: 40px;
|
|
11
|
-
min-height: var(--size-40);
|
|
12
|
-
width: 40px;
|
|
13
|
-
width: var(--size-40);
|
|
14
|
-
height: 40px;
|
|
15
|
-
height: var(--size-40);
|
|
16
|
-
padding: 0;
|
|
17
|
-
border-radius: 50%;
|
|
18
|
-
margin-bottom: 8px;
|
|
19
|
-
margin-bottom: var(--size-8);
|
|
20
|
-
}
|
|
21
|
-
.np-theme-personal .np-circular-btn input[type="button"] {
|
|
22
|
-
min-height: 56px;
|
|
23
|
-
min-height: var(--size-56);
|
|
24
|
-
width: 56px;
|
|
25
|
-
width: var(--size-56);
|
|
26
|
-
height: 56px;
|
|
27
|
-
height: var(--size-56);
|
|
28
|
-
}
|
|
29
|
-
@media (max-width: 320px) {
|
|
30
|
-
.np-theme-personal .np-circular-btn input[type="button"] {
|
|
31
|
-
min-height: 64px;
|
|
32
|
-
min-height: var(--size-64);
|
|
33
|
-
width: 64px;
|
|
34
|
-
width: var(--size-64);
|
|
35
|
-
height: 64px;
|
|
36
|
-
height: var(--size-64);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
9
|
.np-circular-btn .tw-icon {
|
|
40
10
|
position: absolute;
|
|
41
11
|
top: 16px;
|
|
@@ -76,13 +46,6 @@
|
|
|
76
46
|
.np-theme-personal .np-circular-btn.negative.secondary:not(.disabled):not(:disabled) .tw-icon {
|
|
77
47
|
color: var(--color-sentiment-negative) !important;
|
|
78
48
|
}
|
|
79
|
-
.np-circular-btn__label {
|
|
80
|
-
transition: color 0.15s ease-in-out;
|
|
81
|
-
font-size: 0.875rem;
|
|
82
|
-
font-size: var(--font-size-14);
|
|
83
|
-
font-weight: 600;
|
|
84
|
-
font-weight: var(--font-weight-semi-bold);
|
|
85
|
-
}
|
|
86
49
|
.np-circular-btn.accent .np-circular-btn__label {
|
|
87
50
|
color: #00a2dd;
|
|
88
51
|
color: var(--color-interactive-accent);
|
|
@@ -9,27 +9,6 @@
|
|
|
9
9
|
cursor: pointer;
|
|
10
10
|
position: relative;
|
|
11
11
|
|
|
12
|
-
input[type="button"] {
|
|
13
|
-
min-height: var(--size-40);
|
|
14
|
-
width: var(--size-40);
|
|
15
|
-
height: var(--size-40);
|
|
16
|
-
padding: 0;
|
|
17
|
-
border-radius: 50%;
|
|
18
|
-
margin-bottom: var(--size-8);
|
|
19
|
-
|
|
20
|
-
.np-theme-personal & {
|
|
21
|
-
min-height: var(--size-56);
|
|
22
|
-
width: var(--size-56);
|
|
23
|
-
height: var(--size-56);
|
|
24
|
-
|
|
25
|
-
@media (--screen-400-zoom) {
|
|
26
|
-
min-height: var(--size-64);
|
|
27
|
-
width: var(--size-64);
|
|
28
|
-
height: var(--size-64);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
12
|
.tw-icon {
|
|
34
13
|
position: absolute;
|
|
35
14
|
top: var(--size-16);
|
|
@@ -72,12 +51,6 @@
|
|
|
72
51
|
}
|
|
73
52
|
}
|
|
74
53
|
|
|
75
|
-
.np-circular-btn__label {
|
|
76
|
-
transition: color 0.15s ease-in-out;
|
|
77
|
-
font-size: var(--font-size-14);
|
|
78
|
-
font-weight: var(--font-weight-semi-bold);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
54
|
.button-label-states(
|
|
82
55
|
np-circular-btn,
|
|
83
56
|
accent,
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Plus } from '@transferwise/icons';
|
|
2
2
|
|
|
3
3
|
import { ControlType, Priority } from '../common';
|
|
4
|
-
import { render, screen, userEvent } from '../test-utils';
|
|
4
|
+
import { render, screen, userEvent, mockMatchMedia } from '../test-utils';
|
|
5
5
|
|
|
6
6
|
import CircularButton from './CircularButton';
|
|
7
7
|
|
|
8
|
+
mockMatchMedia();
|
|
9
|
+
|
|
8
10
|
const { ACCENT, POSITIVE, NEGATIVE } = ControlType;
|
|
9
11
|
const { PRIMARY, SECONDARY } = Priority;
|
|
10
12
|
|
|
@@ -3,7 +3,9 @@ import { cloneElement } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import Body from '../body/Body';
|
|
5
5
|
import { typeClassMap, priorityClassMap } from '../button/classMap';
|
|
6
|
-
import { ControlType, Priority, Typography } from '../common';
|
|
6
|
+
import { Breakpoint, ControlType, Priority, Typography } from '../common';
|
|
7
|
+
import Circle from '../common/circle';
|
|
8
|
+
import { useMedia } from '../common/hooks/useMedia';
|
|
7
9
|
|
|
8
10
|
export interface CircularButtonProps {
|
|
9
11
|
className?: string;
|
|
@@ -24,14 +26,19 @@ const CircularButton = ({
|
|
|
24
26
|
type = ControlType.ACCENT,
|
|
25
27
|
...rest
|
|
26
28
|
}: CircularButtonProps) => {
|
|
27
|
-
const classes = clsx('btn np-btn', typeClassMap[type], priorityClassMap[priority]);
|
|
29
|
+
const classes = clsx('btn np-btn', 'm-b-1', typeClassMap[type], priorityClassMap[priority]);
|
|
28
30
|
|
|
29
31
|
const iconElement = Number(icon.props.size) !== 24 ? cloneElement(icon, { size: 24 }) : icon;
|
|
30
32
|
|
|
33
|
+
const isTinyViewport = useMedia(`(max-width: ${Breakpoint.ZOOM_400}px)`);
|
|
34
|
+
|
|
31
35
|
return (
|
|
32
36
|
<label className={clsx('np-circular-btn', priority, type, disabled && 'disabled', className)}>
|
|
33
|
-
<
|
|
37
|
+
<Circle
|
|
38
|
+
as="input"
|
|
39
|
+
// @ts-expect-error it's input[type=button] element
|
|
34
40
|
type="button"
|
|
41
|
+
size={isTinyViewport ? 64 : 56}
|
|
35
42
|
aria-label={children}
|
|
36
43
|
className={classes}
|
|
37
44
|
disabled={disabled}
|
|
@@ -7,7 +7,8 @@ exports[`CircularButton defaults renders a button of type accent and priority pr
|
|
|
7
7
|
>
|
|
8
8
|
<input
|
|
9
9
|
aria-label="Add money"
|
|
10
|
-
class="btn np-btn btn-accent btn-priority-1"
|
|
10
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-accent btn-priority-1"
|
|
11
|
+
style="--circle-size: var(--size-56);"
|
|
11
12
|
type="button"
|
|
12
13
|
/>
|
|
13
14
|
<span
|
|
@@ -44,7 +45,8 @@ exports[`CircularButton priorities renders primary buttons 1`] = `
|
|
|
44
45
|
>
|
|
45
46
|
<input
|
|
46
47
|
aria-label="Add money"
|
|
47
|
-
class="btn np-btn btn-accent btn-priority-1"
|
|
48
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-accent btn-priority-1"
|
|
49
|
+
style="--circle-size: var(--size-56);"
|
|
48
50
|
type="button"
|
|
49
51
|
/>
|
|
50
52
|
<span
|
|
@@ -81,7 +83,8 @@ exports[`CircularButton priorities renders primary buttons 2`] = `
|
|
|
81
83
|
>
|
|
82
84
|
<input
|
|
83
85
|
aria-label="Add money"
|
|
84
|
-
class="btn np-btn btn-positive btn-priority-1"
|
|
86
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-positive btn-priority-1"
|
|
87
|
+
style="--circle-size: var(--size-56);"
|
|
85
88
|
type="button"
|
|
86
89
|
/>
|
|
87
90
|
<span
|
|
@@ -118,7 +121,8 @@ exports[`CircularButton priorities renders primary buttons 3`] = `
|
|
|
118
121
|
>
|
|
119
122
|
<input
|
|
120
123
|
aria-label="Add money"
|
|
121
|
-
class="btn np-btn btn-negative btn-priority-1"
|
|
124
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-negative btn-priority-1"
|
|
125
|
+
style="--circle-size: var(--size-56);"
|
|
122
126
|
type="button"
|
|
123
127
|
/>
|
|
124
128
|
<span
|
|
@@ -155,7 +159,8 @@ exports[`CircularButton priorities renders secondary buttons 1`] = `
|
|
|
155
159
|
>
|
|
156
160
|
<input
|
|
157
161
|
aria-label="Add money"
|
|
158
|
-
class="btn np-btn btn-accent btn-priority-2"
|
|
162
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-accent btn-priority-2"
|
|
163
|
+
style="--circle-size: var(--size-56);"
|
|
159
164
|
type="button"
|
|
160
165
|
/>
|
|
161
166
|
<span
|
|
@@ -192,7 +197,8 @@ exports[`CircularButton priorities renders secondary buttons 2`] = `
|
|
|
192
197
|
>
|
|
193
198
|
<input
|
|
194
199
|
aria-label="Add money"
|
|
195
|
-
class="btn np-btn btn-positive btn-priority-2"
|
|
200
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-positive btn-priority-2"
|
|
201
|
+
style="--circle-size: var(--size-56);"
|
|
196
202
|
type="button"
|
|
197
203
|
/>
|
|
198
204
|
<span
|
|
@@ -229,7 +235,8 @@ exports[`CircularButton priorities renders secondary buttons 3`] = `
|
|
|
229
235
|
>
|
|
230
236
|
<input
|
|
231
237
|
aria-label="Add money"
|
|
232
|
-
class="btn np-btn btn-negative btn-priority-2"
|
|
238
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-negative btn-priority-2"
|
|
239
|
+
style="--circle-size: var(--size-56);"
|
|
233
240
|
type="button"
|
|
234
241
|
/>
|
|
235
242
|
<span
|
|
@@ -266,7 +273,8 @@ exports[`CircularButton types renders accent buttons 1`] = `
|
|
|
266
273
|
>
|
|
267
274
|
<input
|
|
268
275
|
aria-label="Add money"
|
|
269
|
-
class="btn np-btn btn-accent btn-priority-1"
|
|
276
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-accent btn-priority-1"
|
|
277
|
+
style="--circle-size: var(--size-56);"
|
|
270
278
|
type="button"
|
|
271
279
|
/>
|
|
272
280
|
<span
|
|
@@ -303,7 +311,8 @@ exports[`CircularButton types renders negative buttons 1`] = `
|
|
|
303
311
|
>
|
|
304
312
|
<input
|
|
305
313
|
aria-label="Add money"
|
|
306
|
-
class="btn np-btn btn-negative btn-priority-1"
|
|
314
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-negative btn-priority-1"
|
|
315
|
+
style="--circle-size: var(--size-56);"
|
|
307
316
|
type="button"
|
|
308
317
|
/>
|
|
309
318
|
<span
|
|
@@ -340,7 +349,8 @@ exports[`CircularButton types renders positive buttons 1`] = `
|
|
|
340
349
|
>
|
|
341
350
|
<input
|
|
342
351
|
aria-label="Add money"
|
|
343
|
-
class="btn np-btn btn-positive btn-priority-1"
|
|
352
|
+
class="np-circle d-flex align-items-center justify-content-center btn np-btn m-b-1 btn-positive btn-priority-1"
|
|
353
|
+
style="--circle-size: var(--size-56);"
|
|
344
354
|
type="button"
|
|
345
355
|
/>
|
|
346
356
|
<span
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { storyConfig } from '../../test-utils';
|
|
3
|
+
import Circle from './Circle';
|
|
4
|
+
import { Profile } from '@transferwise/icons';
|
|
5
|
+
import { action } from '@storybook/addon-actions';
|
|
6
|
+
import { CircleProps } from '.';
|
|
7
|
+
import Body from '../../body';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Internal/Circle',
|
|
11
|
+
component: Circle,
|
|
12
|
+
} satisfies Meta<typeof Circle>;
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof Circle>;
|
|
15
|
+
|
|
16
|
+
export const Basic: Story = {
|
|
17
|
+
tags: ['autodocs'],
|
|
18
|
+
args: {
|
|
19
|
+
children: 'NP',
|
|
20
|
+
size: 40,
|
|
21
|
+
as: 'div',
|
|
22
|
+
className: 'bg-neutral',
|
|
23
|
+
},
|
|
24
|
+
render: (args) => {
|
|
25
|
+
return <Circle {...args} />;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Sizes: Story = storyConfig(
|
|
30
|
+
{
|
|
31
|
+
render: () => {
|
|
32
|
+
const content = <Profile size={16} />;
|
|
33
|
+
const sizes: CircleProps['size'][] = [32, 40, 48, 56, 72];
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
style={{
|
|
37
|
+
gap: '1em',
|
|
38
|
+
display: 'grid',
|
|
39
|
+
justifyContent: 'space-between',
|
|
40
|
+
gridTemplate: 'auto auto / repeat(5, min-content)',
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
{sizes.map((size) => (
|
|
44
|
+
<Circle key={size} size={size} className="bg-neutral">
|
|
45
|
+
{content}
|
|
46
|
+
</Circle>
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{ variants: ['light', 'dark'] },
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
export const FixedSize: Story = storyConfig(
|
|
56
|
+
{
|
|
57
|
+
render: () => {
|
|
58
|
+
const size = 72;
|
|
59
|
+
const content = <Profile size={16} />;
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
style={{
|
|
63
|
+
gap: '1em',
|
|
64
|
+
display: 'grid',
|
|
65
|
+
justifyContent: 'space-between',
|
|
66
|
+
gridTemplate: 'auto auto / repeat(2, 180px)',
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
<Body className="d-block">
|
|
70
|
+
Dynamic Size (<code>--size-{size}</code>)
|
|
71
|
+
</Body>
|
|
72
|
+
<Body className="d-block">
|
|
73
|
+
Fixed Size (<code>{size}px</code>)
|
|
74
|
+
</Body>
|
|
75
|
+
<Circle size={72} fixedSize={false} className="bg-neutral">
|
|
76
|
+
{content}
|
|
77
|
+
</Circle>
|
|
78
|
+
<Circle size={72} fixedSize className="bg-neutral">
|
|
79
|
+
{content}
|
|
80
|
+
</Circle>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{ variants: ['400%'] },
|
|
86
|
+
);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { HTMLAttributes, forwardRef } from 'react';
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
|
|
4
|
+
export type ShapeSize = 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72;
|
|
5
|
+
|
|
6
|
+
export type Props = {
|
|
7
|
+
/**
|
|
8
|
+
* Modify underlying element, `div` by default
|
|
9
|
+
*/
|
|
10
|
+
as?: React.ElementType;
|
|
11
|
+
/**
|
|
12
|
+
* Set size of the circle in px, `48` by default
|
|
13
|
+
*/
|
|
14
|
+
size?: ShapeSize;
|
|
15
|
+
/**
|
|
16
|
+
* When `true` will use the fixed size (`48px`) instead of the CSS spacing variable (`--size-*`)
|
|
17
|
+
* as those can be dynamic a at certain viewport sizes
|
|
18
|
+
*/
|
|
19
|
+
fixedSize?: boolean;
|
|
20
|
+
} & HTMLAttributes<HTMLDivElement>;
|
|
21
|
+
|
|
22
|
+
const Circle = forwardRef(function Circle(
|
|
23
|
+
{
|
|
24
|
+
as: Element = 'div',
|
|
25
|
+
children,
|
|
26
|
+
size = 48,
|
|
27
|
+
fixedSize = false,
|
|
28
|
+
className,
|
|
29
|
+
style,
|
|
30
|
+
...props
|
|
31
|
+
}: Props,
|
|
32
|
+
ref,
|
|
33
|
+
) {
|
|
34
|
+
return (
|
|
35
|
+
<Element
|
|
36
|
+
{...props}
|
|
37
|
+
ref={ref}
|
|
38
|
+
style={{ ...style, '--circle-size': fixedSize ? `${size}px` : `var(--size-${size})` }}
|
|
39
|
+
className={clsx('np-circle', 'd-flex align-items-center justify-content-center', className)}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</Element>
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export default Circle;
|
|
@@ -21,10 +21,12 @@ exports[`FlowNavigation on mobile renders as expected 1`] = `
|
|
|
21
21
|
class="np-flow-header__right d-flex align-items-center justify-content-end order-2--lg"
|
|
22
22
|
>
|
|
23
23
|
<div
|
|
24
|
-
class="tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
24
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
25
|
+
style="--circle-size: 48px;"
|
|
25
26
|
>
|
|
26
27
|
<div
|
|
27
|
-
class="tw-avatar__content"
|
|
28
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
29
|
+
style="--circle-size: 48px;"
|
|
28
30
|
>
|
|
29
31
|
TM
|
|
30
32
|
</div>
|
|
@@ -136,10 +138,12 @@ exports[`FlowNavigation renders as expected 1`] = `
|
|
|
136
138
|
class="np-flow-header__right d-flex align-items-center justify-content-end order-2--lg"
|
|
137
139
|
>
|
|
138
140
|
<div
|
|
139
|
-
class="tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
141
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
142
|
+
style="--circle-size: 48px;"
|
|
140
143
|
>
|
|
141
144
|
<div
|
|
142
|
-
class="tw-avatar__content"
|
|
145
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
146
|
+
style="--circle-size: 48px;"
|
|
143
147
|
>
|
|
144
148
|
TM
|
|
145
149
|
</div>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { Sentiment } from '../common';
|
|
3
|
-
import { render, screen } from '../test-utils';
|
|
3
|
+
import { render, screen, mockMatchMedia } from '../test-utils';
|
|
4
4
|
|
|
5
5
|
import InlineAlert from './InlineAlert';
|
|
6
6
|
|
|
7
|
+
mockMatchMedia();
|
|
8
|
+
|
|
7
9
|
describe('InlineAlert', () => {
|
|
8
10
|
const message = 'Your card is on its way.';
|
|
9
11
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
import { MoneyInput } from '..';
|
|
3
|
+
|
|
4
|
+
<Meta title="Forms/SelectInput/Accessibility" />
|
|
5
|
+
|
|
6
|
+
# Accessibility
|
|
7
|
+
|
|
8
|
+
## Labelling
|
|
9
|
+
|
|
10
|
+
In order for the `<SelectInput />` to be considered accessible, it must be provided with a matching label, preferably via the <a href="/?path=/docs/field--docs">Field</a> component.
|
|
11
|
+
|
|
12
|
+
Additionally, the `listbox` container that holds all the options is also expected to have its own label, which the component will attempt to resolve by looking in the following places:
|
|
13
|
+
|
|
14
|
+
1. `UNSAFE_triggerButtonProps['aria-label']` prop, which reuses the custom label provided for the trigger button.
|
|
15
|
+
<br /> A good example of this strategy is the `<MoneyInput />` component, internally setting
|
|
16
|
+
`"Select currency"` as a trigger button label, which then gets automatically applied to the
|
|
17
|
+
`listbox`.
|
|
18
|
+
2. `UNSAFE_triggerButtonProps['aria-labelledby']` prop, which holds the id of the element labelling the trigger button.
|
|
19
|
+
3. Correctly paired input `<label />` text, ideally via the `Field` component.
|
|
20
|
+
|
|
21
|
+
> Using option group heading is possible but complicated as we can have multiple groups, and those are not necessarily rendered consistently if search or virtualisation are enabled.
|