@arcblock/ux 2.13.6 → 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.
Files changed (45) hide show
  1. package/lib/Colors/index.d.ts +3 -1
  2. package/lib/Colors/index.js +4 -2
  3. package/lib/Config/config-provider.d.ts +7 -7
  4. package/lib/Config/config-provider.js +1 -1
  5. package/lib/Theme/theme.d.ts +7 -41
  6. package/lib/Theme/theme.js +50 -132
  7. package/lib/UserCard/Cards/avatar-only.d.ts +3 -2
  8. package/lib/UserCard/Cards/basic-info.d.ts +3 -2
  9. package/lib/UserCard/Cards/basic-info.js +12 -6
  10. package/lib/UserCard/Cards/index.d.ts +3 -2
  11. package/lib/UserCard/Cards/name-only.d.ts +4 -2
  12. package/lib/UserCard/Cards/name-only.js +3 -2
  13. package/lib/UserCard/Container/dialog.js +1 -1
  14. package/lib/UserCard/Content/basic.d.ts +2 -1
  15. package/lib/UserCard/Content/basic.js +195 -67
  16. package/lib/UserCard/Content/minimal.d.ts +2 -2
  17. package/lib/UserCard/Content/minimal.js +2 -0
  18. package/lib/UserCard/Content/tooltip-avatar.d.ts +4 -4
  19. package/lib/UserCard/Content/tooltip-avatar.js +4 -3
  20. package/lib/UserCard/components.d.ts +2 -2
  21. package/lib/UserCard/components.js +9 -3
  22. package/lib/UserCard/index.js +36 -4
  23. package/lib/UserCard/types.d.ts +7 -4
  24. package/lib/UserCard/utils.d.ts +2 -0
  25. package/lib/UserCard/utils.js +33 -0
  26. package/lib/type.d.ts +2 -3
  27. package/lib/withTheme/index.d.ts +2 -3
  28. package/package.json +6 -5
  29. package/src/Colors/index.ts +7 -2
  30. package/src/Config/config-provider.tsx +9 -9
  31. package/src/Theme/theme.ts +55 -166
  32. package/src/UserCard/Cards/avatar-only.tsx +3 -2
  33. package/src/UserCard/Cards/basic-info.tsx +17 -5
  34. package/src/UserCard/Cards/index.tsx +3 -2
  35. package/src/UserCard/Cards/name-only.tsx +4 -4
  36. package/src/UserCard/Container/dialog.tsx +1 -1
  37. package/src/UserCard/Content/basic.tsx +191 -57
  38. package/src/UserCard/Content/minimal.tsx +4 -3
  39. package/src/UserCard/Content/tooltip-avatar.tsx +10 -5
  40. package/src/UserCard/components.tsx +17 -7
  41. package/src/UserCard/index.tsx +41 -3
  42. package/src/UserCard/types.ts +11 -4
  43. package/src/UserCard/utils.ts +33 -0
  44. package/src/type.d.ts +2 -3
  45. package/src/withTheme/index.tsx +2 -3
