@arcblock/ux 2.13.27 → 2.13.29
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/Config/config-provider.d.ts +1 -0
- package/lib/DIDConnect/did-connect-container.d.ts +2 -1
- package/lib/DIDConnect/did-connect-container.js +4 -2
- package/lib/DIDConnect/index.d.ts +1 -0
- package/lib/DIDConnect/index.js +2 -1
- package/lib/DIDConnect/request-storage-access-api-dialog.d.ts +12 -0
- package/lib/DIDConnect/request-storage-access-api-dialog.js +325 -0
- package/lib/RelativeTime/index.d.ts +2 -1
- package/lib/RelativeTime/index.js +11 -5
- package/lib/SessionUser/components/un-login.js +29 -37
- package/lib/SharedBridge/index.d.ts +5 -6
- package/lib/SharedBridge/index.js +34 -48
- package/lib/Tabs/index.js +2 -2
- package/lib/Theme/theme-provider.d.ts +5 -2
- package/lib/Theme/theme-provider.js +28 -9
- package/lib/Theme/theme.d.ts +6 -4
- package/lib/Theme/theme.js +15 -9
- package/package.json +6 -6
- package/src/DIDConnect/did-connect-container.tsx +4 -1
- package/src/DIDConnect/index.ts +1 -0
- package/src/DIDConnect/request-storage-access-api-dialog.tsx +280 -0
- package/src/RelativeTime/index.tsx +25 -4
- package/src/SessionUser/components/un-login.tsx +21 -29
- package/src/SharedBridge/index.tsx +91 -97
- package/src/Tabs/index.tsx +2 -2
- package/src/Theme/theme-provider.tsx +36 -10
- package/src/Theme/theme.ts +21 -15
- package/lib/LoginButton/index.d.ts +0 -12
- package/lib/LoginButton/index.js +0 -74
- package/lib/SharedBridge/need-storage-access-api-dialog.d.ts +0 -6
- package/lib/SharedBridge/need-storage-access-api-dialog.js +0 -191
- package/src/LoginButton/index.tsx +0 -73
- package/src/SharedBridge/need-storage-access-api-dialog.tsx +0 -149
@@ -55,6 +55,7 @@ export interface RelativeTimeProps {
|
|
55
55
|
tz?: string;
|
56
56
|
relativeRange?: number;
|
57
57
|
enableTooltip?: boolean;
|
58
|
+
showUTCPrefix?: boolean;
|
58
59
|
}
|
59
60
|
|
60
61
|
function useRelativeTime({
|
@@ -144,13 +145,17 @@ function UTCChip({
|
|
144
145
|
sign,
|
145
146
|
hoursOffset,
|
146
147
|
setIsUtc,
|
148
|
+
showUTCPrefix = true,
|
147
149
|
}: {
|
148
150
|
locale: Locale;
|
149
151
|
isUtc?: boolean;
|
150
152
|
sign: string;
|
151
153
|
hoursOffset: number;
|
152
154
|
setIsUtc: (data: any) => void;
|
155
|
+
showUTCPrefix?: boolean;
|
153
156
|
}) {
|
157
|
+
const prefix = showUTCPrefix ? `${translations[locale].utc}: ` : '';
|
158
|
+
|
154
159
|
return (
|
155
160
|
<Box
|
156
161
|
component="span"
|
@@ -161,10 +166,11 @@ function UTCChip({
|
|
161
166
|
fontSize: '0.8rem',
|
162
167
|
borderColor: 'divider',
|
163
168
|
borderRadius: '20px',
|
164
|
-
padding: '
|
169
|
+
padding: '4px 8px',
|
170
|
+
lineHeight: 1,
|
165
171
|
}}
|
166
172
|
onClick={() => setIsUtc((r: any) => !r)}>
|
167
|
-
{`${
|
173
|
+
{`${prefix}${isUtc ? 'UTC' : `UTC${sign}${hoursOffset}`}`}
|
168
174
|
</Box>
|
169
175
|
);
|
170
176
|
}
|
@@ -179,6 +185,7 @@ export default function RelativeTime({
|
|
179
185
|
tz,
|
180
186
|
relativeRange,
|
181
187
|
enableTooltip = true,
|
188
|
+
showUTCPrefix = true,
|
182
189
|
...rest
|
183
190
|
}: RelativeTimeProps) {
|
184
191
|
const { innerContent, popContent, isUtc, setIsUtc, sign, hoursOffset, relativeString } = useRelativeTime({
|
@@ -212,7 +219,14 @@ export default function RelativeTime({
|
|
212
219
|
·
|
213
220
|
</Box>
|
214
221
|
|
215
|
-
<UTCChip
|
222
|
+
<UTCChip
|
223
|
+
locale={locale}
|
224
|
+
isUtc={isUtc}
|
225
|
+
sign={sign}
|
226
|
+
hoursOffset={hoursOffset}
|
227
|
+
setIsUtc={setIsUtc}
|
228
|
+
showUTCPrefix={showUTCPrefix}
|
229
|
+
/>
|
216
230
|
</Box>
|
217
231
|
</Tooltip>
|
218
232
|
);
|
@@ -226,7 +240,14 @@ export default function RelativeTime({
|
|
226
240
|
</Box>
|
227
241
|
|
228
242
|
{type === 'utc' && (
|
229
|
-
<UTCChip
|
243
|
+
<UTCChip
|
244
|
+
locale={locale}
|
245
|
+
isUtc={isUtc}
|
246
|
+
sign={sign}
|
247
|
+
hoursOffset={hoursOffset}
|
248
|
+
setIsUtc={setIsUtc}
|
249
|
+
showUTCPrefix={showUTCPrefix}
|
250
|
+
/>
|
230
251
|
)}
|
231
252
|
</Box>
|
232
253
|
</Tooltip>
|
@@ -27,7 +27,7 @@ import { translations } from '../libs/translation';
|
|
27
27
|
import Typography from '../../Typography';
|
28
28
|
import QuickLoginItem from './quick-login-item';
|
29
29
|
import { getFederatedEnabled, getMaster } from '../../Util/federated';
|
30
|
-
import
|
30
|
+
import { BLOCKLET_SERVICE_PATH_PREFIX } from '../../Util/constant';
|
31
31
|
|
32
32
|
export interface UnLoginProps {
|
33
33
|
session: Session;
|
@@ -70,7 +70,7 @@ export default function UnLogin({ session, onLogin = noop, size = 24, dark = fal
|
|
70
70
|
const loginAppName = loginApp?.appName || 'DID Connect';
|
71
71
|
const loginAppLogo = joinURL(
|
72
72
|
loginApp?.appUrl || '/',
|
73
|
-
loginApp?.appLogo ||
|
73
|
+
loginApp?.appLogo || `${BLOCKLET_SERVICE_PATH_PREFIX}/blocklet/logo?imageFilter=convert&f=png&h=80`
|
74
74
|
);
|
75
75
|
|
76
76
|
useEffect(() => {
|
@@ -105,34 +105,26 @@ export default function UnLogin({ session, onLogin = noop, size = 24, dark = fal
|
|
105
105
|
|
106
106
|
return (
|
107
107
|
<>
|
108
|
-
<
|
109
|
-
|
108
|
+
<IconButton
|
109
|
+
ref={userAnchorRef}
|
110
|
+
data-cy="sessionManager-login"
|
111
|
+
className="arc-session-user-unlogin"
|
112
|
+
size="medium"
|
110
113
|
onClick={_onLogin}
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
<Icon
|
126
|
-
icon={UserIcon}
|
127
|
-
fontSize={size}
|
128
|
-
color={dark ? '#fff' : 'inherit'}
|
129
|
-
style={{ transform: 'scale(1.25)' }}
|
130
|
-
/>
|
131
|
-
)}
|
132
|
-
</IconButton>
|
133
|
-
);
|
134
|
-
}}
|
135
|
-
/>
|
114
|
+
aria-label="Login button">
|
115
|
+
{isFirstLoading ? (
|
116
|
+
<Box width={size} height={size} display="flex" justifyContent="center" alignItems="center">
|
117
|
+
<CircularProgress style={{ width: size - 4, height: size - 4, color: dark ? '#fff' : '' }} />
|
118
|
+
</Box>
|
119
|
+
) : (
|
120
|
+
<Icon
|
121
|
+
icon={UserIcon}
|
122
|
+
fontSize={size}
|
123
|
+
color={dark ? '#fff' : 'inherit'}
|
124
|
+
style={{ transform: 'scale(1.25)' }}
|
125
|
+
/>
|
126
|
+
)}
|
127
|
+
</IconButton>
|
136
128
|
<Popper
|
137
129
|
open={currentState.open}
|
138
130
|
anchorEl={userAnchorRef.current}
|
@@ -1,119 +1,113 @@
|
|
1
1
|
import { Box } from '@mui/material';
|
2
2
|
import type { SxProps } from '@mui/material';
|
3
|
-
import
|
3
|
+
import { forwardRef, memo, useEffect, useId, useImperativeHandle, useRef } from 'react';
|
4
4
|
import { withQuery } from 'ufo';
|
5
5
|
import { useMemoizedFn, useReactive } from 'ahooks';
|
6
|
+
import noop from 'lodash/noop';
|
6
7
|
|
7
8
|
import { mergeSx } from '../Util/style';
|
8
9
|
import { callIframe, getCallbackAction } from '../Util/iframe';
|
9
10
|
import { Locale } from '../type';
|
10
|
-
import NeedStorageAccessApiDialog from './need-storage-access-api-dialog';
|
11
|
-
import { DIDConnectContainer } from '../DIDConnect';
|
12
11
|
|
13
|
-
const SharedBridge =
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
}) {
|
29
|
-
const _iframeRef = useRef<HTMLIFrameElement>(null);
|
30
|
-
const refId = useId();
|
31
|
-
const dataId = `shared-bridge_${refId}`;
|
32
|
-
const currentState = useReactive<{
|
33
|
-
hasInited?: boolean;
|
34
|
-
open: boolean;
|
35
|
-
hasStorageAccess: boolean;
|
36
|
-
origin: string;
|
37
|
-
host: string;
|
38
|
-
}>({
|
39
|
-
hasInited: undefined,
|
40
|
-
open: false,
|
41
|
-
hasStorageAccess: false,
|
42
|
-
get origin() {
|
43
|
-
try {
|
44
|
-
return new URL(src).origin;
|
45
|
-
} catch (error) {
|
46
|
-
return src;
|
47
|
-
}
|
48
|
-
},
|
49
|
-
get host() {
|
50
|
-
try {
|
51
|
-
return new URL(src).host;
|
52
|
-
} catch (error) {
|
53
|
-
return src;
|
54
|
-
}
|
12
|
+
const SharedBridge = forwardRef(
|
13
|
+
(
|
14
|
+
{
|
15
|
+
src,
|
16
|
+
onClick,
|
17
|
+
onLoad = noop,
|
18
|
+
sx,
|
19
|
+
locale = 'en',
|
20
|
+
...rest
|
21
|
+
}: {
|
22
|
+
src: string;
|
23
|
+
onClick: (data: { action: string; value: boolean; visitorId?: string; error?: Error }) => void;
|
24
|
+
onLoad?: () => void;
|
25
|
+
sx?: SxProps;
|
26
|
+
locale?: Locale;
|
55
27
|
},
|
56
|
-
|
28
|
+
ref
|
29
|
+
) => {
|
30
|
+
const targetIframeRef = useRef<HTMLIFrameElement>(null);
|
31
|
+
const refId = useId();
|
32
|
+
const dataId = `shared-bridge_${refId}`;
|
33
|
+
const currentState = useReactive<{
|
34
|
+
hasInited?: boolean;
|
35
|
+
open: boolean;
|
36
|
+
hasStorageAccess: boolean;
|
37
|
+
origin: string;
|
38
|
+
host: string;
|
39
|
+
containerEl: HTMLDivElement | null;
|
40
|
+
}>({
|
41
|
+
hasInited: undefined,
|
42
|
+
open: false,
|
43
|
+
hasStorageAccess: false,
|
44
|
+
containerEl: null,
|
45
|
+
get origin() {
|
46
|
+
try {
|
47
|
+
return new URL(src).origin;
|
48
|
+
} catch (error) {
|
49
|
+
return src;
|
50
|
+
}
|
51
|
+
},
|
52
|
+
get host() {
|
53
|
+
try {
|
54
|
+
return new URL(src).host;
|
55
|
+
} catch (error) {
|
56
|
+
return src;
|
57
|
+
}
|
58
|
+
},
|
59
|
+
});
|
57
60
|
|
58
|
-
|
61
|
+
useEffect(() => {
|
62
|
+
async function handleMessage(event: MessageEvent) {
|
63
|
+
const { data } = event;
|
64
|
+
if (data.action === getCallbackAction(dataId, 'requestStorageAccess')) {
|
65
|
+
currentState.open = false;
|
59
66
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
currentState.open = false;
|
67
|
+
if (!data.value) {
|
68
|
+
onClick(data);
|
69
|
+
return;
|
70
|
+
}
|
65
71
|
|
66
|
-
|
67
|
-
onClick(data);
|
68
|
-
|
72
|
+
const { value: visitorId } = await callIframe(targetIframeRef.current as HTMLIFrameElement, 'getVisitorId');
|
73
|
+
onClick({ ...data, visitorId });
|
74
|
+
} else if (data.action === getCallbackAction(dataId, 'preRequestStorageAccess')) {
|
75
|
+
currentState.open = true;
|
69
76
|
}
|
70
|
-
|
71
|
-
const { value: visitorId } = await callIframe(targetIframeRef.current as HTMLIFrameElement, 'getVisitorId');
|
72
|
-
onClick({ ...data, visitorId });
|
73
|
-
} else if (data.action === getCallbackAction(dataId, 'preRequestStorageAccess')) {
|
74
|
-
currentState.open = true;
|
75
77
|
}
|
76
|
-
}
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
window.addEventListener('message', handleMessage);
|
80
|
+
return () => {
|
81
|
+
window.removeEventListener('message', handleMessage);
|
82
|
+
};
|
83
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
84
|
+
}, [onClick, dataId, targetIframeRef?.current]);
|
84
85
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
const handleLoad = useMemoizedFn(() => {
|
87
|
+
callIframe(targetIframeRef.current as HTMLIFrameElement, 'hasStorageAccess').then(({ value }) => {
|
88
|
+
currentState.hasStorageAccess = value;
|
89
|
+
currentState.hasInited = true;
|
90
|
+
});
|
91
|
+
// HACK: 如果目标 bridge 1s 内没有初始化,则认为目标 bridge 不兼容,不进行后续内容的加载
|
92
|
+
setTimeout(() => {
|
93
|
+
if (currentState.hasInited === undefined) {
|
94
|
+
currentState.hasInited = false;
|
95
|
+
}
|
96
|
+
}, 1000);
|
97
|
+
onLoad();
|
89
98
|
});
|
90
|
-
setTimeout(() => {
|
91
|
-
if (currentState.hasInited === undefined) {
|
92
|
-
currentState.hasInited = false;
|
93
|
-
}
|
94
|
-
}, 1000);
|
95
|
-
onLoad();
|
96
|
-
});
|
97
|
-
|
98
|
-
if (currentState.hasInited === false) {
|
99
|
-
return null;
|
100
|
-
}
|
101
99
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
<DIDConnectContainer popup hideCloseButton open={currentState.open}>
|
109
|
-
<NeedStorageAccessApiDialog locale={locale} origin={currentState.origin} host={currentState.host} />
|
110
|
-
</DIDConnectContainer>
|
100
|
+
useImperativeHandle(ref, () => ({
|
101
|
+
callIframe(action: string) {
|
102
|
+
return callIframe(targetIframeRef.current as HTMLIFrameElement, action);
|
103
|
+
},
|
104
|
+
}));
|
105
|
+
return (
|
111
106
|
<Box
|
112
107
|
{...rest}
|
113
108
|
component="iframe"
|
114
109
|
ref={targetIframeRef}
|
115
110
|
onLoad={handleLoad}
|
116
|
-
title="shared-bridge"
|
117
111
|
data-id={dataId}
|
118
112
|
src={withQuery(src, { id: dataId })}
|
119
113
|
sx={mergeSx(
|
@@ -125,13 +119,13 @@ const SharedBridge = memo(function SharedBridge({
|
|
125
119
|
width: '100%',
|
126
120
|
height: '100%',
|
127
121
|
cursor: 'pointer',
|
128
|
-
|
122
|
+
backgroundColor: 'transparent',
|
129
123
|
},
|
130
124
|
sx
|
131
125
|
)}
|
132
126
|
/>
|
133
|
-
|
134
|
-
|
135
|
-
|
127
|
+
);
|
128
|
+
}
|
129
|
+
);
|
136
130
|
|
137
|
-
export default SharedBridge;
|
131
|
+
export default memo(SharedBridge);
|
package/src/Tabs/index.tsx
CHANGED
@@ -46,7 +46,7 @@ function CardTabs({ tabs, current, onChange, ...rest }: CardTabsProps) {
|
|
46
46
|
},
|
47
47
|
'.MuiTabs-flexContainer': {
|
48
48
|
borderRadius: '100vw',
|
49
|
-
backgroundColor: 'grey.
|
49
|
+
backgroundColor: 'grey.100',
|
50
50
|
padding: 0.5,
|
51
51
|
display: 'inline-flex',
|
52
52
|
columnGap: 0.25,
|
@@ -65,7 +65,7 @@ function CardTabs({ tabs, current, onChange, ...rest }: CardTabsProps) {
|
|
65
65
|
textTransform: 'capitalize',
|
66
66
|
transition: 'background-color 0.2s ease',
|
67
67
|
'&.Mui-selected, &:hover': {
|
68
|
-
backgroundColor: '
|
68
|
+
backgroundColor: 'action.selected',
|
69
69
|
borderColor: 'grey.100',
|
70
70
|
color: 'grey.A700',
|
71
71
|
},
|
@@ -1,13 +1,20 @@
|
|
1
1
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import { GlobalStyles, PaletteMode } from '@mui/material';
|
4
|
-
import { ThemeProvider as MuiThemeProvider, Theme, useTheme } from '@mui/material/styles';
|
4
|
+
import { ThemeProvider as MuiThemeProvider, Theme, ThemeOptions, useTheme } from '@mui/material/styles';
|
5
5
|
import StyledEngineProvider from '@mui/material/StyledEngineProvider';
|
6
6
|
import CssBaseline from '@mui/material/CssBaseline';
|
7
7
|
import set from 'lodash/set';
|
8
8
|
import { BLOCKLET_THEME_PREFER_KEY } from '@blocklet/theme';
|
9
9
|
|
10
|
-
import {
|
10
|
+
import {
|
11
|
+
createTheme,
|
12
|
+
getDefaultThemePrefer,
|
13
|
+
isTheme,
|
14
|
+
isUxTheme,
|
15
|
+
lazyCreateDefaultTheme,
|
16
|
+
type UxThemeOptions,
|
17
|
+
} from './theme';
|
11
18
|
|
12
19
|
const defaultTheme = createTheme();
|
13
20
|
|
@@ -15,6 +22,7 @@ const defaultTheme = createTheme();
|
|
15
22
|
export interface ColorSchemeContextType {
|
16
23
|
mode: PaletteMode;
|
17
24
|
toggleMode: () => void;
|
25
|
+
changeMode: (mode: PaletteMode) => void;
|
18
26
|
prefer?: Prefer;
|
19
27
|
}
|
20
28
|
|
@@ -102,7 +110,7 @@ function DarkSchemeStyles({ className }: { className?: string }) {
|
|
102
110
|
return null;
|
103
111
|
}
|
104
112
|
|
105
|
-
export type UxTheme =
|
113
|
+
export type UxTheme = ThemeOptions | ((parentTheme: Theme, context?: { mode: PaletteMode }) => Theme);
|
106
114
|
export type Prefer = 'light' | 'dark' | 'system';
|
107
115
|
|
108
116
|
interface BaseThemeProviderProps {
|
@@ -113,7 +121,7 @@ interface BaseThemeProviderProps {
|
|
113
121
|
darkSchemeClass?: string;
|
114
122
|
}
|
115
123
|
|
116
|
-
/**
|
124
|
+
/** 快速配置 MUI 主题 */
|
117
125
|
function BaseThemeProvider({
|
118
126
|
children,
|
119
127
|
theme = defaultTheme,
|
@@ -144,7 +152,7 @@ interface ColorSchemeProviderProps extends BaseThemeProviderProps {
|
|
144
152
|
disableBlockletTheme?: boolean;
|
145
153
|
}
|
146
154
|
|
147
|
-
/**
|
155
|
+
/** 配置带颜色模式切换功能的 MUI 主题 */
|
148
156
|
function ColorSchemeProvider({
|
149
157
|
children,
|
150
158
|
theme: themeInput,
|
@@ -153,14 +161,21 @@ function ColorSchemeProvider({
|
|
153
161
|
...rest
|
154
162
|
}: ThemeProviderProps) {
|
155
163
|
const [mode, setMode] = useState<PaletteMode>(() => resolveMode(prefer));
|
164
|
+
const parentTheme = useTheme();
|
156
165
|
|
157
166
|
const _themeInput = useMemo(() => {
|
158
|
-
let result:
|
159
|
-
const
|
167
|
+
let result: UxThemeOptions = {};
|
168
|
+
const createBaseTheme = lazyCreateDefaultTheme(mode);
|
160
169
|
|
161
170
|
if (themeInput) {
|
162
171
|
if (typeof themeInput === 'function') {
|
163
|
-
|
172
|
+
const baseTheme = createBaseTheme();
|
173
|
+
|
174
|
+
if (isUxTheme(parentTheme)) {
|
175
|
+
result = { ...themeInput(parentTheme, { mode }) };
|
176
|
+
} else {
|
177
|
+
result = { ...themeInput(baseTheme, { mode }) };
|
178
|
+
}
|
164
179
|
} else {
|
165
180
|
result = { ...themeInput };
|
166
181
|
}
|
@@ -170,7 +185,7 @@ function ColorSchemeProvider({
|
|
170
185
|
set(result, 'mode', mode);
|
171
186
|
|
172
187
|
return result;
|
173
|
-
}, [mode, themeInput]);
|
188
|
+
}, [mode, themeInput, parentTheme]);
|
174
189
|
|
175
190
|
const theme = useMemo(() => {
|
176
191
|
return createTheme({ ..._themeInput, disableBlockletTheme });
|
@@ -183,13 +198,24 @@ function ColorSchemeProvider({
|
|
183
198
|
localStorage.setItem(BLOCKLET_THEME_PREFER_KEY, newMode);
|
184
199
|
}, [mode, setMode]);
|
185
200
|
|
201
|
+
const changeMode = useCallback(
|
202
|
+
(newMode: PaletteMode) => {
|
203
|
+
if (mode !== newMode) {
|
204
|
+
setMode(newMode);
|
205
|
+
localStorage.setItem(BLOCKLET_THEME_PREFER_KEY, newMode);
|
206
|
+
}
|
207
|
+
},
|
208
|
+
[mode, setMode]
|
209
|
+
);
|
210
|
+
|
186
211
|
const colorSchemeValue = useMemo(
|
187
212
|
() => ({
|
188
213
|
mode,
|
189
214
|
toggleMode,
|
215
|
+
changeMode,
|
190
216
|
prefer,
|
191
217
|
}),
|
192
|
-
[mode, prefer, toggleMode]
|
218
|
+
[mode, prefer, toggleMode, changeMode]
|
193
219
|
);
|
194
220
|
|
195
221
|
useEffect(() => {
|
package/src/Theme/theme.ts
CHANGED
@@ -20,6 +20,11 @@ export function isTheme(obj: any): obj is Theme {
|
|
20
20
|
return obj && typeof obj === 'object' && obj.palette && typeof obj.palette.getContrastText === 'function';
|
21
21
|
}
|
22
22
|
|
23
|
+
/** 是否是 UX Theme 对象 */
|
24
|
+
export function isUxTheme(obj: any): obj is Theme {
|
25
|
+
return isTheme(obj) && obj.__isUxTheme__ === true;
|
26
|
+
}
|
27
|
+
|
23
28
|
// 收集字体配置
|
24
29
|
export function collectFontFamilies(obj?: { fontFamily?: string }, fontSet: Set<string> = new Set()): Set<string> {
|
25
30
|
if (!obj || typeof obj !== 'object') return fontSet;
|
@@ -107,26 +112,26 @@ export function createDefaultThemeOptions(mode: PaletteMode = 'light') {
|
|
107
112
|
return BLOCKLET_THEME_LIGHT;
|
108
113
|
}
|
109
114
|
|
110
|
-
export interface
|
115
|
+
export interface UxThemeOptions extends ThemeOptions {
|
111
116
|
disableBlockletTheme?: boolean;
|
112
117
|
}
|
113
118
|
|
114
|
-
|
115
|
-
|
116
|
-
let config: Partial<Theme> | null = null;
|
119
|
+
export function lazyCreateDefaultTheme(mode: PaletteMode) {
|
120
|
+
let theme: Theme | null = null;
|
117
121
|
|
118
122
|
return () => {
|
119
|
-
if (
|
123
|
+
if (theme) return theme;
|
120
124
|
|
121
|
-
|
125
|
+
const options = deepmerge(createDefaultThemeOptions(mode), window.blocklet?.theme?.[mode] ?? {});
|
122
126
|
|
123
|
-
|
127
|
+
theme = _createTheme(options);
|
128
|
+
return theme;
|
124
129
|
};
|
125
130
|
}
|
126
131
|
|
127
132
|
// 主要处理 overrides
|
128
|
-
const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }:
|
129
|
-
const result:
|
133
|
+
const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }: UxThemeOptions) => {
|
134
|
+
const result: UxThemeOptions = {
|
130
135
|
palette,
|
131
136
|
components: {
|
132
137
|
...overrides,
|
@@ -138,7 +143,7 @@ const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }:
|
|
138
143
|
return result;
|
139
144
|
};
|
140
145
|
|
141
|
-
const
|
146
|
+
const defaultUxThemeOptions: UxThemeOptions = {
|
142
147
|
themeName: 'ArcBlock',
|
143
148
|
pageWidth: 'md',
|
144
149
|
disableBlockletTheme: false,
|
@@ -166,13 +171,13 @@ const defaultUserThemeOptions: UserThemeOptions = {
|
|
166
171
|
};
|
167
172
|
|
168
173
|
// https://material-ui.com/customization/default-theme/
|
169
|
-
export const create = (...args: Array<
|
174
|
+
export const create = (...args: Array<UxThemeOptions | ((baseTheme: Theme) => UxThemeOptions)>) => {
|
170
175
|
const defaultPrefer = getDefaultThemePrefer();
|
171
|
-
const
|
172
|
-
const userThemeOptions = args.reduce<
|
176
|
+
const createBaseTheme = lazyCreateDefaultTheme(defaultPrefer);
|
177
|
+
const userThemeOptions = args.reduce<UxThemeOptions>(
|
173
178
|
(acc, curr) =>
|
174
|
-
deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(
|
175
|
-
normalizeUserThemeOptions(
|
179
|
+
deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(createBaseTheme()) : curr)),
|
180
|
+
normalizeUserThemeOptions(defaultUxThemeOptions)
|
176
181
|
);
|
177
182
|
const prefer = userThemeOptions.mode || userThemeOptions.palette?.mode || defaultPrefer;
|
178
183
|
const blockletThemeOptions = window.blocklet?.theme?.[prefer] ?? {};
|
@@ -195,6 +200,7 @@ export const create = (...args: Array<UserThemeOptions | ((config: Partial<Theme
|
|
195
200
|
|
196
201
|
// 创建主题
|
197
202
|
const theme = _createTheme(mergedThemeOptions);
|
203
|
+
theme.__isUxTheme__ = true;
|
198
204
|
|
199
205
|
// 异步加载字体
|
200
206
|
const fonts = collectFontFamilies(theme.typography);
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import { Locale } from '../type';
|
2
|
-
type LoginButtonProps = {
|
3
|
-
onClick: (options?: {
|
4
|
-
openMode?: 'popup' | 'window';
|
5
|
-
}) => void;
|
6
|
-
render: (options: {
|
7
|
-
onClick: () => void;
|
8
|
-
}) => React.ReactNode;
|
9
|
-
locale?: Locale;
|
10
|
-
};
|
11
|
-
export default function LoginButton({ onClick, render, locale }: LoginButtonProps): string | number | boolean | Iterable<import("react").ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
12
|
-
export {};
|
package/lib/LoginButton/index.js
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
-
import { Box } from '@mui/material';
|
3
|
-
import { joinURL } from 'ufo';
|
4
|
-
import { useRef, useState } from 'react';
|
5
|
-
import { useMemoizedFn } from 'ahooks';
|
6
|
-
import { useBrowser } from '@arcblock/react-hooks';
|
7
|
-
import SharedBridge from '../SharedBridge';
|
8
|
-
import { setVisitorId } from '../Util';
|
9
|
-
import { getFederatedEnabled, getMaster } from '../Util/federated';
|
10
|
-
import { callIframe } from '../Util/iframe';
|
11
|
-
export default function LoginButton({
|
12
|
-
onClick,
|
13
|
-
render,
|
14
|
-
locale
|
15
|
-
}) {
|
16
|
-
const blocklet = window?.blocklet;
|
17
|
-
const federatedEnabled = getFederatedEnabled(blocklet);
|
18
|
-
const masterSite = getMaster(blocklet);
|
19
|
-
const sharedBridgeRef = useRef(null);
|
20
|
-
const [hasStorageAccess, setHasStorageAccess] = useState(false);
|
21
|
-
const browser = useBrowser();
|
22
|
-
const handleClick = useMemoizedFn(() => {
|
23
|
-
if (hasStorageAccess) {
|
24
|
-
onClick({
|
25
|
-
openMode: 'popup'
|
26
|
-
});
|
27
|
-
} else {
|
28
|
-
onClick();
|
29
|
-
}
|
30
|
-
});
|
31
|
-
const handleLoad = useMemoizedFn(async () => {
|
32
|
-
const {
|
33
|
-
value: visitorId
|
34
|
-
} = await callIframe(sharedBridgeRef.current, 'getVisitorId');
|
35
|
-
if (visitorId) {
|
36
|
-
setHasStorageAccess(true);
|
37
|
-
setVisitorId(visitorId);
|
38
|
-
}
|
39
|
-
});
|
40
|
-
const handleClickBridge = useMemoizedFn(({
|
41
|
-
value,
|
42
|
-
visitorId
|
43
|
-
}) => {
|
44
|
-
if (visitorId) {
|
45
|
-
setVisitorId(visitorId);
|
46
|
-
}
|
47
|
-
if (value) {
|
48
|
-
onClick({
|
49
|
-
openMode: 'popup'
|
50
|
-
});
|
51
|
-
} else {
|
52
|
-
onClick();
|
53
|
-
}
|
54
|
-
});
|
55
|
-
if (browser.arcSphere || browser.wallet) {
|
56
|
-
return render({
|
57
|
-
onClick
|
58
|
-
});
|
59
|
-
}
|
60
|
-
return /*#__PURE__*/_jsxs(Box, {
|
61
|
-
sx: {
|
62
|
-
position: 'relative'
|
63
|
-
},
|
64
|
-
children: [render({
|
65
|
-
onClick: handleClick
|
66
|
-
}), masterSite?.appUrl && federatedEnabled ? /*#__PURE__*/_jsx(SharedBridge, {
|
67
|
-
locale: locale,
|
68
|
-
iframeRef: sharedBridgeRef,
|
69
|
-
onLoad: handleLoad,
|
70
|
-
onClick: handleClickBridge,
|
71
|
-
src: joinURL(masterSite.appUrl, '/.well-known/service/share/shared-bridge.html')
|
72
|
-
}) : null]
|
73
|
-
});
|
74
|
-
}
|