@transferwise/components 0.0.0-experimental-f7495f3 → 0.0.0-experimental-37d8e2c
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 +4 -1
- package/build/avatar/Avatar.js.map +1 -1
- package/build/avatar/Avatar.mjs +4 -1
- package/build/avatar/Avatar.mjs.map +1 -1
- package/build/avatar/colors/colors.js +1 -1
- package/build/avatar/colors/colors.js.map +1 -1
- package/build/avatar/colors/colors.mjs +1 -1
- package/build/avatar/colors/colors.mjs.map +1 -1
- package/build/avatarView/AvatarView.js +207 -0
- package/build/avatarView/AvatarView.js.map +1 -0
- package/build/avatarView/AvatarView.mjs +205 -0
- package/build/avatarView/AvatarView.mjs.map +1 -0
- package/build/avatarWrapper/AvatarWrapper.js +6 -9
- package/build/avatarWrapper/AvatarWrapper.js.map +1 -1
- package/build/avatarWrapper/AvatarWrapper.mjs +5 -8
- package/build/avatarWrapper/AvatarWrapper.mjs.map +1 -1
- package/build/badge/Badge.js +6 -1
- package/build/badge/Badge.js.map +1 -1
- package/build/badge/Badge.mjs +6 -1
- package/build/badge/Badge.mjs.map +1 -1
- package/build/circularButton/CircularButton.js +4 -7
- package/build/circularButton/CircularButton.js.map +1 -1
- package/build/circularButton/CircularButton.mjs +4 -7
- package/build/circularButton/CircularButton.mjs.map +1 -1
- package/build/common/circle/Circle.js +24 -1
- package/build/common/circle/Circle.js.map +1 -1
- package/build/common/circle/Circle.mjs +24 -1
- package/build/common/circle/Circle.mjs.map +1 -1
- package/build/common/initials.js +12 -0
- package/build/common/initials.js.map +1 -0
- package/build/common/initials.mjs +10 -0
- package/build/common/initials.mjs.map +1 -0
- package/build/common/notificationDot/NotificationDot.js +16 -0
- package/build/common/notificationDot/NotificationDot.js.map +1 -0
- package/build/common/notificationDot/NotificationDot.mjs +14 -0
- package/build/common/notificationDot/NotificationDot.mjs.map +1 -0
- package/build/display/Display.js +1 -1
- package/build/display/Display.js.map +1 -1
- package/build/display/Display.mjs +1 -1
- package/build/display/Display.mjs.map +1 -1
- package/build/index.js +6 -0
- package/build/index.js.map +1 -1
- package/build/index.mjs +3 -0
- package/build/index.mjs.map +1 -1
- package/build/main.css +82 -41
- package/build/statusIcon/StatusIcon.js +4 -2
- package/build/statusIcon/StatusIcon.js.map +1 -1
- package/build/statusIcon/StatusIcon.mjs +4 -2
- package/build/statusIcon/StatusIcon.mjs.map +1 -1
- package/build/styles/avatarGroup/AvatarGroup.css +28 -0
- package/build/styles/avatarView/AvatarView.css +22 -0
- package/build/styles/badge/Badge.css +5 -5
- package/build/styles/circularButton/CircularButton.css +0 -24
- package/build/styles/common/circle/Circle.css +17 -0
- package/build/styles/common/notificationDot/NotificationDot.css +10 -0
- package/build/styles/main.css +82 -41
- package/build/styles/statusIcon/StatusIcon.css +0 -12
- package/build/types/avatar/Avatar.d.ts +3 -0
- package/build/types/avatar/Avatar.d.ts.map +1 -1
- package/build/types/avatar/colors/colors.d.ts +1 -1
- package/build/types/avatar/colors/colors.d.ts.map +1 -1
- package/build/types/avatarGroup/AvatarGroup.d.ts +19 -0
- package/build/types/avatarGroup/AvatarGroup.d.ts.map +1 -0
- package/build/types/avatarGroup/index.d.ts +3 -0
- package/build/types/avatarGroup/index.d.ts.map +1 -0
- package/build/types/avatarView/AvatarView.d.ts +25 -0
- package/build/types/avatarView/AvatarView.d.ts.map +1 -0
- package/build/types/avatarView/index.d.ts +3 -0
- package/build/types/avatarView/index.d.ts.map +1 -0
- package/build/types/avatarWrapper/AvatarWrapper.d.ts +3 -0
- package/build/types/avatarWrapper/AvatarWrapper.d.ts.map +1 -1
- package/build/types/badge/Badge.d.ts +2 -1
- 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 +1 -1
- package/build/types/common/circle/Circle.d.ts.map +1 -1
- package/build/types/common/index.d.ts +1 -0
- package/build/types/common/initials.d.ts +2 -0
- package/build/types/common/initials.d.ts.map +1 -0
- package/build/types/common/notificationDot/NotificationDot.d.ts +8 -0
- package/build/types/common/notificationDot/NotificationDot.d.ts.map +1 -0
- package/build/types/index.d.ts +4 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts +6 -2
- package/build/types/statusIcon/StatusIcon.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/avatar/Avatar.tsx +4 -1
- package/src/avatar/colors/colors.ts +4 -4
- package/src/avatarGroup/AvatarGroup.css +28 -0
- package/src/avatarGroup/AvatarGroup.less +32 -0
- package/src/avatarGroup/AvatarGroup.story.tsx +249 -0
- package/src/avatarGroup/AvatarGroup.tsx +78 -0
- package/src/avatarGroup/index.ts +2 -0
- package/src/avatarView/AvatarView.css +22 -0
- package/src/avatarView/AvatarView.less +24 -0
- package/src/avatarView/AvatarView.story.tsx +425 -0
- package/src/avatarView/AvatarView.tsx +217 -0
- package/src/avatarView/index.ts +2 -0
- package/src/avatarWrapper/AvatarWrapper.tsx +12 -16
- package/src/badge/Badge.css +5 -5
- package/src/badge/Badge.less +3 -3
- package/src/badge/Badge.tsx +10 -1
- package/src/circularButton/CircularButton.css +0 -24
- package/src/circularButton/CircularButton.less +15 -15
- package/src/circularButton/CircularButton.tsx +4 -5
- package/src/common/circle/Circle.css +17 -0
- package/src/common/circle/Circle.less +22 -0
- package/src/common/circle/Circle.tsx +33 -2
- package/src/common/index.js +1 -0
- package/src/common/initials.ts +13 -0
- package/src/common/notificationDot/NotificationDot.css +10 -0
- package/src/common/notificationDot/NotificationDot.less +7 -0
- package/src/common/notificationDot/NotificationDot.tsx +10 -0
- package/src/display/Display.tsx +1 -1
- package/src/index.ts +4 -0
- package/src/main.css +82 -41
- package/src/main.less +3 -0
- package/src/statusIcon/StatusIcon.css +0 -12
- package/src/statusIcon/StatusIcon.less +6 -6
- package/src/statusIcon/StatusIcon.story.tsx +32 -28
- package/src/statusIcon/StatusIcon.tsx +18 -4
- package/src/test-utils/avatar-img.webp +0 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import Badge from '../badge';
|
|
2
|
+
import { getInitials } from '../common';
|
|
3
|
+
import NotificationDot from '../common/notificationDot/NotificationDot';
|
|
4
|
+
import StatusIcon from '../statusIcon';
|
|
5
|
+
import Circle from '../common/circle';
|
|
6
|
+
import { HTMLAttributes, PropsWithChildren, useState } from 'react';
|
|
7
|
+
import { ActionOptions as ActionProps } from '../common/action/Action';
|
|
8
|
+
import { clsx } from 'clsx';
|
|
9
|
+
import { Briefcase, Profile } from '@transferwise/icons';
|
|
10
|
+
|
|
11
|
+
type InteractiveProps = Omit<ActionProps, 'text'> &
|
|
12
|
+
Pick<HTMLAttributes<HTMLDivElement>, 'className' | 'aria-labelledby'>;
|
|
13
|
+
|
|
14
|
+
const AvatarViewDefaultSize = 48;
|
|
15
|
+
|
|
16
|
+
export type Props = PropsWithChildren<{
|
|
17
|
+
size?: 16 | 24 | 32 | 40 | 48 | 56 | 72;
|
|
18
|
+
/** adds prebuilt notification dot via Badge component */
|
|
19
|
+
notification?: boolean;
|
|
20
|
+
/** adds custom badge to avatar */
|
|
21
|
+
badge?: React.ReactNode;
|
|
22
|
+
entity?: EntityProps;
|
|
23
|
+
/** changes background color to neutral and wraps component with button */
|
|
24
|
+
action?: InteractiveProps;
|
|
25
|
+
/** changes background color to neutral and adds predefined Badge */
|
|
26
|
+
selected?: boolean;
|
|
27
|
+
/** often use case to override `background-color` or `border` */
|
|
28
|
+
style?: React.CSSProperties;
|
|
29
|
+
}> &
|
|
30
|
+
Pick<HTMLAttributes<HTMLDivElement>, 'className' | 'style'>;
|
|
31
|
+
|
|
32
|
+
/** Non interactive avatar view has custom border width */
|
|
33
|
+
const mapNonInteractiveBorderWidth = {
|
|
34
|
+
16: 0.667,
|
|
35
|
+
24: 1,
|
|
36
|
+
32: 1,
|
|
37
|
+
40: 1.25,
|
|
38
|
+
48: 1.5,
|
|
39
|
+
56: 1.75,
|
|
40
|
+
72: 2.25,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Selected state has custom border width */
|
|
44
|
+
const mapSelectedBorderWidth = {
|
|
45
|
+
16: 1,
|
|
46
|
+
24: 1,
|
|
47
|
+
32: 1,
|
|
48
|
+
40: 2,
|
|
49
|
+
48: 2,
|
|
50
|
+
56: 2,
|
|
51
|
+
72: 2,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function AvatarView({
|
|
55
|
+
children = undefined,
|
|
56
|
+
size = AvatarViewDefaultSize,
|
|
57
|
+
selected,
|
|
58
|
+
notification,
|
|
59
|
+
badge,
|
|
60
|
+
entity,
|
|
61
|
+
action,
|
|
62
|
+
className,
|
|
63
|
+
style,
|
|
64
|
+
}: Props) {
|
|
65
|
+
return (
|
|
66
|
+
<Interactive
|
|
67
|
+
{...action}
|
|
68
|
+
className={clsx('np-avatar-view', { 'np-avatar-view-selected': selected }, className)}
|
|
69
|
+
>
|
|
70
|
+
<Badges asset={badge} avatarProps={{ size, notification, selected }}>
|
|
71
|
+
<Circle
|
|
72
|
+
size={size}
|
|
73
|
+
fixedSize
|
|
74
|
+
style={{
|
|
75
|
+
// @ts-expect-error CSS custom props allowed
|
|
76
|
+
'--avatar-view-selected-border-width': `${mapSelectedBorderWidth[size]}px`,
|
|
77
|
+
'--avatar-view-non-interactive-border-width': `${mapNonInteractiveBorderWidth[size]}px`,
|
|
78
|
+
...style,
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{children === undefined ? <Entity {...entity} /> : children}
|
|
82
|
+
</Circle>
|
|
83
|
+
</Badges>
|
|
84
|
+
</Interactive>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function Interactive({
|
|
89
|
+
children,
|
|
90
|
+
onClick,
|
|
91
|
+
href,
|
|
92
|
+
target,
|
|
93
|
+
className,
|
|
94
|
+
'aria-label': ariaLabel,
|
|
95
|
+
'aria-labelledby': ariaLabelledby,
|
|
96
|
+
}: PropsWithChildren<InteractiveProps>) {
|
|
97
|
+
const elementName: React.ElementType | null = onClick ? 'button' : href ? 'a' : null;
|
|
98
|
+
if (elementName === null) {
|
|
99
|
+
// non interactive
|
|
100
|
+
return <div className={className}>{children}</div>;
|
|
101
|
+
}
|
|
102
|
+
const a11yProps = { ariaLabel, ariaLabelledby };
|
|
103
|
+
if (elementName === 'button') {
|
|
104
|
+
return (
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
className={clsx(className, 'np-avatar-view-interactive', 'btn-unstyled')}
|
|
108
|
+
onClick={onClick}
|
|
109
|
+
{...a11yProps}
|
|
110
|
+
>
|
|
111
|
+
{children}
|
|
112
|
+
</button>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (elementName === 'a') {
|
|
116
|
+
return (
|
|
117
|
+
// eslint-disable-next-line react/jsx-no-target-blank
|
|
118
|
+
<a
|
|
119
|
+
href={href}
|
|
120
|
+
target={target}
|
|
121
|
+
rel={target === '_blank' ? 'noreferrer' : undefined}
|
|
122
|
+
className={clsx(className, 'np-avatar-view-interactive', 'text-no-decoration')}
|
|
123
|
+
{...a11yProps}
|
|
124
|
+
>
|
|
125
|
+
{children}
|
|
126
|
+
</a>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const mapBadgeSize = {
|
|
132
|
+
16: 'sm',
|
|
133
|
+
24: 'sm',
|
|
134
|
+
32: 'sm',
|
|
135
|
+
40: 'sm',
|
|
136
|
+
48: 'sm',
|
|
137
|
+
56: 'lg',
|
|
138
|
+
72: 'lg',
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/** AvatarView has a custom sizes for badge */
|
|
142
|
+
const mapNotificationSize = {
|
|
143
|
+
16: 6,
|
|
144
|
+
24: 8,
|
|
145
|
+
32: 10,
|
|
146
|
+
40: 10,
|
|
147
|
+
48: 14,
|
|
148
|
+
56: 16,
|
|
149
|
+
72: 20,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
type BadgesProps = PropsWithChildren<{
|
|
153
|
+
asset: React.ReactNode;
|
|
154
|
+
avatarProps: Pick<Props, 'selected' | 'size' | 'notification'>;
|
|
155
|
+
}>;
|
|
156
|
+
|
|
157
|
+
function Badges({ children, asset, avatarProps }: BadgesProps) {
|
|
158
|
+
const { size = AvatarViewDefaultSize, selected, notification } = avatarProps;
|
|
159
|
+
if (asset || selected || notification) {
|
|
160
|
+
if (asset && size > 16) {
|
|
161
|
+
return (
|
|
162
|
+
<Badge badge={asset} size={mapBadgeSize[size]}>
|
|
163
|
+
{children}
|
|
164
|
+
</Badge>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (selected && size > 16) {
|
|
168
|
+
return (
|
|
169
|
+
<Badge
|
|
170
|
+
badge={<StatusIcon sentiment="positive" size={mapBadgeSize[size]} />}
|
|
171
|
+
size={mapBadgeSize[size]}
|
|
172
|
+
>
|
|
173
|
+
{children}
|
|
174
|
+
</Badge>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
if (notification) {
|
|
178
|
+
return (
|
|
179
|
+
<Badge
|
|
180
|
+
badge={
|
|
181
|
+
<NotificationDot
|
|
182
|
+
// @ts-expect-error CSS custom props allowed
|
|
183
|
+
style={{ '--badge-notification-dot-size': `${mapNotificationSize[size]}px` }}
|
|
184
|
+
/>
|
|
185
|
+
}
|
|
186
|
+
position="top-right"
|
|
187
|
+
size={mapBadgeSize[size]}
|
|
188
|
+
>
|
|
189
|
+
{children}
|
|
190
|
+
</Badge>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return children;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export type EntityProps = {
|
|
198
|
+
imageSrc?: string | null;
|
|
199
|
+
name?: string | null;
|
|
200
|
+
profileType?: 'personal' | 'business' | null;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
function Entity({ imageSrc = null, name = null, profileType = null }: EntityProps) {
|
|
204
|
+
const [tryLoadImage, setTryLoadImage] = useState(true);
|
|
205
|
+
if (imageSrc && tryLoadImage) {
|
|
206
|
+
return <img src={imageSrc} alt="" onError={() => setTryLoadImage(false)} />;
|
|
207
|
+
}
|
|
208
|
+
if (profileType) {
|
|
209
|
+
return profileType === 'business' ? <Briefcase /> : <Profile />;
|
|
210
|
+
}
|
|
211
|
+
if (name) {
|
|
212
|
+
return <>{getInitials(name)}</>;
|
|
213
|
+
}
|
|
214
|
+
return <Profile />;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export default AvatarView;
|
|
@@ -3,7 +3,14 @@ import { useState, useEffect } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import Avatar, { AvatarProps, AvatarType } from '../avatar';
|
|
5
5
|
import Badge, { BadgeProps } from '../badge';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
ProfileType,
|
|
8
|
+
ProfileTypePersonal,
|
|
9
|
+
ProfileTypeBusiness,
|
|
10
|
+
Size,
|
|
11
|
+
Sentiment,
|
|
12
|
+
getInitials,
|
|
13
|
+
} from '../common';
|
|
7
14
|
import StatusIcon from '../statusIcon/StatusIcon';
|
|
8
15
|
|
|
9
16
|
interface OptionalBadgeProps extends Omit<BadgeProps, 'badge'> {
|
|
@@ -68,6 +75,9 @@ export type AvatarWrapperProps = {
|
|
|
68
75
|
}
|
|
69
76
|
);
|
|
70
77
|
|
|
78
|
+
/**
|
|
79
|
+
* @deprecated Use `AvatarView` component instead
|
|
80
|
+
*/
|
|
71
81
|
const AvatarWrapper = ({
|
|
72
82
|
url,
|
|
73
83
|
'aria-label': ariaLabel,
|
|
@@ -109,7 +119,7 @@ const AvatarWrapper = ({
|
|
|
109
119
|
return {
|
|
110
120
|
type: AvatarType.INITIALS,
|
|
111
121
|
children: <>{getInitials(name)}</>,
|
|
112
|
-
backgroundColorSeed:
|
|
122
|
+
backgroundColorSeed: name?.toString(),
|
|
113
123
|
...updatedAvatarProps,
|
|
114
124
|
};
|
|
115
125
|
}
|
|
@@ -133,18 +143,4 @@ const AvatarWrapper = ({
|
|
|
133
143
|
);
|
|
134
144
|
};
|
|
135
145
|
|
|
136
|
-
function getInitials(name: string) {
|
|
137
|
-
const allInitials = name
|
|
138
|
-
.split(' ')
|
|
139
|
-
.map((part) => part[0])
|
|
140
|
-
.join('')
|
|
141
|
-
.toUpperCase();
|
|
142
|
-
|
|
143
|
-
if (allInitials.length === 1) {
|
|
144
|
-
return allInitials[0];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return allInitials[0] + allInitials.slice(-1);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
146
|
export default AvatarWrapper;
|
package/src/badge/Badge.css
CHANGED
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
--badge-border-color: rgba(0, 0, 0, 0.08);
|
|
15
15
|
}
|
|
16
16
|
.tw-badge > .tw-badge__children {
|
|
17
|
-
-webkit-mask-image: radial-gradient(circle at
|
|
18
|
-
mask-image: radial-gradient(circle at
|
|
17
|
+
-webkit-mask-image: radial-gradient(circle at var(--badge-mask-position) calc(100% - var(--badge-mask-offset)) left calc(100% - var(--badge-mask-offset)), transparent 0, transparent calc(var(--badge-size) / 2 + var(--badge-mask)), black calc(var(--badge-size) / 2 + var(--badge-mask) + 0.5px));
|
|
18
|
+
mask-image: radial-gradient(circle at var(--badge-mask-position) calc(100% - var(--badge-mask-offset)) left calc(100% - var(--badge-mask-offset)), transparent 0, transparent calc(var(--badge-size) / 2 + var(--badge-mask)), black calc(var(--badge-size) / 2 + var(--badge-mask) + 0.5px));
|
|
19
19
|
}
|
|
20
20
|
[dir="rtl"] .tw-badge > .tw-badge__children {
|
|
21
|
-
-webkit-mask-image: radial-gradient(circle at
|
|
22
|
-
mask-image: radial-gradient(circle at
|
|
21
|
+
-webkit-mask-image: radial-gradient(circle at var(--badge-mask-position) calc(100% - var(--badge-mask-offset)) right calc(100% - var(--badge-mask-offset)), transparent 0, transparent calc(var(--badge-size) / 2 + var(--badge-mask)), black calc(var(--badge-size) / 2 + var(--badge-mask) + 0.5px));
|
|
22
|
+
mask-image: radial-gradient(circle at var(--badge-mask-position) calc(100% - var(--badge-mask-offset)) right calc(100% - var(--badge-mask-offset)), transparent 0, transparent calc(var(--badge-size) / 2 + var(--badge-mask)), black calc(var(--badge-size) / 2 + var(--badge-mask) + 0.5px));
|
|
23
23
|
}
|
|
24
24
|
.tw-badge > .tw-badge__content {
|
|
25
25
|
position: absolute;
|
|
26
|
-
bottom:
|
|
26
|
+
bottom: var(--badge-bottom-position);
|
|
27
27
|
right: 0;
|
|
28
28
|
box-sizing: border-box;
|
|
29
29
|
text-align: center;
|
package/src/badge/Badge.less
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
mask-image:
|
|
35
35
|
radial-gradient(
|
|
36
|
-
circle at
|
|
36
|
+
circle at var(--badge-mask-position) calc(100% - var(--badge-mask-offset)) left calc(100% - var(--badge-mask-offset)),
|
|
37
37
|
transparent 0,
|
|
38
38
|
transparent calc(var(--badge-size) / 2 + var(--badge-mask)),
|
|
39
39
|
black calc(var(--badge-size) / 2 + var(--badge-mask) + 0.5px)
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
[dir="rtl"] & {
|
|
43
43
|
mask-image:
|
|
44
44
|
radial-gradient(
|
|
45
|
-
circle at
|
|
45
|
+
circle at var(--badge-mask-position) calc(100% - var(--badge-mask-offset)) right calc(100% - var(--badge-mask-offset)),
|
|
46
46
|
transparent 0,
|
|
47
47
|
transparent calc(var(--badge-size) / 2 + var(--badge-mask)),
|
|
48
48
|
black calc(var(--badge-size) / 2 + var(--badge-mask) + 0.5px)
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
|
|
53
53
|
& > &__content {
|
|
54
54
|
position: absolute;
|
|
55
|
-
bottom:
|
|
55
|
+
bottom: var(--badge-bottom-position);
|
|
56
56
|
.right(0);
|
|
57
57
|
|
|
58
58
|
box-sizing: border-box;
|
package/src/badge/Badge.tsx
CHANGED
|
@@ -27,6 +27,7 @@ export type BadgeProps = {
|
|
|
27
27
|
size?: SizeSmall | DeprecatedSizes | SizeLarge;
|
|
28
28
|
border?: ThemeDark | ThemeLight;
|
|
29
29
|
'aria-label'?: string;
|
|
30
|
+
position?: 'top-right' | 'bottom-right';
|
|
30
31
|
} & CommonProps;
|
|
31
32
|
|
|
32
33
|
const mapLegacySize = {
|
|
@@ -43,6 +44,7 @@ const Badge = ({
|
|
|
43
44
|
border = Theme.LIGHT,
|
|
44
45
|
'aria-label': ariaLabel,
|
|
45
46
|
children,
|
|
47
|
+
position = 'bottom-right',
|
|
46
48
|
}: BadgeProps) => {
|
|
47
49
|
// medium is deprecated, so we map it to small
|
|
48
50
|
const size = sizeProp === Size.MEDIUM ? Size.SMALL : sizeProp;
|
|
@@ -56,7 +58,14 @@ const Badge = ({
|
|
|
56
58
|
);
|
|
57
59
|
|
|
58
60
|
return (
|
|
59
|
-
<div
|
|
61
|
+
<div
|
|
62
|
+
aria-label={ariaLabel}
|
|
63
|
+
className={classes}
|
|
64
|
+
style={{
|
|
65
|
+
'--badge-mask-position': position === 'top-right' ? 'bottom' : 'top',
|
|
66
|
+
'--badge-bottom-position': position === 'top-right' ? 'calc(var(--badge-size) * 2)' : 0,
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
60
69
|
<div className="tw-badge__children">{children}</div>
|
|
61
70
|
<Circle size={mapLegacySize[size]} fixedSize className="tw-badge__content">
|
|
62
71
|
{badge}
|
|
@@ -6,30 +6,6 @@
|
|
|
6
6
|
cursor: pointer;
|
|
7
7
|
position: relative;
|
|
8
8
|
}
|
|
9
|
-
.np-circular-btn .tw-icon {
|
|
10
|
-
position: absolute;
|
|
11
|
-
top: 16px;
|
|
12
|
-
top: var(--size-16);
|
|
13
|
-
pointer-events: none;
|
|
14
|
-
color: white;
|
|
15
|
-
transition: color 0.15s ease-in-out;
|
|
16
|
-
width: 100%;
|
|
17
|
-
left: 0;
|
|
18
|
-
}
|
|
19
|
-
[dir="rtl"] .np-circular-btn .tw-icon {
|
|
20
|
-
right: 0;
|
|
21
|
-
left: auto;
|
|
22
|
-
left: initial;
|
|
23
|
-
}
|
|
24
|
-
@media (max-width: 320px) {
|
|
25
|
-
.np-circular-btn .tw-icon {
|
|
26
|
-
top: 8px;
|
|
27
|
-
top: var(--size-8);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
.np-circular-btn .tw-icon > svg {
|
|
31
|
-
margin: 0 auto;
|
|
32
|
-
}
|
|
33
9
|
.np-theme-personal .np-circular-btn {
|
|
34
10
|
/* stylelint-disable-next-line no-duplicate-selectors */
|
|
35
11
|
}
|
|
@@ -9,23 +9,23 @@
|
|
|
9
9
|
cursor: pointer;
|
|
10
10
|
position: relative;
|
|
11
11
|
|
|
12
|
-
.tw-icon {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
// .tw-icon {
|
|
13
|
+
// position: absolute;
|
|
14
|
+
// top: var(--size-16);
|
|
15
|
+
// pointer-events: none;
|
|
16
|
+
// color: white;
|
|
17
|
+
// transition: color 0.15s ease-in-out;
|
|
18
|
+
// width: 100%;
|
|
19
|
+
// .left(0);
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
// @media (--screen-400-zoom) {
|
|
22
|
+
// top: var(--size-8);
|
|
23
|
+
// }
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
25
|
+
// > svg {
|
|
26
|
+
// margin: 0 auto;
|
|
27
|
+
// }
|
|
28
|
+
// }
|
|
29
29
|
|
|
30
30
|
.np-theme-personal & {
|
|
31
31
|
/* stylelint-disable-next-line no-duplicate-selectors */
|
|
@@ -28,14 +28,12 @@ const CircularButton = ({
|
|
|
28
28
|
}: CircularButtonProps) => {
|
|
29
29
|
const classes = clsx('btn np-btn', 'm-b-1', typeClassMap[type], priorityClassMap[priority]);
|
|
30
30
|
|
|
31
|
-
const iconElement = Number(icon.props.size) !== 24 ? cloneElement(icon, { size: 24 }) : icon;
|
|
32
|
-
|
|
33
31
|
const isTinyViewport = useMedia(`(max-width: ${Breakpoint.ZOOM_400}px)`);
|
|
34
32
|
|
|
35
33
|
return (
|
|
36
34
|
<label className={clsx('np-circular-btn', priority, type, disabled && 'disabled', className)}>
|
|
37
35
|
<Circle
|
|
38
|
-
as="
|
|
36
|
+
as="button"
|
|
39
37
|
// @ts-expect-error it's input[type=button] element
|
|
40
38
|
type="button"
|
|
41
39
|
size={isTinyViewport ? 64 : 56}
|
|
@@ -43,8 +41,9 @@ const CircularButton = ({
|
|
|
43
41
|
className={classes}
|
|
44
42
|
disabled={disabled}
|
|
45
43
|
{...rest}
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
>
|
|
45
|
+
{icon}
|
|
46
|
+
</Circle>
|
|
48
47
|
<Body as="span" className="np-circular-btn__label" type={Typography.BODY_DEFAULT_BOLD}>
|
|
49
48
|
{children}
|
|
50
49
|
</Body>
|
|
@@ -4,4 +4,21 @@
|
|
|
4
4
|
width: var(--circle-size);
|
|
5
5
|
height: var(--circle-size);
|
|
6
6
|
flex-shrink: 0;
|
|
7
|
+
font-size: var(--circle-font-size);
|
|
8
|
+
font-weight: 600;
|
|
9
|
+
font-weight: var(--font-weight-semi-bold);
|
|
10
|
+
line-height: 1;
|
|
11
|
+
}
|
|
12
|
+
.np-circle img {
|
|
13
|
+
border-radius: 9999px;
|
|
14
|
+
border-radius: var(--radius-full);
|
|
15
|
+
width: 100%;
|
|
16
|
+
height: 100%;
|
|
17
|
+
}
|
|
18
|
+
.np-circle .np-display {
|
|
19
|
+
font-size: var(--circle-font-size);
|
|
20
|
+
}
|
|
21
|
+
.np-circle .tw-icon > svg {
|
|
22
|
+
height: var(--circle-icon-size);
|
|
23
|
+
width: var(--circle-icon-size);
|
|
7
24
|
}
|
|
@@ -3,4 +3,26 @@
|
|
|
3
3
|
width: var(--circle-size);
|
|
4
4
|
height: var(--circle-size);
|
|
5
5
|
flex-shrink: 0;
|
|
6
|
+
|
|
7
|
+
img {
|
|
8
|
+
border-radius: var(--radius-full);
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: 100%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// circle like components set custom typography styles for default (Inter) font
|
|
14
|
+
font-size: var(--circle-font-size);
|
|
15
|
+
font-weight: var(--font-weight-semi-bold);
|
|
16
|
+
line-height: 1;
|
|
17
|
+
|
|
18
|
+
// circle like components set custom typography styles for Wise Sand font
|
|
19
|
+
.np-display {
|
|
20
|
+
font-size: var(--circle-font-size);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// circle like components have custom icon sizes
|
|
24
|
+
.tw-icon > svg {
|
|
25
|
+
height: var(--circle-icon-size);
|
|
26
|
+
width: var(--circle-icon-size);
|
|
27
|
+
}
|
|
6
28
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HTMLAttributes, forwardRef } from 'react';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
|
|
4
|
-
export type ShapeSize = 16 | 24 | 32 | 40 | 48 | 56 |
|
|
4
|
+
export type ShapeSize = 16 | 24 | 32 | 40 | 48 | 56 | 72;
|
|
5
5
|
|
|
6
6
|
export type Props = {
|
|
7
7
|
/**
|
|
@@ -19,6 +19,32 @@ export type Props = {
|
|
|
19
19
|
fixedSize?: boolean;
|
|
20
20
|
} & HTMLAttributes<HTMLDivElement>;
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* circle like components has custom sizes for icons
|
|
24
|
+
*/
|
|
25
|
+
const mapIconSize = {
|
|
26
|
+
16: 12,
|
|
27
|
+
24: 16,
|
|
28
|
+
32: 18,
|
|
29
|
+
40: 20,
|
|
30
|
+
48: 24,
|
|
31
|
+
56: 28,
|
|
32
|
+
72: 36,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* circle like components have custom font styles
|
|
37
|
+
*/
|
|
38
|
+
const mapFontSize = {
|
|
39
|
+
16: 8,
|
|
40
|
+
24: 12,
|
|
41
|
+
32: 14,
|
|
42
|
+
40: 18,
|
|
43
|
+
48: 22,
|
|
44
|
+
56: 26,
|
|
45
|
+
72: 30,
|
|
46
|
+
};
|
|
47
|
+
|
|
22
48
|
const Circle = forwardRef(function Circle(
|
|
23
49
|
{
|
|
24
50
|
as: Element = 'div',
|
|
@@ -35,7 +61,12 @@ const Circle = forwardRef(function Circle(
|
|
|
35
61
|
<Element
|
|
36
62
|
{...props}
|
|
37
63
|
ref={ref}
|
|
38
|
-
style={{
|
|
64
|
+
style={{
|
|
65
|
+
...style,
|
|
66
|
+
'--circle-size': fixedSize ? `${size}px` : `var(--size-${size})`,
|
|
67
|
+
'--circle-icon-size': `${mapIconSize[size]}px`,
|
|
68
|
+
'--circle-font-size': `${mapFontSize[size]}px`,
|
|
69
|
+
}}
|
|
39
70
|
className={clsx('np-circle', 'd-flex align-items-center justify-content-center', className)}
|
|
40
71
|
>
|
|
41
72
|
{children}
|
package/src/common/index.js
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function getInitials(name: string) {
|
|
2
|
+
const allInitials = name
|
|
3
|
+
.split(' ')
|
|
4
|
+
.map((part) => part[0])
|
|
5
|
+
.join('')
|
|
6
|
+
.toUpperCase();
|
|
7
|
+
|
|
8
|
+
if (allInitials.length === 1) {
|
|
9
|
+
return allInitials[0];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return allInitials[0] + allInitials.slice(-1);
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
.np-notification-dot {
|
|
2
|
+
--badge-notification-dot-size: 14px;
|
|
3
|
+
width: 14px;
|
|
4
|
+
width: var(--badge-notification-dot-size);
|
|
5
|
+
height: 14px;
|
|
6
|
+
height: var(--badge-notification-dot-size);
|
|
7
|
+
background-color: var(--color-sentiment-negative);
|
|
8
|
+
border-radius: 9999px;
|
|
9
|
+
border-radius: var(--radius-full);
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
type Props = Pick<HTMLAttributes<HTMLDivElement>, 'className' | 'style'>;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated make this element part pre build badges
|
|
7
|
+
*/
|
|
8
|
+
export default function NotificationDot(props: Props) {
|
|
9
|
+
return <div {...props} className="np-notification-dot" />;
|
|
10
|
+
}
|
package/src/display/Display.tsx
CHANGED
|
@@ -18,7 +18,7 @@ function Display({
|
|
|
18
18
|
id,
|
|
19
19
|
}: Props) {
|
|
20
20
|
return (
|
|
21
|
-
<Heading id={id} className={clsx(`np-text-${type}`, 'text-primary', className)}>
|
|
21
|
+
<Heading id={id} className={clsx('np-display', `np-text-${type}`, 'text-primary', className)}>
|
|
22
22
|
{children}
|
|
23
23
|
</Heading>
|
|
24
24
|
);
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type { ActionOptionProps } from './actionOption';
|
|
|
8
8
|
export type { SelectOptionProps, SelectOptionValue, SelectOptiopsSection } from './selectOption';
|
|
9
9
|
export type { AlertAction, AlertProps, AlertType } from './alert';
|
|
10
10
|
export type { AvatarProps } from './avatar';
|
|
11
|
+
export type { AvatarViewProps } from './avatarView';
|
|
11
12
|
export type { BadgeProps } from './badge';
|
|
12
13
|
export type { CardProps } from './card';
|
|
13
14
|
export type { CarouselProps } from './carousel';
|
|
@@ -102,6 +103,7 @@ export { default as ActionOption } from './actionOption';
|
|
|
102
103
|
export { default as SelectOption } from './selectOption';
|
|
103
104
|
export { default as Alert } from './alert';
|
|
104
105
|
export { default as Avatar } from './avatar';
|
|
106
|
+
export { default as AvatarView } from './avatarView';
|
|
105
107
|
export { default as AvatarWrapper } from './avatarWrapper';
|
|
106
108
|
export { default as Badge } from './badge';
|
|
107
109
|
export { default as Body } from './body';
|
|
@@ -243,7 +245,9 @@ export {
|
|
|
243
245
|
getLangFromLocale,
|
|
244
246
|
isBrowser,
|
|
245
247
|
isServerSide,
|
|
248
|
+
getInitials,
|
|
246
249
|
} from './common';
|
|
250
|
+
export { getAvatarColorFromSeed } from './avatar/colors';
|
|
247
251
|
|
|
248
252
|
/**
|
|
249
253
|
* Translations
|