@arcblock/ux 2.13.7 → 2.13.8
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/lib/UserCard/Cards/avatar-only.d.ts +3 -2
- package/lib/UserCard/Cards/basic-info.d.ts +3 -2
- package/lib/UserCard/Cards/basic-info.js +12 -6
- package/lib/UserCard/Cards/index.d.ts +3 -2
- package/lib/UserCard/Cards/name-only.d.ts +4 -2
- package/lib/UserCard/Cards/name-only.js +3 -2
- package/lib/UserCard/Container/dialog.js +1 -1
- package/lib/UserCard/Content/basic.d.ts +2 -1
- package/lib/UserCard/Content/basic.js +195 -67
- package/lib/UserCard/Content/minimal.d.ts +2 -2
- package/lib/UserCard/Content/minimal.js +2 -0
- package/lib/UserCard/Content/tooltip-avatar.d.ts +4 -4
- package/lib/UserCard/Content/tooltip-avatar.js +4 -3
- package/lib/UserCard/components.d.ts +2 -2
- package/lib/UserCard/components.js +9 -3
- package/lib/UserCard/index.js +36 -4
- package/lib/UserCard/types.d.ts +7 -4
- package/lib/UserCard/utils.d.ts +2 -0
- package/lib/UserCard/utils.js +33 -0
- package/package.json +6 -6
- package/src/UserCard/Cards/avatar-only.tsx +3 -2
- package/src/UserCard/Cards/basic-info.tsx +17 -5
- package/src/UserCard/Cards/index.tsx +3 -2
- package/src/UserCard/Cards/name-only.tsx +4 -4
- package/src/UserCard/Container/dialog.tsx +1 -1
- package/src/UserCard/Content/basic.tsx +191 -57
- package/src/UserCard/Content/minimal.tsx +4 -3
- package/src/UserCard/Content/tooltip-avatar.tsx +10 -5
- package/src/UserCard/components.tsx +17 -7
- package/src/UserCard/index.tsx +41 -3
- package/src/UserCard/types.ts +11 -4
- package/src/UserCard/utils.ts +33 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps } from '../types';
|
3
|
-
interface AvatarOnlyCardProps extends UserCardProps {
|
2
|
+
import { UserCardProps, User } from '../types';
|
3
|
+
interface AvatarOnlyCardProps extends Omit<UserCardProps, 'user'> {
|
4
|
+
user: User;
|
4
5
|
renderCardContent: () => React.ReactNode;
|
5
6
|
shouldShowHoverCard: boolean;
|
6
7
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps } from '../types';
|
3
|
-
interface BasicCardProps extends UserCardProps {
|
2
|
+
import { UserCardProps, User } from '../types';
|
3
|
+
interface BasicCardProps extends Omit<UserCardProps, 'user'> {
|
4
|
+
user: User;
|
4
5
|
shouldShowHoverCard: boolean;
|
5
6
|
renderCardContent?: () => React.ReactNode | null;
|
6
7
|
isFull?: boolean;
|
@@ -12,6 +12,8 @@ function BasicCard(props) {
|
|
12
12
|
renderCustomContent,
|
13
13
|
isFull = true,
|
14
14
|
infoType = InfoType.Minimal,
|
15
|
+
renderFields,
|
16
|
+
popupRenderFields,
|
15
17
|
...rest
|
16
18
|
} = props;
|
17
19
|
return /*#__PURE__*/_jsxs(Box, {
|
@@ -28,12 +30,16 @@ function BasicCard(props) {
|
|
28
30
|
...rest
|
29
31
|
}), infoType === InfoType.Basic && /*#__PURE__*/_jsx(BasicContent, {
|
30
32
|
user: user,
|
31
|
-
isFull: isFull
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
isFull: isFull,
|
34
|
+
renderFields: renderFields
|
35
|
+
}), /*#__PURE__*/_jsx(Box, {
|
36
|
+
className: "user-card__footer",
|
37
|
+
children: renderCustomContent && /*#__PURE__*/_jsx(Box, {
|
38
|
+
sx: {
|
39
|
+
mt: 1.5
|
40
|
+
},
|
41
|
+
children: renderCustomContent()
|
42
|
+
})
|
37
43
|
})]
|
38
44
|
});
|
39
45
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps } from '../types';
|
3
|
-
interface DetailedCardProps extends UserCardProps {
|
2
|
+
import { UserCardProps, User } from '../types';
|
3
|
+
interface DetailedCardProps extends Omit<UserCardProps, 'user'> {
|
4
|
+
user: User;
|
4
5
|
shouldShowHoverCard: boolean;
|
5
6
|
renderCardContent?: () => React.ReactNode | null;
|
6
7
|
}
|
@@ -1,3 +1,5 @@
|
|
1
|
-
import { UserCardProps } from '../types';
|
2
|
-
declare function NameOnlyCard(props: UserCardProps
|
1
|
+
import { UserCardProps, User } from '../types';
|
2
|
+
declare function NameOnlyCard(props: Omit<UserCardProps, 'user'> & {
|
3
|
+
user: User;
|
4
|
+
}): import("react/jsx-runtime").JSX.Element;
|
3
5
|
export default NameOnlyCard;
|
@@ -6,10 +6,11 @@ import { renderAvatar } from '../components';
|
|
6
6
|
function NameOnlyCard(props) {
|
7
7
|
const {
|
8
8
|
user,
|
9
|
-
avatarSize = 48
|
9
|
+
avatarSize = 48,
|
10
|
+
onAvatarClick
|
10
11
|
} = props;
|
11
12
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
12
|
-
children: [renderAvatar(user, avatarSize, props.avatarProps), /*#__PURE__*/_jsx(Typography, {
|
13
|
+
children: [renderAvatar(user, avatarSize, props.avatarProps, onAvatarClick), /*#__PURE__*/_jsx(Typography, {
|
13
14
|
variant: "body1",
|
14
15
|
children: user.fullName || user.email || user.did
|
15
16
|
})]
|
@@ -2,6 +2,7 @@ import { User } from '../types';
|
|
2
2
|
interface BasicContentProps {
|
3
3
|
user: User;
|
4
4
|
isFull?: boolean;
|
5
|
+
renderFields?: string[];
|
5
6
|
}
|
6
|
-
declare function BasicContent({ user, isFull }: BasicContentProps): import("react/jsx-runtime").JSX.Element;
|
7
|
+
declare function BasicContent({ user, isFull, renderFields }: BasicContentProps): import("react/jsx-runtime").JSX.Element | null;
|
7
8
|
export default BasicContent;
|
@@ -1,13 +1,25 @@
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
-
import { Typography, Box } from '@mui/material';
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
2
|
+
import { Typography, Box, Grid } from '@mui/material';
|
3
3
|
import { useCreation } from 'ahooks';
|
4
4
|
import styled from '@emotion/styled';
|
5
|
+
import isArray from 'lodash/isArray';
|
6
|
+
import { Icon as IconifyIcon } from '@iconify/react';
|
7
|
+
import infoCircleIcon from '@iconify-icons/tabler/info-circle';
|
5
8
|
import LinkIcon from '@arcblock/icons/lib/Link';
|
9
|
+
import PhoneIcon from '@arcblock/icons/lib/Phone';
|
6
10
|
import LocationIcon from '@arcblock/icons/lib/Location';
|
7
11
|
import EmailIcon from '@arcblock/icons/lib/Email';
|
8
12
|
import TimezoneIcon from '@arcblock/icons/lib/Timezone';
|
9
|
-
import { withoutProtocol } from 'ufo';
|
13
|
+
import { joinURL, withoutProtocol } from 'ufo';
|
14
|
+
import { Fragment, useState, useMemo, useCallback } from 'react';
|
10
15
|
import Clock from './clock';
|
16
|
+
const IconMap = {
|
17
|
+
timezone: TimezoneIcon,
|
18
|
+
email: EmailIcon,
|
19
|
+
phone: PhoneIcon,
|
20
|
+
location: LocationIcon,
|
21
|
+
link: LinkIcon
|
22
|
+
};
|
11
23
|
|
12
24
|
/**
|
13
25
|
* 格式化链接显示
|
@@ -20,10 +32,106 @@ const iconSize = {
|
|
20
32
|
width: 16,
|
21
33
|
height: 16
|
22
34
|
};
|
35
|
+
function TimeZoneField({
|
36
|
+
value
|
37
|
+
}) {
|
38
|
+
return /*#__PURE__*/_jsxs(Box, {
|
39
|
+
display: "flex",
|
40
|
+
alignItems: "center",
|
41
|
+
gap: 1,
|
42
|
+
className: "user-card__timezone-field",
|
43
|
+
children: [/*#__PURE__*/_jsx(TimezoneIcon, {
|
44
|
+
...iconSize
|
45
|
+
}), /*#__PURE__*/_jsx(LineText, {
|
46
|
+
variant: "body2",
|
47
|
+
color: "grey.800",
|
48
|
+
children: /*#__PURE__*/_jsx(Clock, {
|
49
|
+
value: value,
|
50
|
+
variant: "body2",
|
51
|
+
color: "grey.800"
|
52
|
+
})
|
53
|
+
})]
|
54
|
+
});
|
55
|
+
}
|
56
|
+
function LinkField({
|
57
|
+
value
|
58
|
+
}) {
|
59
|
+
const [useFallback, setUseFallback] = useState(false);
|
60
|
+
const faviconUrl = useCreation(() => {
|
61
|
+
try {
|
62
|
+
const url = new URL(value);
|
63
|
+
return joinURL(url.origin, 'favicon.ico');
|
64
|
+
} catch (e) {
|
65
|
+
return '';
|
66
|
+
}
|
67
|
+
}, [value]);
|
68
|
+
const handleImageError = () => {
|
69
|
+
setUseFallback(true);
|
70
|
+
};
|
71
|
+
return /*#__PURE__*/_jsxs(Box, {
|
72
|
+
display: "flex",
|
73
|
+
alignItems: "center",
|
74
|
+
gap: 1,
|
75
|
+
children: [faviconUrl && !useFallback ? /*#__PURE__*/_jsx("img", {
|
76
|
+
src: faviconUrl,
|
77
|
+
alt: "site icon",
|
78
|
+
style: {
|
79
|
+
width: 14,
|
80
|
+
height: 14,
|
81
|
+
objectFit: 'contain'
|
82
|
+
},
|
83
|
+
onError: handleImageError
|
84
|
+
}) : /*#__PURE__*/_jsx(LinkIcon, {
|
85
|
+
...iconSize
|
86
|
+
}), /*#__PURE__*/_jsx(LineText, {
|
87
|
+
children: /*#__PURE__*/_jsx(Typography, {
|
88
|
+
component: "a",
|
89
|
+
href: value,
|
90
|
+
style: {
|
91
|
+
textDecoration: 'none'
|
92
|
+
},
|
93
|
+
target: "_blank",
|
94
|
+
variant: "body2",
|
95
|
+
color: "grey.800",
|
96
|
+
rel: "noopener noreferrer",
|
97
|
+
children: formatLinkDisplay(value)
|
98
|
+
})
|
99
|
+
})]
|
100
|
+
});
|
101
|
+
}
|
102
|
+
function BasicField({
|
103
|
+
field,
|
104
|
+
value
|
105
|
+
}) {
|
106
|
+
const Icon = IconMap[field];
|
107
|
+
return /*#__PURE__*/_jsxs(Box, {
|
108
|
+
display: "flex",
|
109
|
+
alignItems: "center",
|
110
|
+
gap: 1,
|
111
|
+
className: `user-card__${field}-field`,
|
112
|
+
children: [Icon ? /*#__PURE__*/_jsx(Icon, {
|
113
|
+
...iconSize
|
114
|
+
}) : /*#__PURE__*/_jsx(IconifyIcon, {
|
115
|
+
icon: infoCircleIcon,
|
116
|
+
...iconSize
|
117
|
+
}), /*#__PURE__*/_jsx(LineText, {
|
118
|
+
variant: "body2",
|
119
|
+
color: "grey.800",
|
120
|
+
children: value
|
121
|
+
})]
|
122
|
+
}, field);
|
123
|
+
}
|
23
124
|
function BasicContent({
|
24
125
|
user,
|
25
|
-
isFull = false
|
126
|
+
isFull = false,
|
127
|
+
renderFields
|
26
128
|
}) {
|
129
|
+
const fields = useCreation(() => {
|
130
|
+
return renderFields ?? ['bio', 'email', 'phone', 'location', 'timezone', 'link'];
|
131
|
+
}, [renderFields]);
|
132
|
+
const includeBio = useCreation(() => {
|
133
|
+
return fields.includes('bio');
|
134
|
+
}, [fields]);
|
27
135
|
const metadata = useCreation(() => {
|
28
136
|
return user.metadata ?? {
|
29
137
|
joinedAt: user?.createdAt,
|
@@ -34,83 +142,103 @@ function BasicContent({
|
|
34
142
|
}
|
35
143
|
};
|
36
144
|
}, [user]);
|
145
|
+
const address = useCreation(() => {
|
146
|
+
return user.address;
|
147
|
+
}, [user.address]);
|
148
|
+
const getFieldValue = useCallback(field => {
|
149
|
+
if (!field) return '';
|
150
|
+
switch (field) {
|
151
|
+
case 'bio':
|
152
|
+
return user.metadata?.bio || '';
|
153
|
+
case 'email':
|
154
|
+
return metadata.email || user.email || '';
|
155
|
+
case 'phone':
|
156
|
+
return metadata.phone?.phoneNumber || user.phone || '';
|
157
|
+
case 'location':
|
158
|
+
return address?.city || metadata.location || '';
|
159
|
+
case 'timezone':
|
160
|
+
return metadata.timezone || '';
|
161
|
+
case 'link':
|
162
|
+
return metadata.links?.map(link => link.url).filter(Boolean) || [];
|
163
|
+
default:
|
164
|
+
return user[field] || '';
|
165
|
+
}
|
166
|
+
}, [user, metadata, address]);
|
37
167
|
|
38
|
-
//
|
39
|
-
const
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
168
|
+
// 计算实际可见的字段数量
|
169
|
+
const visibleFields = useMemo(() => {
|
170
|
+
return fields.filter(field => {
|
171
|
+
if (field === 'bio') return false; // bio field is handled separately
|
172
|
+
const value = getFieldValue(field);
|
173
|
+
if (value === undefined || value === null || value === '') return false;
|
174
|
+
if (isArray(value)) {
|
175
|
+
return value.length > 0;
|
176
|
+
}
|
177
|
+
return String(value).trim().length > 0;
|
178
|
+
});
|
179
|
+
}, [fields, getFieldValue]);
|
180
|
+
|
181
|
+
// 判断是否需要使用两列布局
|
182
|
+
const useDoubleColumn = visibleFields.length > 4;
|
183
|
+
if (fields.length === 0) {
|
184
|
+
return null;
|
185
|
+
}
|
186
|
+
const renderField = field => {
|
187
|
+
const value = getFieldValue(field);
|
188
|
+
if (!value || field === 'bio') {
|
189
|
+
return null;
|
190
|
+
}
|
191
|
+
if (isArray(value)) {
|
192
|
+
return /*#__PURE__*/_jsx(Fragment, {
|
193
|
+
children: field === 'link' ? /*#__PURE__*/_jsx(_Fragment, {
|
194
|
+
children: value.map(link => /*#__PURE__*/_jsx(LinkField, {
|
195
|
+
value: link
|
196
|
+
}, link))
|
197
|
+
}) : /*#__PURE__*/_jsx(_Fragment, {
|
198
|
+
children: value.map(item => /*#__PURE__*/_jsx(BasicField, {
|
199
|
+
field: field,
|
200
|
+
value: item
|
201
|
+
}, item))
|
54
202
|
})
|
55
|
-
})
|
56
|
-
}
|
203
|
+
}, field);
|
204
|
+
}
|
205
|
+
if (field === 'timezone') {
|
206
|
+
return /*#__PURE__*/_jsx(TimeZoneField, {
|
207
|
+
value: value
|
208
|
+
}, field);
|
209
|
+
}
|
210
|
+
return /*#__PURE__*/_jsx(BasicField, {
|
211
|
+
field: field,
|
212
|
+
value: value
|
213
|
+
}, field);
|
57
214
|
};
|
58
215
|
return /*#__PURE__*/_jsxs(Box, {
|
59
216
|
mt: 1,
|
60
217
|
display: "flex",
|
61
218
|
flexDirection: "column",
|
62
219
|
gap: 1.5,
|
63
|
-
|
220
|
+
className: "user-card__basic-content",
|
221
|
+
children: [includeBio && user.metadata?.bio && /*#__PURE__*/_jsx(LineText, {
|
64
222
|
variant: "body2",
|
65
223
|
color: "grey.800",
|
224
|
+
className: "user-card__bio-field",
|
66
225
|
children: user.metadata.bio
|
67
|
-
}), /*#__PURE__*/
|
226
|
+
}), useDoubleColumn ? /*#__PURE__*/_jsx(Grid, {
|
227
|
+
container: true,
|
228
|
+
spacing: 0.5,
|
229
|
+
children: fields.map(field => {
|
230
|
+
if (field === 'bio' || !getFieldValue(field)) return null;
|
231
|
+
return /*#__PURE__*/_jsx(Grid, {
|
232
|
+
item: true,
|
233
|
+
xs: 6,
|
234
|
+
children: renderField(field)
|
235
|
+
}, field);
|
236
|
+
})
|
237
|
+
}) : /*#__PURE__*/_jsx(Box, {
|
68
238
|
display: "flex",
|
69
239
|
flexDirection: "column",
|
70
240
|
gap: 0.5,
|
71
|
-
children:
|
72
|
-
display: "flex",
|
73
|
-
alignItems: "center",
|
74
|
-
gap: 1,
|
75
|
-
children: [/*#__PURE__*/_jsx(LinkIcon, {
|
76
|
-
...iconSize
|
77
|
-
}), /*#__PURE__*/_jsx(LineText, {
|
78
|
-
children: /*#__PURE__*/_jsx(Typography, {
|
79
|
-
component: "a",
|
80
|
-
href: firstLink.url,
|
81
|
-
style: {
|
82
|
-
textDecoration: 'none'
|
83
|
-
},
|
84
|
-
target: "_blank",
|
85
|
-
variant: "body2",
|
86
|
-
color: "grey.800",
|
87
|
-
rel: "noopener noreferrer",
|
88
|
-
children: formatLinkDisplay(firstLink.url)
|
89
|
-
})
|
90
|
-
})]
|
91
|
-
}), metadata.location && /*#__PURE__*/_jsxs(Box, {
|
92
|
-
display: "flex",
|
93
|
-
alignItems: "center",
|
94
|
-
gap: 1,
|
95
|
-
children: [/*#__PURE__*/_jsx(LocationIcon, {
|
96
|
-
...iconSize
|
97
|
-
}), /*#__PURE__*/_jsx(LineText, {
|
98
|
-
variant: "body2",
|
99
|
-
color: "grey.800",
|
100
|
-
children: metadata.location
|
101
|
-
})]
|
102
|
-
}), isFull && moreContent(), (metadata.email || user.email) && /*#__PURE__*/_jsxs(Box, {
|
103
|
-
display: "flex",
|
104
|
-
alignItems: "center",
|
105
|
-
gap: 1,
|
106
|
-
children: [/*#__PURE__*/_jsx(EmailIcon, {
|
107
|
-
...iconSize
|
108
|
-
}), /*#__PURE__*/_jsx(LineText, {
|
109
|
-
variant: "body2",
|
110
|
-
color: "grey.800",
|
111
|
-
children: metadata.email || user.email
|
112
|
-
})]
|
113
|
-
})]
|
241
|
+
children: fields.map(field => renderField(field))
|
114
242
|
})]
|
115
243
|
});
|
116
244
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps } from '../types';
|
2
|
+
import { User, UserCardProps } from '../types';
|
3
3
|
interface MinimalContentProps extends UserCardProps {
|
4
|
-
user:
|
4
|
+
user: User;
|
5
5
|
avatarSize: number;
|
6
6
|
shouldShowHoverCard: boolean;
|
7
7
|
renderCardContent?: () => React.ReactNode | null;
|
@@ -22,6 +22,7 @@ function MinimalContent(props) {
|
|
22
22
|
display: "flex",
|
23
23
|
justifyContent: "space-between",
|
24
24
|
alignItems: "center",
|
25
|
+
className: "user-card__avatar-content",
|
25
26
|
children: [/*#__PURE__*/_jsxs(Box, {
|
26
27
|
display: "flex",
|
27
28
|
justifyContent: "flex-start",
|
@@ -40,6 +41,7 @@ function MinimalContent(props) {
|
|
40
41
|
variant: "subtitle1",
|
41
42
|
fontWeight: 500,
|
42
43
|
color: "text.primary",
|
44
|
+
className: "user-card__full-name-label",
|
43
45
|
fontSize: 18,
|
44
46
|
noWrap: true,
|
45
47
|
sx: {
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps } from '../types';
|
3
|
-
interface TooltipAvatarProps {
|
4
|
-
user:
|
2
|
+
import { User, UserCardProps } from '../types';
|
3
|
+
interface TooltipAvatarProps extends UserCardProps {
|
4
|
+
user: User;
|
5
5
|
avatarSize: number;
|
6
6
|
shouldShowHoverCard: boolean;
|
7
7
|
renderCardContent?: () => React.ReactNode | null;
|
@@ -13,5 +13,5 @@ interface TooltipAvatarProps {
|
|
13
13
|
* 统一处理头像的Tooltip显示组件
|
14
14
|
* 根据条件显示普通Tooltip、自定义Tooltip内容或无Tooltip的头像
|
15
15
|
*/
|
16
|
-
declare function TooltipAvatar({ user, avatarSize, shouldShowHoverCard, renderCardContent, tooltipTitle, tooltipProps, avatarProps, }: TooltipAvatarProps): import("react/jsx-runtime").JSX.Element;
|
16
|
+
declare function TooltipAvatar({ user, avatarSize, shouldShowHoverCard, renderCardContent, tooltipTitle, tooltipProps, avatarProps, onAvatarClick, }: TooltipAvatarProps): import("react/jsx-runtime").JSX.Element;
|
17
17
|
export default TooltipAvatar;
|
@@ -14,11 +14,12 @@ function TooltipAvatar({
|
|
14
14
|
renderCardContent,
|
15
15
|
tooltipTitle,
|
16
16
|
tooltipProps,
|
17
|
-
avatarProps
|
17
|
+
avatarProps,
|
18
|
+
onAvatarClick
|
18
19
|
}) {
|
19
20
|
const avatarElement = /*#__PURE__*/_jsx(Box, {
|
20
21
|
display: "inline-block",
|
21
|
-
children: renderAvatar(user, avatarSize, avatarProps)
|
22
|
+
children: renderAvatar(user, avatarSize, avatarProps, onAvatarClick, shouldShowHoverCard || !!tooltipTitle)
|
22
23
|
});
|
23
24
|
// 使用普通文本Tooltip
|
24
25
|
if (tooltipTitle) {
|
@@ -44,7 +45,7 @@ function TooltipAvatar({
|
|
44
45
|
'& .MuiTooltip-tooltip': {
|
45
46
|
backgroundColor: 'transparent',
|
46
47
|
p: 0,
|
47
|
-
maxWidth:
|
48
|
+
maxWidth: 500,
|
48
49
|
zIndex: 1000
|
49
50
|
}
|
50
51
|
}
|
@@ -1,4 +1,4 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps } from './types';
|
3
|
-
export declare const renderAvatar: (user:
|
2
|
+
import { User, UserCardProps } from './types';
|
3
|
+
export declare const renderAvatar: (user: User, avatarSize?: number, avatarProps?: UserCardProps["avatarProps"], onAvatarClick?: UserCardProps["onAvatarClick"], shouldShowHoverCard?: boolean) => import("react/jsx-runtime").JSX.Element;
|
4
4
|
export declare const renderTopRight: (renderTopRightContent: (() => React.ReactNode) | undefined, topRightMaxWidth?: number) => import("react/jsx-runtime").JSX.Element | null;
|
@@ -5,7 +5,10 @@ import Avatar from '../Avatar';
|
|
5
5
|
import { createNameOnlyAvatar } from './utils';
|
6
6
|
|
7
7
|
// 渲染头像
|
8
|
-
export const renderAvatar = (user, avatarSize = 48, avatarProps = undefined) => {
|
8
|
+
export const renderAvatar = (user, avatarSize = 48, avatarProps = undefined, onAvatarClick = undefined, shouldShowHoverCard = false) => {
|
9
|
+
const onClick = e => {
|
10
|
+
onAvatarClick?.(user, e);
|
11
|
+
};
|
9
12
|
// 如果用户没有头像,则显示名称首字母头像
|
10
13
|
if (!user.avatar) {
|
11
14
|
const avatarContent = createNameOnlyAvatar(user);
|
@@ -13,9 +16,10 @@ export const renderAvatar = (user, avatarSize = 48, avatarProps = undefined) =>
|
|
13
16
|
size: avatarSize,
|
14
17
|
did: user.did,
|
15
18
|
variant: "circle",
|
19
|
+
onClick: onClick,
|
16
20
|
sx: {
|
17
21
|
fontSize: avatarSize * 0.4,
|
18
|
-
cursor: 'pointer'
|
22
|
+
cursor: shouldShowHoverCard || onAvatarClick ? 'pointer' : 'default'
|
19
23
|
},
|
20
24
|
...(avatarProps || {}),
|
21
25
|
children: avatarContent
|
@@ -28,8 +32,9 @@ export const renderAvatar = (user, avatarSize = 48, avatarProps = undefined) =>
|
|
28
32
|
did: user.did,
|
29
33
|
variant: "circle",
|
30
34
|
style: {
|
31
|
-
cursor: 'pointer'
|
35
|
+
cursor: shouldShowHoverCard || onAvatarClick ? 'pointer' : 'default'
|
32
36
|
},
|
37
|
+
onClick: onClick,
|
33
38
|
src: user.avatar,
|
34
39
|
alt: user.fullName || '',
|
35
40
|
...(avatarProps || {})
|
@@ -43,6 +48,7 @@ export const renderTopRight = (renderTopRightContent, topRightMaxWidth = 120) =>
|
|
43
48
|
sx: {
|
44
49
|
maxWidth: topRightMaxWidth
|
45
50
|
},
|
51
|
+
className: "user-card__top-right-content",
|
46
52
|
children: renderTopRightContent()
|
47
53
|
});
|
48
54
|
}
|
package/lib/UserCard/index.js
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import { useRef } from 'react';
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
3
3
|
import { CardType } from './types';
|
4
4
|
import AvatarOnlyCard from './Cards/avatar-only';
|
5
5
|
import DetailedCard from './Cards';
|
6
6
|
import DialogContainer from './Container/dialog';
|
7
7
|
import CardContainer from './Container/card';
|
8
|
+
import Avatar from '../Avatar';
|
9
|
+
import { getUserByDid, isUserDid } from './utils';
|
8
10
|
|
9
11
|
// 创建仅显示名称首字母的头像
|
10
12
|
export function createNameOnlyAvatar(user) {
|
@@ -36,7 +38,33 @@ function UserCard(props) {
|
|
36
38
|
// 默认规则:AvatarOnly模式下默认显示悬停卡片,Detailed模式下默认不显示
|
37
39
|
const shouldShowHoverCard = showHoverCard !== undefined ? showHoverCard : cardType === CardType.AvatarOnly;
|
38
40
|
const containerRef = useRef(null);
|
41
|
+
const [user, setUser] = useState(null);
|
42
|
+
useEffect(() => {
|
43
|
+
let isSubscribed = true;
|
44
|
+
if (props.user) {
|
45
|
+
setUser(props.user);
|
46
|
+
} else if (props.did && isUserDid(props.did) && !props.user) {
|
47
|
+
getUserByDid(props.did).then(_user => {
|
48
|
+
if (isSubscribed) {
|
49
|
+
setUser(_user);
|
50
|
+
}
|
51
|
+
});
|
52
|
+
}
|
53
|
+
return () => {
|
54
|
+
isSubscribed = false;
|
55
|
+
};
|
56
|
+
}, [props.did, props.user]);
|
39
57
|
|
58
|
+
// 如果不存在,则使用 did 渲染头像
|
59
|
+
if (!user) {
|
60
|
+
return /*#__PURE__*/_jsx(Avatar, {
|
61
|
+
did: props.did,
|
62
|
+
size: props.avatarSize,
|
63
|
+
...props.avatarProps
|
64
|
+
});
|
65
|
+
}
|
66
|
+
|
67
|
+
// user 存在,则使用 user 渲染头像
|
40
68
|
// 渲染卡片内容(用于Tooltip)
|
41
69
|
const renderCardContent = () => {
|
42
70
|
const _avatarProps = props.popupAvatarProps || props.avatarProps;
|
@@ -46,8 +74,10 @@ function UserCard(props) {
|
|
46
74
|
children: /*#__PURE__*/_jsx(DetailedCard, {
|
47
75
|
...props,
|
48
76
|
shouldShowHoverCard: false,
|
77
|
+
user: user,
|
49
78
|
avatarProps: _avatarProps,
|
50
|
-
shortenLabelProps: _shortenLabelProps
|
79
|
+
shortenLabelProps: _shortenLabelProps,
|
80
|
+
renderFields: props.popupRenderFields
|
51
81
|
})
|
52
82
|
});
|
53
83
|
};
|
@@ -57,7 +87,8 @@ function UserCard(props) {
|
|
57
87
|
return /*#__PURE__*/_jsx(AvatarOnlyCard, {
|
58
88
|
...props,
|
59
89
|
shouldShowHoverCard: shouldShowHoverCard,
|
60
|
-
renderCardContent: renderCardContent
|
90
|
+
renderCardContent: renderCardContent,
|
91
|
+
user: user
|
61
92
|
});
|
62
93
|
}
|
63
94
|
|
@@ -69,7 +100,8 @@ function UserCard(props) {
|
|
69
100
|
children: /*#__PURE__*/_jsx(DetailedCard, {
|
70
101
|
...props,
|
71
102
|
shouldShowHoverCard: shouldShowHoverCard,
|
72
|
-
renderCardContent: renderCardContent
|
103
|
+
renderCardContent: renderCardContent,
|
104
|
+
user: user
|
73
105
|
})
|
74
106
|
});
|
75
107
|
}
|
package/lib/UserCard/types.d.ts
CHANGED
@@ -57,7 +57,6 @@ export type UserAddress = {
|
|
57
57
|
postalCode?: string;
|
58
58
|
};
|
59
59
|
export type User = UserPublicInfo & {
|
60
|
-
role: string;
|
61
60
|
email?: string;
|
62
61
|
phone?: string;
|
63
62
|
sourceProvider?: string;
|
@@ -69,7 +68,7 @@ export type User = UserPublicInfo & {
|
|
69
68
|
didSpace?: Record<string, any>;
|
70
69
|
connectedAccounts?: any[];
|
71
70
|
locale?: string;
|
72
|
-
url
|
71
|
+
url?: string;
|
73
72
|
inviter?: string;
|
74
73
|
emailVerified?: boolean;
|
75
74
|
phoneVerified?: boolean;
|
@@ -92,7 +91,8 @@ export declare enum InfoType {
|
|
92
91
|
Basic = "Basic"
|
93
92
|
}
|
94
93
|
export interface UserCardProps {
|
95
|
-
user
|
94
|
+
user?: User;
|
95
|
+
did?: string;
|
96
96
|
cardType?: CardType;
|
97
97
|
infoType?: InfoType;
|
98
98
|
avatarSize?: number;
|
@@ -101,13 +101,16 @@ export interface UserCardProps {
|
|
101
101
|
didProps?: Partial<DIDProps>;
|
102
102
|
avatarProps?: Partial<AvatarProps>;
|
103
103
|
popupAvatarProps?: Partial<AvatarProps>;
|
104
|
-
tooltipProps?:
|
104
|
+
tooltipProps?: Partial<TooltipProps>;
|
105
105
|
sx?: SxProps<Theme>;
|
106
106
|
popupSx?: SxProps<Theme>;
|
107
107
|
shortenLabelProps?: Partial<ShortenLabelProps>;
|
108
108
|
popupShortenLabelProps?: Partial<ShortenLabelProps>;
|
109
|
+
renderFields?: string[];
|
110
|
+
popupRenderFields?: string[];
|
109
111
|
renderTopRightContent?: () => React.ReactNode;
|
110
112
|
topRightMaxWidth?: number;
|
111
113
|
renderCustomContent?: () => React.ReactNode;
|
114
|
+
onAvatarClick?: (user: User, e?: React.MouseEvent<HTMLDivElement>) => void;
|
112
115
|
}
|
113
116
|
export {};
|
package/lib/UserCard/utils.d.ts
CHANGED