@@ -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 firstLink = metadata.links && metadata.links.length > 0 ? metadata.links[0] : null;
40
- const moreContent = () => {
41
- return metadata.timezone ? /*#__PURE__*/_jsxs(Box, {
42
- display: "flex",
43
- alignItems: "center",
44
- gap: 1,
45
- children: [/*#__PURE__*/_jsx(TimezoneIcon, {
46
- ...iconSize
47
- }), /*#__PURE__*/_jsx(LineText, {
48
- variant: "body2",
49
- color: "grey.800",
50
- children: /*#__PURE__*/_jsx(Clock, {
51
- value: metadata.timezone,
52
- variant: "body2",
53
- color: "grey.800"
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
- }) : null;
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
- children: [user.metadata?.bio && /*#__PURE__*/_jsx(LineText, {
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__*/_jsxs(Box, {
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: [firstLink && /*#__PURE__*/_jsxs(Box, {
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: UserCardProps['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: UserCardProps['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: 400,
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: UserCardProps["user"], avatarSize?: number, avatarProps?: UserCardProps["avatarProps"]) => import("react/jsx-runtime").JSX.Element;
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
  }
@@ -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
  }
@@ -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: string;
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: 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?: Omit<TooltipProps, 'title'>;
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 {};
@@ -1,2 +1,4 @@
1
1
  import { User } from './types';
2
2
  export declare function createNameOnlyAvatar(user: User): string | null;
3
+ export declare function isUserDid(did: string): boolean;
4
+ export declare function getUserByDid(did: string): Promise<User | null>;
@@ -1,3 +1,14 @@
1
+ import { toTypeInfo } from '@arcblock/did';
2
+ import { types } from '@ocap/mcrypto';
3
+ import { BlockletSDK } from '@blocklet/js-sdk';
4
+ let client = null;
5
+ try {
6
+ client = new BlockletSDK();
7
+ } catch (error) {
8
+ console.error('Failed to initialize BlockletSDK:', error);
9
+ client = null;
10
+ }
11
+
1
12
  // 创建仅显示名称首字母的头像
2
13
  // eslint-disable-next-line import/prefer-default-export
3
14
  export function createNameOnlyAvatar(user) {
@@ -16,4 +27,26 @@ export function createNameOnlyAvatar(user) {
16
27
  content = user.did ? user.did.charAt(0).toUpperCase() : '?';
17
28
  }
18
29
  return content;
30
+ }
31
+ export function isUserDid(did) {
32
+ if (!did || typeof did !== 'string') return false;
33
+ try {
34
+ const didInfo = toTypeInfo(did);
35
+ return didInfo.role !== undefined && didInfo.role !== types.RoleType.ROLE_APPLICATION;
36
+ } catch (error) {
37
+ console.error('Failed to check if did is user did:', error);
38
+ return false;
39
+ }
40
+ }
41
+ export async function getUserByDid(did) {
42
+ if (!client) return null;
43
+ try {
44
+ const user = await client.user.getUserPublicInfo({
45
+ did
46
+ });
47
+ return user;
48
+ } catch (error) {
49
+ console.error('Failed to get user by did:', error);
50
+ return null;
51
+ }
19
52
  }
package/lib/type.d.ts CHANGED
@@ -1,10 +1,9 @@
1
- import type { Theme } from '@mui/material';
1
+ import type { Theme, PaletteMode } from '@mui/material';
2
2
  import type { LiteralUnion } from 'type-fest';
3
3
 
4
4
  export type $TSFixMe = any;
5
5
  export type Translations = Record<string, Record<string, any>>;
6
6
  export type Locale = LiteralUnion<'en' | 'zh', string>;
7
- export type ThemeMode = 'light' | 'dark';
8
7
 
9
8
  // TODO: 以下为 blocklet 应用专属的全局对象类型,可以更加具体
10
9
  export type User = Record<string, any>;
@@ -26,7 +25,7 @@ export type Blocklet = {
26
25
  version: string;
27
26
  mode: string;
28
27
  tenantMode: 'single' | 'multiple';
29
- theme: Record<ThemeMode, Theme>;
28
+ theme: Record<PaletteMode, Theme>;
30
29
  navigation: $TSFixMe[];
31
30
  preferences: Record<string, any>;
32
31
  languages: {
@@ -1,9 +1,8 @@
1
- import { Breakpoint } from '@mui/material';
1
+ import { Breakpoint, type PaletteMode } from '@mui/material';
2
2
  import { type PaletteOptions } from '@mui/material/styles/createPalette';
3
3
  import { type TypographyOptions } from '@mui/material/styles/createTypography';
4
- import { ThemeMode } from '../type';
5
4
  declare function withTheme<P extends object>(Component: React.ComponentType<P>, { mode, pageWidth, palette, typography, }?: {
6
- mode?: ThemeMode;
5
+ mode?: PaletteMode;
7
6
  pageWidth?: Breakpoint;
8
7
  palette?: PaletteOptions;
9
8
  typography?: TypographyOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.13.6",
3
+ "version": "2.13.8",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -70,13 +70,14 @@
70
70
  "react": ">=18.2.0",
71
71
  "react-router-dom": ">=6.22.3"
72
72
  },
73
- "gitHead": "1cc41a6a655f93eb1536a9dd36fe3979a2c654c8",
73
+ "gitHead": "86ba86fce59551ceb09ee3cbdfd4646de2a69900",
74
74
  "dependencies": {
75
75
  "@arcblock/did-motif": "^1.1.13",
76
- "@arcblock/icons": "^2.13.6",
77
- "@arcblock/nft-display": "^2.13.6",
78
- "@arcblock/react-hooks": "^2.13.6",
76
+ "@arcblock/icons": "^2.13.8",
77
+ "@arcblock/nft-display": "^2.13.8",
78
+ "@arcblock/react-hooks": "^2.13.8",
79
79
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
80
+ "@blocklet/theme": "^2.13.8",
80
81
  "@fontsource/roboto": "~5.1.1",
81
82
  "@fontsource/ubuntu-mono": "^5.0.18",
82
83
  "@iconify-icons/logos": "^1.2.36",
@@ -1,4 +1,9 @@
1
- // eslint-disable-next-line no-restricted-exports
2
- export { default } from './themes/default';
1
+ import { BLOCKLET_THEME_LIGHT } from '@blocklet/theme';
2
+ import type { Theme } from '@mui/material';
3
+
4
+ // @compatibility
5
+ const colors = BLOCKLET_THEME_LIGHT.palette as Theme['palette'];
6
+
7
+ export default colors;
3
8
  export { default as temp } from './themes/temp';
4
9
  export { default as didConnectColors } from './themes/did-connect';