@arcblock/ux 2.13.7 → 2.13.9
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 +255 -68
- package/lib/UserCard/Content/clock.js +18 -5
- package/lib/UserCard/Content/minimal.d.ts +2 -2
- package/lib/UserCard/Content/minimal.js +6 -2
- 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 +243 -58
- package/src/UserCard/Content/clock.tsx +22 -11
- package/src/UserCard/Content/minimal.tsx +6 -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
- package/lib/UserCard/Content/left-layout.d.ts +0 -16
- package/lib/UserCard/Content/left-layout.js +0 -33
- package/src/UserCard/Content/left-layout.tsx +0 -40
@@ -1,13 +1,13 @@
|
|
1
1
|
import React, { memo } from 'react';
|
2
2
|
import { Typography, Box } from '@mui/material';
|
3
3
|
import DID from '../../DID';
|
4
|
-
import { UserCardProps } from '../types';
|
4
|
+
import { User, UserCardProps } from '../types';
|
5
5
|
import TooltipAvatar from './tooltip-avatar';
|
6
6
|
import { renderTopRight } from '../components';
|
7
7
|
import ShortenLabel from './shorten-label';
|
8
8
|
|
9
9
|
interface MinimalContentProps extends UserCardProps {
|
10
|
-
user:
|
10
|
+
user: User;
|
11
11
|
avatarSize: number;
|
12
12
|
shouldShowHoverCard: boolean;
|
13
13
|
renderCardContent?: () => React.ReactNode | null;
|
@@ -27,10 +27,11 @@ function MinimalContent(props: MinimalContentProps) {
|
|
27
27
|
topRightMaxWidth,
|
28
28
|
avatarProps,
|
29
29
|
shortenLabelProps,
|
30
|
+
...rest
|
30
31
|
} = props;
|
31
32
|
|
32
33
|
return (
|
33
|
-
<Box display="flex" justifyContent="space-between" alignItems="center">
|
34
|
+
<Box display="flex" justifyContent="space-between" alignItems="center" className="user-card__avatar-content">
|
34
35
|
<Box display="flex" justifyContent="flex-start" alignItems="center" gap={2} flex={1} minWidth={0}>
|
35
36
|
<TooltipAvatar
|
36
37
|
user={user}
|
@@ -38,12 +39,14 @@ function MinimalContent(props: MinimalContentProps) {
|
|
38
39
|
shouldShowHoverCard={shouldShowHoverCard}
|
39
40
|
renderCardContent={renderCardContent}
|
40
41
|
avatarProps={avatarProps}
|
42
|
+
{...rest}
|
41
43
|
/>
|
42
44
|
<Box>
|
43
45
|
<Typography
|
44
46
|
variant="subtitle1"
|
45
47
|
fontWeight={500}
|
46
48
|
color="text.primary"
|
49
|
+
className="user-card__full-name-label"
|
47
50
|
fontSize={18}
|
48
51
|
noWrap
|
49
52
|
sx={{ lineHeight: 1.1 }}>
|
@@ -2,11 +2,11 @@ import React from 'react';
|
|
2
2
|
import { Box, Tooltip } from '@mui/material';
|
3
3
|
|
4
4
|
import Zoom from '@mui/material/Zoom';
|
5
|
-
import { UserCardProps } from '../types';
|
5
|
+
import { User, UserCardProps } from '../types';
|
6
6
|
import { renderAvatar } from '../components';
|
7
7
|
|
8
|
-
interface TooltipAvatarProps {
|
9
|
-
user:
|
8
|
+
interface TooltipAvatarProps extends UserCardProps {
|
9
|
+
user: User;
|
10
10
|
avatarSize: number;
|
11
11
|
shouldShowHoverCard: boolean;
|
12
12
|
renderCardContent?: () => React.ReactNode | null;
|
@@ -27,8 +27,13 @@ function TooltipAvatar({
|
|
27
27
|
tooltipTitle,
|
28
28
|
tooltipProps,
|
29
29
|
avatarProps,
|
30
|
+
onAvatarClick,
|
30
31
|
}: TooltipAvatarProps) {
|
31
|
-
const avatarElement =
|
32
|
+
const avatarElement = (
|
33
|
+
<Box display="inline-block">
|
34
|
+
{renderAvatar(user, avatarSize, avatarProps, onAvatarClick, shouldShowHoverCard || !!tooltipTitle)}
|
35
|
+
</Box>
|
36
|
+
);
|
32
37
|
// 使用普通文本Tooltip
|
33
38
|
if (tooltipTitle) {
|
34
39
|
return (
|
@@ -52,7 +57,7 @@ function TooltipAvatar({
|
|
52
57
|
'& .MuiTooltip-tooltip': {
|
53
58
|
backgroundColor: 'transparent',
|
54
59
|
p: 0,
|
55
|
-
maxWidth:
|
60
|
+
maxWidth: 500,
|
56
61
|
zIndex: 1000,
|
57
62
|
},
|
58
63
|
},
|
@@ -1,27 +1,32 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { Box } from '@mui/material';
|
3
3
|
import Avatar from '../Avatar';
|
4
|
-
import { UserCardProps } from './types';
|
4
|
+
import { User, UserCardProps } from './types';
|
5
5
|
import { createNameOnlyAvatar } from './utils';
|
6
6
|
|
7
7
|
// 渲染头像
|
8
8
|
export const renderAvatar = (
|
9
|
-
user:
|
9
|
+
user: User,
|
10
10
|
avatarSize: number = 48,
|
11
|
-
avatarProps: UserCardProps['avatarProps'] = undefined
|
11
|
+
avatarProps: UserCardProps['avatarProps'] = undefined,
|
12
|
+
onAvatarClick: UserCardProps['onAvatarClick'] = undefined,
|
13
|
+
shouldShowHoverCard: boolean = false
|
12
14
|
) => {
|
15
|
+
const onClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
16
|
+
onAvatarClick?.(user, e);
|
17
|
+
};
|
13
18
|
// 如果用户没有头像,则显示名称首字母头像
|
14
19
|
if (!user.avatar) {
|
15
20
|
const avatarContent = createNameOnlyAvatar(user);
|
16
|
-
|
17
21
|
return (
|
18
22
|
<Avatar
|
19
23
|
size={avatarSize}
|
20
24
|
did={user.did}
|
21
25
|
variant="circle"
|
26
|
+
onClick={onClick}
|
22
27
|
sx={{
|
23
28
|
fontSize: avatarSize * 0.4,
|
24
|
-
cursor: 'pointer',
|
29
|
+
cursor: shouldShowHoverCard || onAvatarClick ? 'pointer' : 'default',
|
25
30
|
}}
|
26
31
|
{...(avatarProps || {})}>
|
27
32
|
{avatarContent}
|
@@ -36,8 +41,9 @@ export const renderAvatar = (
|
|
36
41
|
did={user.did}
|
37
42
|
variant="circle"
|
38
43
|
style={{
|
39
|
-
cursor: 'pointer',
|
44
|
+
cursor: shouldShowHoverCard || onAvatarClick ? 'pointer' : 'default',
|
40
45
|
}}
|
46
|
+
onClick={onClick}
|
41
47
|
src={user.avatar}
|
42
48
|
alt={user.fullName || ''}
|
43
49
|
{...(avatarProps || {})}
|
@@ -51,7 +57,11 @@ export const renderTopRight = (
|
|
51
57
|
topRightMaxWidth: number = 120
|
52
58
|
) => {
|
53
59
|
if (renderTopRightContent) {
|
54
|
-
return
|
60
|
+
return (
|
61
|
+
<Box sx={{ maxWidth: topRightMaxWidth }} className="user-card__top-right-content">
|
62
|
+
{renderTopRightContent()}
|
63
|
+
</Box>
|
64
|
+
);
|
55
65
|
}
|
56
66
|
|
57
67
|
return null;
|
package/src/UserCard/index.tsx
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
import { useRef } from 'react';
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
2
|
+
import { toTypeInfo } from '@arcblock/did';
|
2
3
|
import type { User } from './types';
|
3
4
|
import { UserCardProps, CardType } from './types';
|
4
5
|
import AvatarOnlyCard from './Cards/avatar-only';
|
5
6
|
import DetailedCard from './Cards';
|
6
7
|
import DialogContainer from './Container/dialog';
|
7
8
|
import CardContainer from './Container/card';
|
9
|
+
import Avatar from '../Avatar';
|
10
|
+
import { getUserByDid, isUserDid } from './utils';
|
8
11
|
|
9
12
|
// 创建仅显示名称首字母的头像
|
10
13
|
export function createNameOnlyAvatar(user: User) {
|
@@ -35,7 +38,30 @@ function UserCard(props: UserCardProps) {
|
|
35
38
|
const shouldShowHoverCard = showHoverCard !== undefined ? showHoverCard : cardType === CardType.AvatarOnly;
|
36
39
|
|
37
40
|
const containerRef = useRef<HTMLDivElement>(null);
|
41
|
+
const [user, setUser] = useState<User | null>(null);
|
38
42
|
|
43
|
+
useEffect(() => {
|
44
|
+
let isSubscribed = true;
|
45
|
+
if (props.user) {
|
46
|
+
setUser(props.user);
|
47
|
+
} else if (props.did && isUserDid(props.did) && !props.user) {
|
48
|
+
getUserByDid(props.did).then((_user) => {
|
49
|
+
if (isSubscribed) {
|
50
|
+
setUser(_user);
|
51
|
+
}
|
52
|
+
});
|
53
|
+
}
|
54
|
+
return () => {
|
55
|
+
isSubscribed = false;
|
56
|
+
};
|
57
|
+
}, [props.did, props.user]);
|
58
|
+
|
59
|
+
// 如果不存在,则使用 did 渲染头像
|
60
|
+
if (!user) {
|
61
|
+
return <Avatar did={props.did} size={props.avatarSize} {...props.avatarProps} />;
|
62
|
+
}
|
63
|
+
|
64
|
+
// user 存在,则使用 user 渲染头像
|
39
65
|
// 渲染卡片内容(用于Tooltip)
|
40
66
|
const renderCardContent = () => {
|
41
67
|
const _avatarProps = props.popupAvatarProps || props.avatarProps;
|
@@ -45,8 +71,10 @@ function UserCard(props: UserCardProps) {
|
|
45
71
|
<DetailedCard
|
46
72
|
{...props}
|
47
73
|
shouldShowHoverCard={false}
|
74
|
+
user={user!}
|
48
75
|
avatarProps={_avatarProps}
|
49
76
|
shortenLabelProps={_shortenLabelProps}
|
77
|
+
renderFields={props.popupRenderFields}
|
50
78
|
/>
|
51
79
|
</DialogContainer>
|
52
80
|
);
|
@@ -55,14 +83,24 @@ function UserCard(props: UserCardProps) {
|
|
55
83
|
// 根据卡片类型选择合适的组件
|
56
84
|
if (cardType === CardType.AvatarOnly) {
|
57
85
|
return (
|
58
|
-
<AvatarOnlyCard
|
86
|
+
<AvatarOnlyCard
|
87
|
+
{...props}
|
88
|
+
shouldShowHoverCard={shouldShowHoverCard}
|
89
|
+
renderCardContent={renderCardContent}
|
90
|
+
user={user!}
|
91
|
+
/>
|
59
92
|
);
|
60
93
|
}
|
61
94
|
|
62
95
|
// 详细卡片模式
|
63
96
|
return (
|
64
97
|
<CardContainer containerRef={containerRef} cardType={cardType} sx={props.sx}>
|
65
|
-
<DetailedCard
|
98
|
+
<DetailedCard
|
99
|
+
{...props}
|
100
|
+
shouldShowHoverCard={shouldShowHoverCard}
|
101
|
+
renderCardContent={renderCardContent}
|
102
|
+
user={user!}
|
103
|
+
/>
|
66
104
|
</CardContainer>
|
67
105
|
);
|
68
106
|
}
|
package/src/UserCard/types.ts
CHANGED
@@ -64,7 +64,6 @@ export type UserAddress = {
|
|
64
64
|
};
|
65
65
|
|
66
66
|
export type User = UserPublicInfo & {
|
67
|
-
role: string;
|
68
67
|
email?: string;
|
69
68
|
phone?: string;
|
70
69
|
sourceProvider?: string;
|
@@ -76,7 +75,7 @@ export type User = UserPublicInfo & {
|
|
76
75
|
didSpace?: Record<string, any>;
|
77
76
|
connectedAccounts?: any[];
|
78
77
|
locale?: string;
|
79
|
-
url
|
78
|
+
url?: string;
|
80
79
|
inviter?: string;
|
81
80
|
emailVerified?: boolean;
|
82
81
|
phoneVerified?: boolean;
|
@@ -109,7 +108,8 @@ export enum InfoType {
|
|
109
108
|
|
110
109
|
// 定义UserCard属性接口
|
111
110
|
export interface UserCardProps {
|
112
|
-
user
|
111
|
+
user?: User;
|
112
|
+
did?: string;
|
113
113
|
cardType?: CardType;
|
114
114
|
infoType?: InfoType;
|
115
115
|
avatarSize?: number;
|
@@ -121,7 +121,7 @@ export interface UserCardProps {
|
|
121
121
|
popupAvatarProps?: Partial<AvatarProps>;
|
122
122
|
|
123
123
|
// 弹出层相关属性
|
124
|
-
tooltipProps?:
|
124
|
+
tooltipProps?: Partial<TooltipProps>;
|
125
125
|
|
126
126
|
// 样式相关属性
|
127
127
|
sx?: SxProps<Theme>;
|
@@ -131,10 +131,17 @@ export interface UserCardProps {
|
|
131
131
|
shortenLabelProps?: Partial<ShortenLabelProps>;
|
132
132
|
popupShortenLabelProps?: Partial<ShortenLabelProps>;
|
133
133
|
|
134
|
+
// 自定义渲染字段
|
135
|
+
renderFields?: string[];
|
136
|
+
popupRenderFields?: string[];
|
137
|
+
|
134
138
|
// 右上角内容相关属性
|
135
139
|
renderTopRightContent?: () => React.ReactNode;
|
136
140
|
topRightMaxWidth?: number;
|
137
141
|
|
138
142
|
// 自定义内容渲染函数
|
139
143
|
renderCustomContent?: () => React.ReactNode;
|
144
|
+
|
145
|
+
// 头像点击事件
|
146
|
+
onAvatarClick?: (user: User, e?: React.MouseEvent<HTMLDivElement>) => void;
|
140
147
|
}
|
package/src/UserCard/utils.ts
CHANGED
@@ -1,5 +1,16 @@
|
|
1
|
+
import { toTypeInfo } from '@arcblock/did';
|
2
|
+
import { types } from '@ocap/mcrypto';
|
3
|
+
import { BlockletSDK } from '@blocklet/js-sdk';
|
1
4
|
import { User } from './types';
|
2
5
|
|
6
|
+
let client: BlockletSDK | null = null;
|
7
|
+
try {
|
8
|
+
client = new BlockletSDK();
|
9
|
+
} catch (error) {
|
10
|
+
console.error('Failed to initialize BlockletSDK:', error);
|
11
|
+
client = null;
|
12
|
+
}
|
13
|
+
|
3
14
|
// 创建仅显示名称首字母的头像
|
4
15
|
// eslint-disable-next-line import/prefer-default-export
|
5
16
|
export function createNameOnlyAvatar(user: User) {
|
@@ -20,3 +31,25 @@ export function createNameOnlyAvatar(user: User) {
|
|
20
31
|
|
21
32
|
return content;
|
22
33
|
}
|
34
|
+
|
35
|
+
export function isUserDid(did: string) {
|
36
|
+
if (!did || typeof did !== 'string') return false;
|
37
|
+
try {
|
38
|
+
const didInfo = toTypeInfo(did);
|
39
|
+
return didInfo.role !== undefined && didInfo.role !== types.RoleType.ROLE_APPLICATION;
|
40
|
+
} catch (error) {
|
41
|
+
console.error('Failed to check if did is user did:', error);
|
42
|
+
return false;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
export async function getUserByDid(did: string): Promise<User | null> {
|
47
|
+
if (!client) return null;
|
48
|
+
try {
|
49
|
+
const user = await client.user.getUserPublicInfo({ did });
|
50
|
+
return user as User;
|
51
|
+
} catch (error) {
|
52
|
+
console.error('Failed to get user by did:', error);
|
53
|
+
return null;
|
54
|
+
}
|
55
|
+
}
|
@@ -1,16 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { User } from '../types';
|
3
|
-
interface LeftColumnLayoutProps {
|
4
|
-
user: User;
|
5
|
-
avatarSize: number;
|
6
|
-
shouldShowHoverCard: boolean;
|
7
|
-
renderCardContent: () => React.ReactNode;
|
8
|
-
followButtonStyle: string;
|
9
|
-
isFollowed: boolean;
|
10
|
-
followLoading: boolean;
|
11
|
-
}
|
12
|
-
/**
|
13
|
-
* 统一左侧列布局组件,包含头像和关注按钮
|
14
|
-
*/
|
15
|
-
declare function LeftColumnLayout({ user, avatarSize, shouldShowHoverCard, renderCardContent, followButtonStyle, isFollowed, followLoading, }: LeftColumnLayoutProps): import("react/jsx-runtime").JSX.Element;
|
16
|
-
export default LeftColumnLayout;
|
@@ -1,33 +0,0 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import React from 'react';
|
3
|
-
import { Box } from '@mui/material';
|
4
|
-
import TooltipAvatar from './tooltip-avatar';
|
5
|
-
/**
|
6
|
-
* 统一左侧列布局组件,包含头像和关注按钮
|
7
|
-
*/
|
8
|
-
function LeftColumnLayout({
|
9
|
-
user,
|
10
|
-
avatarSize,
|
11
|
-
shouldShowHoverCard,
|
12
|
-
renderCardContent,
|
13
|
-
followButtonStyle,
|
14
|
-
isFollowed,
|
15
|
-
followLoading
|
16
|
-
}) {
|
17
|
-
return /*#__PURE__*/_jsx(Box, {
|
18
|
-
sx: {
|
19
|
-
mr: 2,
|
20
|
-
display: 'flex',
|
21
|
-
flexDirection: 'column',
|
22
|
-
alignItems: 'center',
|
23
|
-
gap: 1
|
24
|
-
},
|
25
|
-
children: /*#__PURE__*/_jsx(TooltipAvatar, {
|
26
|
-
user: user,
|
27
|
-
avatarSize: avatarSize,
|
28
|
-
shouldShowHoverCard: shouldShowHoverCard,
|
29
|
-
renderCardContent: renderCardContent
|
30
|
-
})
|
31
|
-
});
|
32
|
-
}
|
33
|
-
export default LeftColumnLayout;
|
@@ -1,40 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import { Box } from '@mui/material';
|
3
|
-
import { User } from '../types';
|
4
|
-
import TooltipAvatar from './tooltip-avatar';
|
5
|
-
|
6
|
-
interface LeftColumnLayoutProps {
|
7
|
-
user: User;
|
8
|
-
avatarSize: number;
|
9
|
-
shouldShowHoverCard: boolean;
|
10
|
-
renderCardContent: () => React.ReactNode;
|
11
|
-
followButtonStyle: string;
|
12
|
-
isFollowed: boolean;
|
13
|
-
followLoading: boolean;
|
14
|
-
}
|
15
|
-
|
16
|
-
/**
|
17
|
-
* 统一左侧列布局组件,包含头像和关注按钮
|
18
|
-
*/
|
19
|
-
function LeftColumnLayout({
|
20
|
-
user,
|
21
|
-
avatarSize,
|
22
|
-
shouldShowHoverCard,
|
23
|
-
renderCardContent,
|
24
|
-
followButtonStyle,
|
25
|
-
isFollowed,
|
26
|
-
followLoading,
|
27
|
-
}: LeftColumnLayoutProps) {
|
28
|
-
return (
|
29
|
-
<Box sx={{ mr: 2, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}>
|
30
|
-
<TooltipAvatar
|
31
|
-
user={user}
|
32
|
-
avatarSize={avatarSize}
|
33
|
-
shouldShowHoverCard={shouldShowHoverCard}
|
34
|
-
renderCardContent={renderCardContent}
|
35
|
-
/>
|
36
|
-
</Box>
|
37
|
-
);
|
38
|
-
}
|
39
|
-
|
40
|
-
export default LeftColumnLayout;
|