@arcblock/ux 2.13.12 → 2.13.14
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/ActivityIndicator/index.js +9 -5
- package/lib/Address/did-address.js +14 -7
- package/lib/Address/responsive-did-address.js +3 -1
- package/lib/BlockletV2/blocklet.js +1 -1
- package/lib/CloseButton/index.js +1 -2
- package/lib/Colors/index.d.ts +1 -3
- package/lib/Colors/index.js +2 -4
- package/lib/Colors/themes/default.d.ts +3 -66
- package/lib/Colors/themes/default.js +4 -74
- package/lib/Colors/themes/did-connect.d.ts +11 -6
- package/lib/Colors/themes/did-connect.js +17 -12
- package/lib/Colors/themes/temp.d.ts +3 -0
- package/lib/Colors/themes/temp.js +3 -0
- package/lib/Config/config-provider.d.ts +4 -5
- package/lib/Config/config-provider.js +7 -26
- package/lib/Config/theme-mode-toggle.js +0 -1
- package/lib/DID/index.js +3 -4
- package/lib/DIDConnect/app-icon.d.ts +8 -0
- package/lib/DIDConnect/app-icon.js +31 -0
- package/lib/DIDConnect/app-info-item.d.ts +7 -0
- package/lib/DIDConnect/app-info-item.js +73 -0
- package/lib/DIDConnect/did-connect-footer.d.ts +4 -0
- package/lib/DIDConnect/did-connect-footer.js +54 -0
- package/lib/DIDConnect/did-connect-logo.d.ts +1 -0
- package/lib/DIDConnect/did-connect-logo.js +11 -0
- package/lib/DIDConnect/index.d.ts +7 -0
- package/lib/DIDConnect/index.js +7 -0
- package/lib/DIDConnect/powered-by.d.ts +3 -0
- package/lib/DIDConnect/powered-by.js +46 -0
- package/lib/DIDConnect/with-container.d.ts +11 -0
- package/lib/DIDConnect/with-container.js +273 -0
- package/lib/DIDConnect/with-ux-theme.d.ts +1 -0
- package/lib/DIDConnect/with-ux-theme.js +23 -0
- package/lib/Datatable/CustomToolbar.js +3 -0
- package/lib/Datatable/index.js +105 -71
- package/lib/Dialog/confirm.d.ts +6 -1
- package/lib/Dialog/confirm.js +7 -3
- package/lib/Dialog/use-confirm.js +6 -0
- package/lib/Footer/index.js +2 -5
- package/lib/Header/header.js +3 -1
- package/lib/Header/responsive-header.js +3 -1
- package/lib/Layout/dashboard/index.js +14 -2
- package/lib/Layout/dashboard/sidebar.js +1 -2
- package/lib/LoadingMask/index.js +4 -3
- package/lib/Locale/selector.js +3 -3
- package/lib/Locale/util.d.ts +3 -3
- package/lib/Locale/util.js +6 -1
- package/lib/LoginButton/index.d.ts +12 -0
- package/lib/LoginButton/index.js +74 -0
- package/lib/NavMenu/nav-menu.js +14 -9
- package/lib/NavMenu/products.js +3 -1
- package/lib/NavMenu/style.js +7 -3
- package/lib/NavMenu/sub-item-group.js +1 -1
- package/lib/PhoneInput/country-select.js +2 -3
- package/lib/SessionBlocklet/index.js +3 -3
- package/lib/SessionUser/components/did-space.js +14 -28
- package/lib/SessionUser/components/logged-in.js +2 -2
- package/lib/SessionUser/components/quick-login-item.js +13 -11
- package/lib/SessionUser/components/session-user-item.js +5 -6
- package/lib/SessionUser/components/session-user-switch.js +15 -13
- package/lib/SessionUser/components/un-login.js +51 -38
- package/lib/SessionUser/components/user-info.js +9 -8
- package/lib/SessionUser/images/did-spaces.svg +7 -13
- package/lib/SharedBridge/index.d.ts +16 -0
- package/lib/SharedBridge/index.js +109 -0
- package/lib/SharedBridge/need-storage-access-api-dialog.d.ts +7 -0
- package/lib/SharedBridge/need-storage-access-api-dialog.js +212 -0
- package/lib/Success/index.js +8 -4
- package/lib/Switch/index.js +3 -3
- package/lib/Tabs/index.js +8 -9
- package/lib/Theme/index.d.ts +2 -2
- package/lib/Theme/index.js +1 -1
- package/lib/Theme/theme-provider.d.ts +5 -1
- package/lib/Theme/theme-provider.js +60 -5
- package/lib/Theme/theme.d.ts +6 -3
- package/lib/Theme/theme.js +55 -19
- package/lib/UserCard/Container/card.js +1 -1
- package/lib/UserCard/Container/dialog.js +1 -1
- package/lib/Util/iframe.d.ts +5 -0
- package/lib/Util/iframe.js +24 -0
- package/lib/Util/index.d.ts +18 -1
- package/lib/Util/index.js +90 -5
- package/lib/type.d.ts +5 -1
- package/package.json +8 -6
- package/src/ActivityIndicator/index.jsx +4 -4
- package/src/Address/did-address.tsx +5 -5
- package/src/Address/responsive-did-address.tsx +11 -1
- package/src/BlockletV2/blocklet.tsx +1 -1
- package/src/CloseButton/index.tsx +1 -2
- package/src/Colors/index.ts +2 -7
- package/src/Colors/themes/default.ts +4 -50
- package/src/Colors/themes/did-connect.ts +13 -6
- package/src/Colors/themes/temp.ts +3 -0
- package/src/Config/config-provider.tsx +17 -30
- package/src/Config/theme-mode-toggle.tsx +1 -1
- package/src/DID/index.tsx +3 -4
- package/src/DIDConnect/app-icon.tsx +36 -0
- package/src/DIDConnect/app-info-item.tsx +82 -0
- package/src/DIDConnect/did-connect-footer.tsx +51 -0
- package/src/DIDConnect/did-connect-logo.tsx +8 -0
- package/src/DIDConnect/index.ts +7 -0
- package/src/DIDConnect/powered-by.tsx +48 -0
- package/src/DIDConnect/with-container.tsx +307 -0
- package/src/DIDConnect/with-ux-theme.tsx +22 -0
- package/src/Datatable/CustomToolbar.jsx +1 -0
- package/src/Datatable/index.jsx +107 -70
- package/src/Dialog/confirm.jsx +31 -23
- package/src/Dialog/use-confirm.jsx +6 -0
- package/src/Footer/index.tsx +2 -2
- package/src/Header/header.tsx +1 -1
- package/src/Header/responsive-header.tsx +2 -0
- package/src/Layout/dashboard/index.tsx +8 -4
- package/src/Layout/dashboard/sidebar.tsx +1 -2
- package/src/LoadingMask/index.tsx +3 -4
- package/src/Locale/selector.tsx +3 -4
- package/src/Locale/util.ts +7 -2
- package/src/LoginButton/index.tsx +73 -0
- package/src/NavMenu/nav-menu.tsx +15 -10
- package/src/NavMenu/products.tsx +1 -1
- package/src/NavMenu/style.ts +5 -2
- package/src/NavMenu/sub-item-group.tsx +1 -1
- package/src/PhoneInput/country-select.tsx +2 -3
- package/src/SessionBlocklet/index.tsx +3 -3
- package/src/SessionUser/components/did-space.tsx +14 -10
- package/src/SessionUser/components/logged-in.tsx +2 -2
- package/src/SessionUser/components/quick-login-item.tsx +11 -12
- package/src/SessionUser/components/session-user-item.tsx +3 -6
- package/src/SessionUser/components/session-user-switch.tsx +13 -12
- package/src/SessionUser/components/un-login.tsx +41 -33
- package/src/SessionUser/components/user-info.tsx +7 -8
- package/src/SessionUser/images/did-spaces.svg +7 -13
- package/src/SharedBridge/index.tsx +123 -0
- package/src/SharedBridge/need-storage-access-api-dialog.tsx +171 -0
- package/src/Success/index.tsx +6 -4
- package/src/Switch/index.jsx +3 -3
- package/src/Tabs/index.tsx +8 -9
- package/src/Theme/index.ts +2 -2
- package/src/Theme/theme-provider.tsx +73 -2
- package/src/Theme/theme.ts +73 -22
- package/src/UserCard/Container/card.tsx +1 -1
- package/src/UserCard/Container/dialog.tsx +1 -1
- package/src/Util/iframe.ts +19 -0
- package/src/Util/index.ts +102 -4
- package/src/type.d.ts +5 -1
package/src/Success/index.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Box } from '@mui/material';
|
1
|
+
import { Box, useTheme } from '@mui/material';
|
2
2
|
|
3
3
|
export interface SuccessProps {
|
4
4
|
size?: number;
|
@@ -7,8 +7,10 @@ export interface SuccessProps {
|
|
7
7
|
}
|
8
8
|
|
9
9
|
// FIXME: @zhanghan 目前无法适配各种 size,后续优化
|
10
|
-
export default function Success({ size = 64, backgroundColor
|
10
|
+
export default function Success({ size = 64, backgroundColor, borderWidth = 4 }: SuccessProps) {
|
11
|
+
const { palette } = useTheme();
|
11
12
|
const contentSize = size - borderWidth * 2;
|
13
|
+
const _backgroundColor = backgroundColor || palette.background.default;
|
12
14
|
|
13
15
|
return (
|
14
16
|
<Box
|
@@ -27,7 +29,7 @@ export default function Success({ size = 64, backgroundColor = 'white', borderWi
|
|
27
29
|
content: '""',
|
28
30
|
height: '125%',
|
29
31
|
position: 'absolute',
|
30
|
-
background:
|
32
|
+
background: _backgroundColor,
|
31
33
|
transform: 'rotate(-45deg)',
|
32
34
|
},
|
33
35
|
'&::before': {
|
@@ -165,7 +167,7 @@ export default function Success({ size = 64, backgroundColor = 'white', borderWi
|
|
165
167
|
height: contentSize + borderWidth * 2,
|
166
168
|
position: 'absolute',
|
167
169
|
transform: 'rotate(-45deg)',
|
168
|
-
backgroundColor,
|
170
|
+
backgroundColor: _backgroundColor,
|
169
171
|
}}
|
170
172
|
/>
|
171
173
|
</Box>
|
package/src/Switch/index.jsx
CHANGED
@@ -17,7 +17,7 @@ const IOSSwitch = styled((props) => <MuiSwitch focusVisibleClassName=".Mui-focus
|
|
17
17
|
transform: 'translateX(16px)',
|
18
18
|
color: '#fff',
|
19
19
|
'& + .MuiSwitch-track': {
|
20
|
-
backgroundColor: theme.palette.
|
20
|
+
backgroundColor: theme.palette.primary.main,
|
21
21
|
opacity: 1,
|
22
22
|
border: 0,
|
23
23
|
},
|
@@ -26,7 +26,7 @@ const IOSSwitch = styled((props) => <MuiSwitch focusVisibleClassName=".Mui-focus
|
|
26
26
|
},
|
27
27
|
},
|
28
28
|
'&.Mui-focusVisible .MuiSwitch-thumb': {
|
29
|
-
color:
|
29
|
+
color: theme.palette.primary.main,
|
30
30
|
border: '6px solid #fff',
|
31
31
|
},
|
32
32
|
'&.Mui-disabled .MuiSwitch-thumb': {
|
@@ -43,7 +43,7 @@ const IOSSwitch = styled((props) => <MuiSwitch focusVisibleClassName=".Mui-focus
|
|
43
43
|
},
|
44
44
|
'& .MuiSwitch-track': {
|
45
45
|
borderRadius: 26 / 2,
|
46
|
-
backgroundColor: theme.palette.
|
46
|
+
backgroundColor: theme.palette.grey[200],
|
47
47
|
opacity: 1,
|
48
48
|
transition: theme.transitions.create(['background-color'], {
|
49
49
|
duration: 500,
|
package/src/Tabs/index.tsx
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import { Tabs as MuiTabs, Tab as MuiTab, type TabsProps as MuiTabsProps } from '@mui/material';
|
2
2
|
|
3
|
-
import { temp as colors } from '../Colors';
|
4
3
|
import { styled } from '../Theme';
|
5
4
|
|
6
5
|
const PREFIX = 'index';
|
@@ -47,7 +46,7 @@ function CardTabs({ tabs, current, onChange, ...rest }: CardTabsProps) {
|
|
47
46
|
},
|
48
47
|
'.MuiTabs-flexContainer': {
|
49
48
|
borderRadius: '100vw',
|
50
|
-
backgroundColor:
|
49
|
+
backgroundColor: 'grey.200',
|
51
50
|
padding: 0.5,
|
52
51
|
display: 'inline-flex',
|
53
52
|
columnGap: 0.25,
|
@@ -60,15 +59,15 @@ function CardTabs({ tabs, current, onChange, ...rest }: CardTabsProps) {
|
|
60
59
|
minHeight: 'auto',
|
61
60
|
lineHeight: 1,
|
62
61
|
py: 1,
|
63
|
-
color:
|
62
|
+
color: 'text.secondary',
|
64
63
|
fontSize: '13px',
|
65
64
|
fontWeight: 'normal',
|
66
65
|
textTransform: 'capitalize',
|
67
66
|
transition: 'background-color 0.2s ease',
|
68
67
|
'&.Mui-selected, &:hover': {
|
69
68
|
backgroundColor: 'white',
|
70
|
-
borderColor:
|
71
|
-
color:
|
69
|
+
borderColor: 'grey.100',
|
70
|
+
color: 'grey.A700',
|
72
71
|
},
|
73
72
|
},
|
74
73
|
'.MuiTabs-indicator': {
|
@@ -115,7 +114,7 @@ function LineTabs({ tabs, current, onChange, ...rest }: LineTabsProps) {
|
|
115
114
|
zIndex: -1,
|
116
115
|
width: '100%',
|
117
116
|
height: '1px',
|
118
|
-
backgroundColor:
|
117
|
+
backgroundColor: 'grey.300',
|
119
118
|
},
|
120
119
|
}
|
121
120
|
: {},
|
@@ -131,18 +130,18 @@ function LineTabs({ tabs, current, onChange, ...rest }: LineTabsProps) {
|
|
131
130
|
lineHeight: 1,
|
132
131
|
py: 1,
|
133
132
|
px: 0,
|
134
|
-
color:
|
133
|
+
color: 'text.secondary',
|
135
134
|
fontSize: '14px',
|
136
135
|
fontWeight: 500,
|
137
136
|
textTransform: 'capitalize',
|
138
137
|
minWidth: 'auto',
|
139
138
|
'&.Mui-selected, &:hover': {
|
140
|
-
color:
|
139
|
+
color: 'primary.main',
|
141
140
|
},
|
142
141
|
},
|
143
142
|
'.MuiTabs-indicator': {
|
144
143
|
height: '1px',
|
145
|
-
backgroundColor:
|
144
|
+
backgroundColor: 'primary.main',
|
146
145
|
},
|
147
146
|
...rest.sx,
|
148
147
|
}}>
|
package/src/Theme/index.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { CreateMUIStyled, Theme } from '@mui/material';
|
2
|
-
import { styled as muiStyled, useTheme } from '@mui/material
|
1
|
+
import type { CreateMUIStyled, Theme } from '@mui/material';
|
2
|
+
import { styled as muiStyled, useTheme } from '@mui/material';
|
3
3
|
|
4
4
|
export * from './theme';
|
5
5
|
export { default as ThemeProvider } from './theme-provider';
|
@@ -1,26 +1,95 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
|
-
import {
|
2
|
+
import { GlobalStyles } from '@mui/material';
|
3
|
+
import { ThemeProvider as MuiThemeProvider, Theme, useTheme } from '@mui/material/styles';
|
3
4
|
import StyledEngineProvider from '@mui/material/StyledEngineProvider';
|
4
5
|
import CssBaseline from '@mui/material/CssBaseline';
|
5
6
|
import { createTheme } from './theme';
|
6
7
|
|
7
8
|
const defaultTheme = createTheme();
|
8
9
|
|
10
|
+
function DarkSchemeStyles({ className }: { className?: string }) {
|
11
|
+
const theme = useTheme();
|
12
|
+
|
13
|
+
if (theme.palette.mode === 'dark') {
|
14
|
+
const trackColor = 'transparent';
|
15
|
+
const thumbColor = theme.palette.grey[300];
|
16
|
+
|
17
|
+
// 处理作用域选择器
|
18
|
+
const prefix = (className || '')
|
19
|
+
.trim()
|
20
|
+
.split(/\s+/)
|
21
|
+
.filter(Boolean)
|
22
|
+
.map((c) => (c.startsWith('.') ? c : `.${c}`))
|
23
|
+
.join(' ');
|
24
|
+
|
25
|
+
const webkitScrollbar = prefix
|
26
|
+
? `${prefix}::-webkit-scrollbar, ${prefix} *::-webkit-scrollbar`
|
27
|
+
: '*::-webkit-scrollbar';
|
28
|
+
const webkitTrack = prefix
|
29
|
+
? `${prefix}::-webkit-scrollbar-track, ${prefix} *::-webkit-scrollbar-track`
|
30
|
+
: '*::-webkit-scrollbar-track';
|
31
|
+
const webkitThumb = prefix
|
32
|
+
? `${prefix}::-webkit-scrollbar-thumb, ${prefix} *::-webkit-scrollbar-thumb`
|
33
|
+
: '*::-webkit-scrollbar-thumb';
|
34
|
+
const firefoxSelector = prefix ? `${prefix}, ${prefix} *` : '*';
|
35
|
+
|
36
|
+
return (
|
37
|
+
<GlobalStyles
|
38
|
+
styles={{
|
39
|
+
// Chrome, Safari, Edge
|
40
|
+
'@supports selector(::-webkit-scrollbar)': {
|
41
|
+
[webkitScrollbar]: {
|
42
|
+
width: '12px',
|
43
|
+
height: '12px',
|
44
|
+
},
|
45
|
+
[webkitTrack]: {
|
46
|
+
background: trackColor,
|
47
|
+
},
|
48
|
+
[webkitThumb]: {
|
49
|
+
background: thumbColor,
|
50
|
+
borderRadius: '6px',
|
51
|
+
border: '2px solid',
|
52
|
+
borderColor: trackColor,
|
53
|
+
backgroundClip: 'padding-box',
|
54
|
+
'&:hover': {
|
55
|
+
background: theme.palette.grey[400],
|
56
|
+
backgroundClip: 'padding-box',
|
57
|
+
},
|
58
|
+
},
|
59
|
+
},
|
60
|
+
// Firefox
|
61
|
+
'@supports not selector(::-webkit-scrollbar)': {
|
62
|
+
[firefoxSelector]: {
|
63
|
+
scrollbarWidth: 'auto',
|
64
|
+
scrollbarColor: `${thumbColor} ${trackColor}`,
|
65
|
+
},
|
66
|
+
},
|
67
|
+
}}
|
68
|
+
/>
|
69
|
+
);
|
70
|
+
}
|
71
|
+
|
72
|
+
return null;
|
73
|
+
}
|
74
|
+
|
9
75
|
export interface ThemeProviderProps {
|
10
76
|
children?: React.ReactNode;
|
11
77
|
theme: Theme;
|
12
78
|
injectFirst?: boolean;
|
79
|
+
/** 指定一个类名,DarkSchemeStyles 只会作用于带有该类的元素及其后代 */
|
80
|
+
darkSchemeClass?: string;
|
13
81
|
}
|
14
82
|
|
15
83
|
/**
|
16
84
|
* 默认的 theme provider, 可以为 webapp/blocklet 快捷的配置好 mui theme provider
|
17
85
|
*/
|
18
|
-
export default function ThemeProvider({ children, theme, injectFirst }: ThemeProviderProps) {
|
86
|
+
export default function ThemeProvider({ children, theme, injectFirst, darkSchemeClass }: ThemeProviderProps) {
|
19
87
|
return (
|
20
88
|
// injectFirst 会影响 makeStyles 自定义样式和 mui styles 覆盖问题
|
21
89
|
<StyledEngineProvider injectFirst={injectFirst}>
|
22
90
|
<MuiThemeProvider theme={theme}>
|
23
91
|
<CssBaseline />
|
92
|
+
<DarkSchemeStyles className={darkSchemeClass} />
|
24
93
|
{children}
|
25
94
|
</MuiThemeProvider>
|
26
95
|
</StyledEngineProvider>
|
@@ -31,10 +100,12 @@ ThemeProvider.propTypes = {
|
|
31
100
|
children: PropTypes.any,
|
32
101
|
theme: PropTypes.any,
|
33
102
|
injectFirst: PropTypes.bool,
|
103
|
+
darkSchemeClass: PropTypes.string,
|
34
104
|
};
|
35
105
|
|
36
106
|
ThemeProvider.defaultProps = {
|
37
107
|
children: null,
|
38
108
|
theme: defaultTheme,
|
39
109
|
injectFirst: true,
|
110
|
+
darkSchemeClass: '',
|
40
111
|
};
|
package/src/Theme/theme.ts
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
/* eslint-disable no-shadow */
|
2
2
|
// https://app.zeplin.io/styleguide/5d1436f1e97c2156f49c0725/colors
|
3
|
-
import type { PaletteMode } from '@mui/material';
|
3
|
+
import type { PaletteMode, Theme } from '@mui/material';
|
4
4
|
import { createTheme as _createTheme, responsiveFontSizes, type ThemeOptions } from '@mui/material/styles';
|
5
5
|
import { deepmerge } from '@mui/utils';
|
6
|
+
import pick from 'lodash/pick';
|
6
7
|
import webfontloader from 'webfontloader';
|
7
|
-
import { BLOCKLET_THEME_LIGHT, BLOCKLET_THEME_DARK, DEFAULT_FONTS } from '@blocklet/theme';
|
8
|
+
import { BLOCKLET_THEME_LIGHT, BLOCKLET_THEME_DARK, DEFAULT_FONTS, BLOCKLET_THEME_PREFER_KEY } from '@blocklet/theme';
|
8
9
|
|
9
|
-
import { cleanedObj } from '../Util';
|
10
|
+
import { cleanedObj, deepmergeAll } from '../Util';
|
10
11
|
|
11
12
|
// 默认只加载最基本的 roboto latin 字体
|
12
13
|
import '@fontsource/roboto/latin-400.css';
|
@@ -71,6 +72,29 @@ export function loadFonts(fonts: string[]) {
|
|
71
72
|
});
|
72
73
|
}
|
73
74
|
|
75
|
+
// 获取默认主题偏好
|
76
|
+
export function getDefaultThemePrefer(): PaletteMode {
|
77
|
+
const prefer = window.blocklet?.theme?.prefer;
|
78
|
+
|
79
|
+
if (prefer === 'system') {
|
80
|
+
// 本地缓存
|
81
|
+
const localPrefer = localStorage.getItem(BLOCKLET_THEME_PREFER_KEY) as PaletteMode;
|
82
|
+
if (localPrefer && (localPrefer === 'light' || localPrefer === 'dark')) {
|
83
|
+
return localPrefer;
|
84
|
+
}
|
85
|
+
|
86
|
+
// 跟随系统
|
87
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
88
|
+
}
|
89
|
+
|
90
|
+
if (prefer === 'light' || prefer === 'dark') {
|
91
|
+
return prefer;
|
92
|
+
}
|
93
|
+
|
94
|
+
// 未设置偏好
|
95
|
+
return 'light';
|
96
|
+
}
|
97
|
+
|
74
98
|
// 创建默认主题配置
|
75
99
|
export function createDefaultThemeOptions(mode: PaletteMode = 'light') {
|
76
100
|
if (mode === 'dark') {
|
@@ -84,20 +108,36 @@ export interface UserThemeOptions extends ThemeOptions {
|
|
84
108
|
disableBlockletTheme?: boolean;
|
85
109
|
}
|
86
110
|
|
87
|
-
//
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
111
|
+
// 用于获取 Blocklet Theme 配置,便于用户创建自定义主题
|
112
|
+
export type ThemeConfig = Pick<Theme, 'palette'>;
|
113
|
+
export function lazyThemeConfig(mode: PaletteMode) {
|
114
|
+
const fields = ['palette'];
|
115
|
+
let config: ThemeConfig | null = null;
|
116
|
+
|
117
|
+
return () => {
|
118
|
+
if (config) return config;
|
119
|
+
|
120
|
+
config = deepmerge(
|
121
|
+
pick(createDefaultThemeOptions(mode), fields),
|
122
|
+
pick(window.blocklet?.theme?.[mode] ?? {}, fields)
|
123
|
+
) as ThemeConfig;
|
124
|
+
|
125
|
+
return config;
|
126
|
+
};
|
127
|
+
}
|
128
|
+
|
129
|
+
// 主要处理 overrides
|
130
|
+
const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }: UserThemeOptions) => {
|
131
|
+
const result: UserThemeOptions = {
|
132
|
+
palette,
|
95
133
|
components: {
|
96
134
|
...overrides,
|
97
135
|
...components,
|
98
136
|
},
|
99
137
|
...rest,
|
100
138
|
};
|
139
|
+
|
140
|
+
return result;
|
101
141
|
};
|
102
142
|
|
103
143
|
const defaultUserThemeOptions: UserThemeOptions = {
|
@@ -128,21 +168,32 @@ const defaultUserThemeOptions: UserThemeOptions = {
|
|
128
168
|
};
|
129
169
|
|
130
170
|
// https://material-ui.com/customization/default-theme/
|
131
|
-
export const create = (...args: UserThemeOptions
|
132
|
-
const
|
133
|
-
|
171
|
+
export const create = (...args: Array<UserThemeOptions | ((config: ThemeConfig) => UserThemeOptions)>) => {
|
172
|
+
const defaultPrefer = getDefaultThemePrefer();
|
173
|
+
const getThemeConfig = lazyThemeConfig(defaultPrefer);
|
174
|
+
const userThemeOptions = args.reduce<UserThemeOptions>(
|
175
|
+
(acc, curr) =>
|
176
|
+
deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(getThemeConfig()) : curr)),
|
134
177
|
normalizeUserThemeOptions(defaultUserThemeOptions)
|
135
178
|
);
|
136
|
-
const
|
137
|
-
const blockletThemeOptions = window.blocklet?.theme?.[
|
138
|
-
const defaultThemeOptions = createDefaultThemeOptions(
|
179
|
+
const prefer = userThemeOptions.mode || userThemeOptions.palette?.mode || defaultPrefer;
|
180
|
+
const blockletThemeOptions = window.blocklet?.theme?.[prefer] ?? {};
|
181
|
+
const defaultThemeOptions = createDefaultThemeOptions(prefer);
|
182
|
+
const { disableBlockletTheme } = userThemeOptions;
|
139
183
|
|
140
184
|
// 合并配置
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
185
|
+
const mergedThemeOptions = deepmergeAll(
|
186
|
+
[
|
187
|
+
defaultThemeOptions,
|
188
|
+
!disableBlockletTheme && cleanedObj(blockletThemeOptions),
|
189
|
+
cleanedObj(userThemeOptions),
|
190
|
+
// 确保 mode 跟 prefer 一致
|
191
|
+
{
|
192
|
+
mode: prefer,
|
193
|
+
palette: { mode: prefer },
|
194
|
+
},
|
195
|
+
].filter(Boolean) as ThemeOptions[]
|
196
|
+
);
|
146
197
|
|
147
198
|
// 创建主题
|
148
199
|
const theme = _createTheme(mergedThemeOptions);
|
@@ -22,7 +22,7 @@ function DialogContainer({ children, sx }: DialogContainerProps) {
|
|
22
22
|
backgroundColor: theme.palette.background.paper,
|
23
23
|
border: '1px solid',
|
24
24
|
borderColor: 'divider',
|
25
|
-
borderRadius:
|
25
|
+
borderRadius: 1,
|
26
26
|
maxWidth: 500,
|
27
27
|
minWidth: 320,
|
28
28
|
display: 'flex',
|
@@ -0,0 +1,19 @@
|
|
1
|
+
export function getCallbackAction(id: string, action: string) {
|
2
|
+
return `callback_${action}_${id}`;
|
3
|
+
}
|
4
|
+
|
5
|
+
// eslint-disable-next-line require-await
|
6
|
+
export async function callIframe(iframe: HTMLIFrameElement, action: string) {
|
7
|
+
const callbackAction = getCallbackAction(iframe.dataset.id as string, action);
|
8
|
+
const promise = new Promise<{ value: any; action: string }>((resolve) => {
|
9
|
+
const handleMessage = ({ data }: MessageEvent) => {
|
10
|
+
if (data.action === callbackAction) {
|
11
|
+
window.removeEventListener('message', handleMessage);
|
12
|
+
resolve(data);
|
13
|
+
}
|
14
|
+
};
|
15
|
+
window.addEventListener('message', handleMessage);
|
16
|
+
});
|
17
|
+
iframe?.contentWindow?.postMessage({ action, callback: callbackAction }, '*');
|
18
|
+
return promise;
|
19
|
+
}
|
package/src/Util/index.ts
CHANGED
@@ -5,8 +5,12 @@ import { getDIDMotifInfo, colors } from '@arcblock/did-motif';
|
|
5
5
|
import isNil from 'lodash/isNil';
|
6
6
|
import omitBy from 'lodash/omitBy';
|
7
7
|
import pRetry from 'p-retry';
|
8
|
+
import Cookies from 'js-cookie';
|
9
|
+
import colorConvert from 'color-convert';
|
10
|
+
import deepmerge, { type DeepmergeOptions } from '@mui/utils/deepmerge';
|
8
11
|
import { DID_PREFIX, BLOCKLET_SERVICE_PATH_PREFIX } from './constant';
|
9
12
|
import type { $TSFixMe, Locale } from '../type';
|
13
|
+
import { getFederatedEnabled } from './federated';
|
10
14
|
|
11
15
|
let dateTool: $TSFixMe | null = null;
|
12
16
|
const IP_V4_REGEX = /^(\d{1,3}\.){3}\d{1,3}(:\d+)?$/;
|
@@ -441,16 +445,74 @@ export const isUrl = (str: string) => {
|
|
441
445
|
return /^https?:\/\//.test(str);
|
442
446
|
};
|
443
447
|
|
444
|
-
const visitorIdKey = '
|
448
|
+
const visitorIdKey = 'vid';
|
449
|
+
const visitorIdKeyLegacy = '__visitor_id';
|
450
|
+
|
445
451
|
export const getVisitorId = () => {
|
446
|
-
|
452
|
+
// FIXME: @zhanghan 短期内做一个兼容,确保在 migrate 前的请求能够携带正确的 vid
|
453
|
+
return Cookies.get(visitorIdKey) || localStorage.getItem(visitorIdKeyLegacy);
|
447
454
|
};
|
448
455
|
|
449
456
|
export const setVisitorId = (value: string | null) => {
|
450
457
|
if (value === null) {
|
451
|
-
|
458
|
+
Cookies.remove(visitorIdKey, {
|
459
|
+
sameSite: 'None',
|
460
|
+
secure: true,
|
461
|
+
});
|
452
462
|
} else {
|
453
|
-
|
463
|
+
Cookies.set(visitorIdKey, value, {
|
464
|
+
sameSite: 'None',
|
465
|
+
secure: true,
|
466
|
+
expires: 365,
|
467
|
+
});
|
468
|
+
}
|
469
|
+
};
|
470
|
+
|
471
|
+
export const ensureVisitorId = () => {
|
472
|
+
let visitorId = localStorage.getItem(visitorIdKeyLegacy);
|
473
|
+
if (visitorId) {
|
474
|
+
localStorage.removeItem(visitorIdKeyLegacy);
|
475
|
+
setVisitorId(visitorId);
|
476
|
+
}
|
477
|
+
if (getVisitorId()) {
|
478
|
+
return;
|
479
|
+
}
|
480
|
+
|
481
|
+
if (!getFederatedEnabled()) {
|
482
|
+
try {
|
483
|
+
// 在支持 crypto.randomUUID 的环境中使用
|
484
|
+
if (window.crypto && typeof window.crypto.randomUUID === 'function') {
|
485
|
+
visitorId = window.crypto.randomUUID();
|
486
|
+
} else {
|
487
|
+
// 在不支持 crypto.randomUUID 的环境中生成随机 ID
|
488
|
+
const randomValues = new Uint8Array(16);
|
489
|
+
if (window.crypto && typeof window.crypto.getRandomValues === 'function') {
|
490
|
+
window.crypto.getRandomValues(randomValues);
|
491
|
+
} else {
|
492
|
+
// 降级方案:使用 Math.random 生成
|
493
|
+
for (let i = 0; i < 16; i++) {
|
494
|
+
randomValues[i] = Math.floor(Math.random() * 256);
|
495
|
+
}
|
496
|
+
}
|
497
|
+
|
498
|
+
// 转换为 UUID 格式
|
499
|
+
const hexArray = Array.from(randomValues).map((b) => b.toString(16).padStart(2, '0'));
|
500
|
+
visitorId = [
|
501
|
+
hexArray.slice(0, 4).join(''),
|
502
|
+
hexArray.slice(4, 6).join(''),
|
503
|
+
hexArray.slice(6, 8).join(''),
|
504
|
+
hexArray.slice(8, 10).join(''),
|
505
|
+
hexArray.slice(10, 16).join(''),
|
506
|
+
].join('-');
|
507
|
+
}
|
508
|
+
} catch (error) {
|
509
|
+
// 如果上述方法都失败,使用时间戳和随机数生成
|
510
|
+
visitorId = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
511
|
+
}
|
512
|
+
}
|
513
|
+
|
514
|
+
if (visitorId) {
|
515
|
+
setVisitorId(visitorId);
|
454
516
|
}
|
455
517
|
};
|
456
518
|
|
@@ -538,3 +600,39 @@ export const lazyRetry = (fn: () => Promise<any>) =>
|
|
538
600
|
export const cleanedObj = (obj: object) => {
|
539
601
|
return omitBy(obj, isNil);
|
540
602
|
};
|
603
|
+
|
604
|
+
/**
|
605
|
+
* 将十六进制颜色转换为 RGBA
|
606
|
+
* @param hex 十六进制颜色字符串 (例如: "#FF0000" 或 "FF0000")
|
607
|
+
* @param alpha 透明度值 (0-1 之间,默认为 1)
|
608
|
+
* @returns RGBA 颜色字符串 (例如: "rgba(255, 0, 0, 1)")
|
609
|
+
*/
|
610
|
+
export function hexToRgba(hex: string, alpha = 1) {
|
611
|
+
const [r, g, b] = colorConvert.hex.rgb(hex);
|
612
|
+
// 返回 RGBA 格式
|
613
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
614
|
+
}
|
615
|
+
|
616
|
+
/**
|
617
|
+
* 依次对数组中的对象进行深度合并
|
618
|
+
* @param objects - 需要合并的对象数组
|
619
|
+
* @param options - deepmerge 的配置选项
|
620
|
+
* @returns 合并后的对象
|
621
|
+
*/
|
622
|
+
export function deepmergeAll<T>(objects: T[], options?: DeepmergeOptions): T {
|
623
|
+
if (!Array.isArray(objects)) {
|
624
|
+
throw new Error('First argument should be an array');
|
625
|
+
}
|
626
|
+
|
627
|
+
if (objects.length === 0) {
|
628
|
+
return {} as T;
|
629
|
+
}
|
630
|
+
|
631
|
+
if (objects.length === 1) {
|
632
|
+
return objects[0];
|
633
|
+
}
|
634
|
+
|
635
|
+
return objects.reduce((acc, obj) => {
|
636
|
+
return deepmerge(acc, obj, options);
|
637
|
+
});
|
638
|
+
}
|
package/src/type.d.ts
CHANGED
@@ -25,7 +25,11 @@ export type Blocklet = {
|
|
25
25
|
version: string;
|
26
26
|
mode: string;
|
27
27
|
tenantMode: 'single' | 'multiple';
|
28
|
-
theme:
|
28
|
+
theme: {
|
29
|
+
prefer?: PaletteMode | 'system';
|
30
|
+
light: Theme;
|
31
|
+
dark: Theme;
|
32
|
+
};
|
29
33
|
navigation: $TSFixMe[];
|
30
34
|
preferences: Record<string, any>;
|
31
35
|
languages: {
|