@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.
- package/lib/Colors/index.d.ts +3 -1
- package/lib/Colors/index.js +4 -2
- package/lib/Config/config-provider.d.ts +7 -7
- package/lib/Config/config-provider.js +1 -1
- package/lib/Theme/theme.d.ts +7 -41
- package/lib/Theme/theme.js +50 -132
- 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/lib/type.d.ts +2 -3
- package/lib/withTheme/index.d.ts +2 -3
- package/package.json +6 -5
- package/src/Colors/index.ts +7 -2
- package/src/Config/config-provider.tsx +9 -9
- package/src/Theme/theme.ts +55 -166
- 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
- package/src/type.d.ts +2 -3
- package/src/withTheme/index.tsx +2 -3
@@ -1,4 +1,5 @@
|
|
1
1
|
import { createContext, useContext, ReactNode, useMemo, useState, useCallback, useEffect } from 'react';
|
2
|
+
import { type PaletteMode } from '@mui/material';
|
2
3
|
import type { ThemeOptions } from '@mui/material/styles';
|
3
4
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
4
5
|
import set from 'lodash/set';
|
@@ -6,10 +7,9 @@ import { ThemeProvider as EmotionThemeProvider } from '@emotion/react';
|
|
6
7
|
import { LocaleProvider, LocaleProviderProps, useLocaleContext } from '../Locale/context';
|
7
8
|
import ThemeProvider, { ThemeProviderProps } from '../Theme/theme-provider';
|
8
9
|
import { createTheme, useTheme } from '../Theme';
|
9
|
-
import { ThemeMode } from '../type';
|
10
10
|
|
11
11
|
export interface ConfigContextType {
|
12
|
-
mode:
|
12
|
+
mode: PaletteMode;
|
13
13
|
themeOptions: ThemeOptions;
|
14
14
|
toggleMode: () => void;
|
15
15
|
}
|
@@ -18,8 +18,8 @@ const ConfigContext = createContext<ConfigContextType>({} as ConfigContextType);
|
|
18
18
|
const preferThemeModeKey = 'blocklet_theme_prefer';
|
19
19
|
|
20
20
|
export function isThemeRecord(
|
21
|
-
theme: ThemeOptions | Record<
|
22
|
-
): theme is Record<
|
21
|
+
theme: ThemeOptions | Record<PaletteMode, ThemeOptions>
|
22
|
+
): theme is Record<PaletteMode, ThemeOptions> {
|
23
23
|
return 'light' in theme || 'dark' in theme;
|
24
24
|
}
|
25
25
|
|
@@ -27,8 +27,8 @@ export interface ConfigProviderProps
|
|
27
27
|
extends Omit<LocaleProviderProps, 'translations'>,
|
28
28
|
Omit<ThemeProviderProps, 'theme'> {
|
29
29
|
children: ReactNode;
|
30
|
-
prefer?:
|
31
|
-
theme?: ThemeOptions | Record<
|
30
|
+
prefer?: PaletteMode;
|
31
|
+
theme?: ThemeOptions | Record<PaletteMode, ThemeOptions>;
|
32
32
|
disableBlockletTheme?: boolean;
|
33
33
|
translations?: Record<string, any>;
|
34
34
|
}
|
@@ -51,18 +51,18 @@ export function ConfigProvider({
|
|
51
51
|
onLoadingTranslation,
|
52
52
|
}: ConfigProviderProps) {
|
53
53
|
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
54
|
-
const [mode, setMode] = useState<
|
54
|
+
const [mode, setMode] = useState<PaletteMode>(() => {
|
55
55
|
if (prefer) {
|
56
56
|
return prefer;
|
57
57
|
}
|
58
58
|
|
59
59
|
// 未启用暗色主题
|
60
|
-
if (
|
60
|
+
if (['1', 'true'].includes(window.blocklet?.USE_DARK_THEME) === false) {
|
61
61
|
return 'light';
|
62
62
|
}
|
63
63
|
|
64
64
|
// 本地缓存
|
65
|
-
const localPrefer = localStorage.getItem(preferThemeModeKey) as
|
65
|
+
const localPrefer = localStorage.getItem(preferThemeModeKey) as PaletteMode;
|
66
66
|
if (localPrefer && (localPrefer === 'light' || localPrefer === 'dark')) {
|
67
67
|
return localPrefer;
|
68
68
|
}
|
package/src/Theme/theme.ts
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
/* eslint-disable no-shadow */
|
2
2
|
// https://app.zeplin.io/styleguide/5d1436f1e97c2156f49c0725/colors
|
3
|
-
import {
|
3
|
+
import type { PaletteMode } from '@mui/material';
|
4
|
+
import { createTheme as _createTheme, responsiveFontSizes, type ThemeOptions } from '@mui/material/styles';
|
4
5
|
import { deepmerge } from '@mui/utils';
|
5
|
-
import type { Typography } from '@mui/material/styles/createTypography';
|
6
6
|
import webfontloader from 'webfontloader';
|
7
|
+
import { BLOCKLET_THEME_LIGHT, BLOCKLET_THEME_DARK, DEFAULT_FONTS } from '@blocklet/theme';
|
7
8
|
|
8
|
-
import colors from '../Colors';
|
9
|
-
import { ThemeMode } from '../type';
|
10
9
|
import { cleanedObj } from '../Util';
|
11
10
|
|
12
11
|
// 默认只加载最基本的 roboto latin 字体
|
@@ -17,44 +16,6 @@ import '@fontsource/roboto/latin-ext-400.css';
|
|
17
16
|
import '@fontsource/roboto/latin-ext-500.css';
|
18
17
|
import '@fontsource/roboto/latin-ext-700.css';
|
19
18
|
|
20
|
-
// 扩展 Theme
|
21
|
-
declare module '@mui/material/styles' {
|
22
|
-
interface Theme {
|
23
|
-
mode?: ThemeMode;
|
24
|
-
themeName?: string;
|
25
|
-
pageWidth?: string;
|
26
|
-
colors?: Record<string, string>;
|
27
|
-
typography: Typography & {
|
28
|
-
useNextVariants: boolean;
|
29
|
-
color: Record<string, string>;
|
30
|
-
button: {
|
31
|
-
fontWeight?: number;
|
32
|
-
};
|
33
|
-
};
|
34
|
-
}
|
35
|
-
interface ThemeOptions {
|
36
|
-
themeName?: string;
|
37
|
-
mode?: ThemeMode;
|
38
|
-
pageWidth?: string;
|
39
|
-
colors?: Record<string, string>;
|
40
|
-
/** @deprecated 请使用 components */
|
41
|
-
overrides?: Components<Omit<Theme, 'components'>>;
|
42
|
-
}
|
43
|
-
interface TypeText {
|
44
|
-
hint: string;
|
45
|
-
}
|
46
|
-
}
|
47
|
-
// 扩展 TypographyOptions
|
48
|
-
declare module '@mui/material/styles/createTypography' {
|
49
|
-
interface TypographyOptions {
|
50
|
-
useNextVariants?: boolean;
|
51
|
-
color?: Record<string, string>;
|
52
|
-
}
|
53
|
-
}
|
54
|
-
|
55
|
-
// 默认深色主题
|
56
|
-
const defaultDarkTheme = _createTheme({ palette: { mode: 'dark' } });
|
57
|
-
|
58
19
|
// 收集字体配置
|
59
20
|
export function collectFontFamilies(obj?: { fontFamily?: string }, fontSet: Set<string> = new Set()): Set<string> {
|
60
21
|
if (!obj || typeof obj !== 'object') return fontSet;
|
@@ -78,8 +39,7 @@ export function collectFontFamilies(obj?: { fontFamily?: string }, fontSet: Set<
|
|
78
39
|
}
|
79
40
|
|
80
41
|
// 动态加载字体
|
81
|
-
const
|
82
|
-
const prevFonts = new Set<string>(defaultFonts.concat('inherit')); // inherit 属于 MUI 特殊值,无需动态加载
|
42
|
+
const prevFonts = new Set<string>(DEFAULT_FONTS.concat('inherit')); // inherit 属于 MUI 特殊值,无需动态加载
|
83
43
|
export function loadFonts(fonts: string[]) {
|
84
44
|
// 过滤出未加载的字体
|
85
45
|
const unloadedFonts = fonts.filter((font) => !prevFonts.has(font));
|
@@ -112,105 +72,22 @@ export function loadFonts(fonts: string[]) {
|
|
112
72
|
}
|
113
73
|
|
114
74
|
// 创建默认主题配置
|
115
|
-
export function createDefaultThemeOptions(mode:
|
116
|
-
const result: ThemeOptions = {
|
117
|
-
palette: {
|
118
|
-
mode,
|
119
|
-
...colors,
|
120
|
-
background: {
|
121
|
-
paper: colors.common.white,
|
122
|
-
default: colors.background.default,
|
123
|
-
},
|
124
|
-
},
|
125
|
-
typography: {
|
126
|
-
fontFamily: defaultFonts.join(','),
|
127
|
-
useNextVariants: true,
|
128
|
-
color: {
|
129
|
-
// 此处 #222222 必须硬编码, layout/sidebar.js -> Icon/image 加载图片时 color 会影响加载路径
|
130
|
-
// TODO: 此处硬编码的色值后面需要改为 colors.grey[900],
|
131
|
-
// 或者如果可以的话直接删掉 typography#color, 文本颜色建议使用 theme.palette.text 中的色值?
|
132
|
-
// layout 组件建议重构, sidebar 中建议使用 icon 替换 img (#366)
|
133
|
-
main: mode === 'light' ? '#222222' : colors.common.white,
|
134
|
-
gray: mode === 'light' ? colors.grey[500] : colors.grey[300],
|
135
|
-
},
|
136
|
-
// button 默认使用粗体
|
137
|
-
button: {
|
138
|
-
fontWeight: 700,
|
139
|
-
},
|
140
|
-
},
|
141
|
-
components: {
|
142
|
-
MuiButton: {
|
143
|
-
styleOverrides: {
|
144
|
-
root: {
|
145
|
-
boxShadow: 'none',
|
146
|
-
},
|
147
|
-
},
|
148
|
-
},
|
149
|
-
MuiButtonGroup: {
|
150
|
-
styleOverrides: {
|
151
|
-
root: {
|
152
|
-
boxShadow: 'none',
|
153
|
-
},
|
154
|
-
},
|
155
|
-
},
|
156
|
-
MuiTableCell: {
|
157
|
-
styleOverrides: {
|
158
|
-
root: ({ ownerState }) => ({
|
159
|
-
...(ownerState.size === 'small'
|
160
|
-
? {
|
161
|
-
borderBottomWidth: '0',
|
162
|
-
paddingTop: '8px',
|
163
|
-
paddingBottom: '8px',
|
164
|
-
paddingLeft: 0,
|
165
|
-
paddingRight: '20px',
|
166
|
-
}
|
167
|
-
: {
|
168
|
-
borderBottomWidth: '0',
|
169
|
-
paddingTop: '14px',
|
170
|
-
paddingBottom: '14px',
|
171
|
-
paddingLeft: 0,
|
172
|
-
paddingRight: '30px',
|
173
|
-
}),
|
174
|
-
}),
|
175
|
-
head: {
|
176
|
-
textTransform: 'uppercase',
|
177
|
-
color: mode === 'light' ? colors.grey[900] : colors.grey[300],
|
178
|
-
},
|
179
|
-
body: {
|
180
|
-
color: mode === 'light' ? colors.grey[900] : colors.grey[300],
|
181
|
-
},
|
182
|
-
},
|
183
|
-
},
|
184
|
-
},
|
185
|
-
};
|
186
|
-
|
187
|
-
// 深色主题
|
75
|
+
export function createDefaultThemeOptions(mode: PaletteMode = 'light') {
|
188
76
|
if (mode === 'dark') {
|
189
|
-
|
190
|
-
...defaultDarkTheme.palette,
|
191
|
-
background: {
|
192
|
-
paper: colors.grey[900],
|
193
|
-
default: colors.grey[900],
|
194
|
-
},
|
195
|
-
};
|
77
|
+
return BLOCKLET_THEME_DARK;
|
196
78
|
}
|
197
79
|
|
198
|
-
return
|
80
|
+
return BLOCKLET_THEME_LIGHT;
|
199
81
|
}
|
200
82
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
components,
|
210
|
-
...rest
|
211
|
-
}: ThemeOptions & { disableBlockletTheme?: boolean } = {}) => {
|
212
|
-
const userThemeOptions: ThemeOptions = {
|
213
|
-
themeName: 'ArcBlock',
|
83
|
+
export interface UserThemeOptions extends ThemeOptions {
|
84
|
+
disableBlockletTheme?: boolean;
|
85
|
+
}
|
86
|
+
|
87
|
+
// 主要处理 mode 和 overrides
|
88
|
+
const normalizeUserThemeOptions = ({ mode = 'light', palette, components, overrides, ...rest }: UserThemeOptions) => {
|
89
|
+
return {
|
90
|
+
mode,
|
214
91
|
palette: {
|
215
92
|
...palette,
|
216
93
|
mode,
|
@@ -219,43 +96,55 @@ export const create = ({
|
|
219
96
|
...overrides,
|
220
97
|
...components,
|
221
98
|
},
|
222
|
-
// @TODO 考虑使用 theme.shape.pageWidth
|
223
|
-
pageWidth,
|
224
|
-
// @TODO 考虑使用 theme.palette.common
|
225
|
-
colors: {
|
226
|
-
white: '#FFFFFF',
|
227
|
-
dark: '#4A707C',
|
228
|
-
gray: '#222222',
|
229
|
-
minor: '#9B9B9B',
|
230
|
-
darkText: '#DCDCDC',
|
231
|
-
background: '#F7F8F8',
|
232
|
-
yellow: '#FFCF71',
|
233
|
-
green: '#44cdc6',
|
234
|
-
red: '#D0021B',
|
235
|
-
blue: '#4E6AF6',
|
236
|
-
primary: '#222222',
|
237
|
-
black: '#222222',
|
238
|
-
secondary: '#44cdc6',
|
239
|
-
mint: '#44cdc6',
|
240
|
-
textSecondary: '#4A4A4A',
|
241
|
-
active: '#5b9025',
|
242
|
-
danger: '#D0021B',
|
243
|
-
lightGrey: '#BCBCBC',
|
244
|
-
},
|
245
|
-
// @deprecated use theme.palette.mode
|
246
|
-
mode,
|
247
99
|
...rest,
|
248
100
|
};
|
249
|
-
|
101
|
+
};
|
102
|
+
|
103
|
+
const defaultUserThemeOptions: UserThemeOptions = {
|
104
|
+
themeName: 'ArcBlock',
|
105
|
+
pageWidth: 'md',
|
106
|
+
disableBlockletTheme: false,
|
107
|
+
// @deprecated use theme.palette
|
108
|
+
colors: {
|
109
|
+
white: '#FFFFFF',
|
110
|
+
dark: '#4A707C',
|
111
|
+
gray: '#222222',
|
112
|
+
minor: '#9B9B9B',
|
113
|
+
darkText: '#DCDCDC',
|
114
|
+
background: '#F7F8F8',
|
115
|
+
yellow: '#FFCF71',
|
116
|
+
green: '#44cdc6',
|
117
|
+
red: '#D0021B',
|
118
|
+
blue: '#4E6AF6',
|
119
|
+
primary: '#222222',
|
120
|
+
black: '#222222',
|
121
|
+
secondary: '#44cdc6',
|
122
|
+
mint: '#44cdc6',
|
123
|
+
textSecondary: '#4A4A4A',
|
124
|
+
active: '#5b9025',
|
125
|
+
danger: '#D0021B',
|
126
|
+
lightGrey: '#BCBCBC',
|
127
|
+
},
|
128
|
+
};
|
129
|
+
|
130
|
+
// https://material-ui.com/customization/default-theme/
|
131
|
+
export const create = (...args: UserThemeOptions[]) => {
|
132
|
+
const userThemeOptions = args.reduce(
|
133
|
+
(acc, curr) => deepmerge(acc, normalizeUserThemeOptions(curr)),
|
134
|
+
normalizeUserThemeOptions(defaultUserThemeOptions)
|
135
|
+
);
|
136
|
+
const { mode, disableBlockletTheme } = userThemeOptions;
|
250
137
|
const blockletThemeOptions = window.blocklet?.theme?.[mode] ?? {};
|
251
|
-
// UX Theme 默认配置
|
252
138
|
const defaultThemeOptions = createDefaultThemeOptions(mode);
|
139
|
+
|
253
140
|
// 合并配置
|
254
141
|
let mergedThemeOptions = defaultThemeOptions;
|
255
142
|
if (!disableBlockletTheme) {
|
256
143
|
mergedThemeOptions = deepmerge(defaultThemeOptions, cleanedObj(blockletThemeOptions));
|
257
144
|
}
|
258
145
|
mergedThemeOptions = deepmerge(mergedThemeOptions, cleanedObj(userThemeOptions));
|
146
|
+
|
147
|
+
// 创建主题
|
259
148
|
const theme = _createTheme(mergedThemeOptions);
|
260
149
|
|
261
150
|
// 异步加载字体
|
@@ -263,7 +152,7 @@ export const create = ({
|
|
263
152
|
loadFonts(Array.from(fonts));
|
264
153
|
|
265
154
|
/**
|
266
|
-
*
|
155
|
+
* 支持响应式字体,theme.typography.$variant 中会添加 @media 分支,比如
|
267
156
|
* {
|
268
157
|
* "h1": {
|
269
158
|
* "fontSize": "3rem",
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps, InfoType } from '../types';
|
2
|
+
import { UserCardProps, InfoType, User } from '../types';
|
3
3
|
import TooltipAvatar from '../Content/tooltip-avatar';
|
4
4
|
|
5
|
-
interface AvatarOnlyCardProps extends UserCardProps {
|
5
|
+
interface AvatarOnlyCardProps extends Omit<UserCardProps, 'user'> {
|
6
|
+
user: User;
|
6
7
|
renderCardContent: () => React.ReactNode;
|
7
8
|
shouldShowHoverCard: boolean;
|
8
9
|
}
|
@@ -1,10 +1,11 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { Box } from '@mui/material';
|
3
|
-
import { InfoType, UserCardProps } from '../types';
|
3
|
+
import { InfoType, UserCardProps, User } from '../types';
|
4
4
|
import MinimalContent from '../Content/minimal';
|
5
5
|
import BasicContent from '../Content/basic';
|
6
6
|
|
7
|
-
interface BasicCardProps extends UserCardProps {
|
7
|
+
interface BasicCardProps extends Omit<UserCardProps, 'user'> {
|
8
|
+
user: User;
|
8
9
|
shouldShowHoverCard: boolean;
|
9
10
|
renderCardContent?: () => React.ReactNode | null;
|
10
11
|
isFull?: boolean;
|
@@ -12,14 +13,25 @@ interface BasicCardProps extends UserCardProps {
|
|
12
13
|
|
13
14
|
// 详细卡片模式下的Basic渲染组件
|
14
15
|
function BasicCard(props: BasicCardProps) {
|
15
|
-
const {
|
16
|
+
const {
|
17
|
+
user,
|
18
|
+
avatarSize = 40,
|
19
|
+
renderCustomContent,
|
20
|
+
isFull = true,
|
21
|
+
infoType = InfoType.Minimal,
|
22
|
+
renderFields,
|
23
|
+
popupRenderFields,
|
24
|
+
...rest
|
25
|
+
} = props;
|
16
26
|
|
17
27
|
return (
|
18
28
|
<Box display="flex" flexDirection="column" width="100%" sx={{ flex: 1, minWidth: 0 }}>
|
19
29
|
<MinimalContent user={user} avatarSize={avatarSize} {...rest} />
|
20
30
|
|
21
|
-
{infoType === InfoType.Basic && <BasicContent user={user} isFull={isFull} />}
|
22
|
-
|
31
|
+
{infoType === InfoType.Basic && <BasicContent user={user} isFull={isFull} renderFields={renderFields} />}
|
32
|
+
<Box className="user-card__footer">
|
33
|
+
{renderCustomContent && <Box sx={{ mt: 1.5 }}>{renderCustomContent()}</Box>}
|
34
|
+
</Box>
|
23
35
|
</Box>
|
24
36
|
);
|
25
37
|
}
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { UserCardProps, InfoType } from '../types';
|
2
|
+
import { UserCardProps, InfoType, User } from '../types';
|
3
3
|
import NameOnlyCard from './name-only';
|
4
4
|
import BasicCard from './basic-info';
|
5
5
|
|
6
|
-
interface DetailedCardProps extends UserCardProps {
|
6
|
+
interface DetailedCardProps extends Omit<UserCardProps, 'user'> {
|
7
|
+
user: User;
|
7
8
|
shouldShowHoverCard: boolean;
|
8
9
|
renderCardContent?: () => React.ReactNode | null;
|
9
10
|
}
|
@@ -1,14 +1,14 @@
|
|
1
1
|
import { Typography } from '@mui/material';
|
2
|
-
import { UserCardProps } from '../types';
|
2
|
+
import { UserCardProps, User } from '../types';
|
3
3
|
import { renderAvatar } from '../components';
|
4
4
|
|
5
5
|
// 详细卡片模式下的NameOnly渲染组件
|
6
|
-
function NameOnlyCard(props: UserCardProps) {
|
7
|
-
const { user, avatarSize = 48 } = props;
|
6
|
+
function NameOnlyCard(props: Omit<UserCardProps, 'user'> & { user: User }) {
|
7
|
+
const { user, avatarSize = 48, onAvatarClick } = props;
|
8
8
|
|
9
9
|
return (
|
10
10
|
<>
|
11
|
-
{renderAvatar(user, avatarSize, props.avatarProps)}
|
11
|
+
{renderAvatar(user, avatarSize, props.avatarProps, onAvatarClick)}
|
12
12
|
<Typography variant="body1">{user.fullName || user.email || user.did}</Typography>
|
13
13
|
</>
|
14
14
|
);
|