@arcblock/ux 2.13.28 → 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/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/SessionUser/components/un-login.js +29 -37
- package/lib/SharedBridge/index.d.ts +5 -6
- package/lib/SharedBridge/index.js +34 -48
- 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/SessionUser/components/un-login.tsx +21 -29
- package/src/SharedBridge/index.tsx +91 -97
- 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
@@ -37,6 +37,7 @@ export default function DIDConnectContainer({
|
|
37
37
|
appPid,
|
38
38
|
slotProps,
|
39
39
|
onClose = noop,
|
40
|
+
keepMounted = false,
|
40
41
|
}: {
|
41
42
|
// 是否弹出显示, true 表示在 Dialog 中渲染, 并可以通过 open/onClose 控制 dialog 的显示/隐藏, false 表示直接渲染原内容
|
42
43
|
popup?: boolean;
|
@@ -59,6 +60,7 @@ export default function DIDConnectContainer({
|
|
59
60
|
sx?: SxProps;
|
60
61
|
};
|
61
62
|
};
|
63
|
+
keepMounted?: boolean;
|
62
64
|
}) {
|
63
65
|
const color = useCreation(() => {
|
64
66
|
const did = appPid || window.blocklet.appPid;
|
@@ -96,7 +98,7 @@ export default function DIDConnectContainer({
|
|
96
98
|
onClose();
|
97
99
|
};
|
98
100
|
|
99
|
-
const showModal = debouncedOpen || open;
|
101
|
+
const showModal = debouncedOpen || open || keepMounted;
|
100
102
|
|
101
103
|
const DrawerComponent = hideCloseButton ? Drawer : SwipeableDrawer;
|
102
104
|
|
@@ -286,6 +288,7 @@ export default function DIDConnectContainer({
|
|
286
288
|
slots={{
|
287
289
|
backdrop: BackdropWrap,
|
288
290
|
}}
|
291
|
+
keepMounted={keepMounted}
|
289
292
|
className="did-connect__container-dialog"
|
290
293
|
onClose={handleOnClose}
|
291
294
|
PaperProps={{
|
package/src/DIDConnect/index.ts
CHANGED
@@ -6,3 +6,4 @@ export { default as withContainer } from './with-container';
|
|
6
6
|
export { default as withUxTheme } from './with-ux-theme';
|
7
7
|
export { default as DIDConnectLogo } from './did-connect-logo';
|
8
8
|
export { default as DIDConnectContainer } from './did-connect-container';
|
9
|
+
export { default as RequestStorageAccessApiDialog } from './request-storage-access-api-dialog';
|
@@ -0,0 +1,280 @@
|
|
1
|
+
import { Box, Button, Typography, Chip, List, ListItem } from '@mui/material';
|
2
|
+
import { Icon } from '@iconify/react';
|
3
|
+
import externalLinkIcon from '@iconify-icons/tabler/external-link';
|
4
|
+
import lockOutlineIcon from '@iconify-icons/material-symbols/lock-outline';
|
5
|
+
import checkCircleIcon from '@iconify-icons/material-symbols/check-circle';
|
6
|
+
import rocketLaunchRoundedIcon from '@iconify-icons/material-symbols/rocket-launch-rounded';
|
7
|
+
import { useMemoizedFn, useReactive } from 'ahooks';
|
8
|
+
import { forwardRef, memo, useImperativeHandle, useRef } from 'react';
|
9
|
+
import noop from 'lodash/noop';
|
10
|
+
|
11
|
+
import { Locale } from '../type';
|
12
|
+
import { translate } from '../Locale/util';
|
13
|
+
import DIDConnectContainer from './did-connect-container';
|
14
|
+
import CloseButton from '../CloseButton';
|
15
|
+
import SharedBridge from '../SharedBridge';
|
16
|
+
import { setVisitorId } from '../Util';
|
17
|
+
|
18
|
+
type StorageAccessState = 'prompt' | 'granted' | 'denied';
|
19
|
+
|
20
|
+
const translations: Record<
|
21
|
+
Locale,
|
22
|
+
{
|
23
|
+
allow: string;
|
24
|
+
dataUsage: string;
|
25
|
+
title: string;
|
26
|
+
clickAllow: ({ allowButton }: { allowButton: React.ReactNode }) => React.ReactNode;
|
27
|
+
reason: ({ site }: { site: React.ReactNode }) => React.ReactNode;
|
28
|
+
afterAllow: {
|
29
|
+
title: string;
|
30
|
+
list1: string;
|
31
|
+
list2: string;
|
32
|
+
};
|
33
|
+
}
|
34
|
+
> = {
|
35
|
+
en: {
|
36
|
+
allow: 'Allow',
|
37
|
+
dataUsage:
|
38
|
+
'Your data is only used for identity authentication, and will not be collected or used for any other purpose.',
|
39
|
+
title: 'Authorization Request',
|
40
|
+
clickAllow: ({ allowButton }: { allowButton: React.ReactNode }) => {
|
41
|
+
return <>You only need to click the {allowButton} button below, and you will not see this request again.</>;
|
42
|
+
},
|
43
|
+
reason: ({ site }) => {
|
44
|
+
return <>For a better login experience, we need to apply for the storage permission of the {site} site.</>;
|
45
|
+
},
|
46
|
+
afterAllow: {
|
47
|
+
title: 'After authorization, you will enjoy:',
|
48
|
+
list1: 'More convenient login experience',
|
49
|
+
list2: 'Faster access speed',
|
50
|
+
},
|
51
|
+
},
|
52
|
+
zh: {
|
53
|
+
allow: '允许',
|
54
|
+
dataUsage: '您的数据仅用于身份认证,不会被收集或用于其他用途。',
|
55
|
+
title: '授权请求',
|
56
|
+
clickAllow: ({ allowButton }) => {
|
57
|
+
return <>您只需要点击下方的 {allowButton} 按钮,后续将不会再看到这个请求。</>;
|
58
|
+
},
|
59
|
+
reason: ({ site }) => {
|
60
|
+
return <>为了让您获得更好的登录体验,我们需要申请 {site} 站点存储权限。</>;
|
61
|
+
},
|
62
|
+
afterAllow: {
|
63
|
+
title: '授权后,您将享受:',
|
64
|
+
list1: '更便捷的登录体验',
|
65
|
+
list2: '更快的访问速度',
|
66
|
+
},
|
67
|
+
},
|
68
|
+
};
|
69
|
+
|
70
|
+
const RequestStorageAccessApiDialog = forwardRef(
|
71
|
+
(
|
72
|
+
{
|
73
|
+
locale = 'en',
|
74
|
+
src,
|
75
|
+
storageAccessState,
|
76
|
+
onHandle = noop,
|
77
|
+
}: {
|
78
|
+
locale?: Locale;
|
79
|
+
src: string;
|
80
|
+
storageAccessState: StorageAccessState;
|
81
|
+
onHandle: (data: { value: boolean; error?: Error }) => void;
|
82
|
+
},
|
83
|
+
ref
|
84
|
+
) => {
|
85
|
+
const sharedBridgeRef = useRef<{ callIframe: (method: string) => Promise<any> }>(null);
|
86
|
+
const currentState = useReactive({
|
87
|
+
callback: noop,
|
88
|
+
open: false,
|
89
|
+
get origin() {
|
90
|
+
try {
|
91
|
+
return new URL(src).origin;
|
92
|
+
} catch (error) {
|
93
|
+
return src;
|
94
|
+
}
|
95
|
+
},
|
96
|
+
get host() {
|
97
|
+
try {
|
98
|
+
return new URL(src).host;
|
99
|
+
} catch (error) {
|
100
|
+
return src;
|
101
|
+
}
|
102
|
+
},
|
103
|
+
});
|
104
|
+
const t = useMemoizedFn((key, data = {}) => {
|
105
|
+
return translate(translations, key, locale, 'en', data);
|
106
|
+
});
|
107
|
+
|
108
|
+
const reset = useMemoizedFn(() => {
|
109
|
+
currentState.open = false;
|
110
|
+
currentState.callback = noop;
|
111
|
+
});
|
112
|
+
|
113
|
+
const open = useMemoizedFn(() => {
|
114
|
+
currentState.open = true;
|
115
|
+
});
|
116
|
+
const close = useMemoizedFn(() => {
|
117
|
+
currentState.open = false;
|
118
|
+
});
|
119
|
+
|
120
|
+
const _requestStorageAccess = useMemoizedFn(
|
121
|
+
async (callback: (result: boolean, origin?: 'broswer' | 'system') => void) => {
|
122
|
+
const result = await sharedBridgeRef.current?.callIframe('requestStorageAccess');
|
123
|
+
if (result.value) {
|
124
|
+
callback(true, 'broswer');
|
125
|
+
} else if (storageAccessState === undefined) {
|
126
|
+
// 用户未在当前网页交互过,此时必然需要进行一次弹窗
|
127
|
+
callback(false, 'system');
|
128
|
+
} else if (storageAccessState === 'denied') {
|
129
|
+
// 用户已经明确拒绝过跨站授权,直接弹窗
|
130
|
+
callback(false);
|
131
|
+
} else {
|
132
|
+
// NOTICE: 暂时保留这部分逻辑,后续可能会用上
|
133
|
+
// else if (
|
134
|
+
// result.error?.name === 'NotAllowedError' &&
|
135
|
+
// result.error?.message === 'requestStorageAccess not allowed'
|
136
|
+
// ) {
|
137
|
+
// // 操作被浏览器禁止,需要用户手动与 iframe 交互一次才可以
|
138
|
+
// currentState.open = true;
|
139
|
+
// currentState.callback = callback;
|
140
|
+
// }
|
141
|
+
currentState.open = true;
|
142
|
+
currentState.callback = callback;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
);
|
146
|
+
const requestStorageAccess = useMemoizedFn(() => {
|
147
|
+
return new Promise((resolve) => {
|
148
|
+
_requestStorageAccess((result, origin) => {
|
149
|
+
reset();
|
150
|
+
resolve({ value: result, origin });
|
151
|
+
});
|
152
|
+
});
|
153
|
+
});
|
154
|
+
|
155
|
+
const handleAllow = useMemoizedFn(() => {
|
156
|
+
currentState.open = false;
|
157
|
+
});
|
158
|
+
const handleClose = useMemoizedFn(() => {
|
159
|
+
currentState.open = false;
|
160
|
+
currentState.callback(false, 'system');
|
161
|
+
});
|
162
|
+
|
163
|
+
useImperativeHandle(ref, () => ({
|
164
|
+
open,
|
165
|
+
close,
|
166
|
+
requestStorageAccess,
|
167
|
+
}));
|
168
|
+
|
169
|
+
return (
|
170
|
+
<DIDConnectContainer popup open={currentState.open} onClose={handleClose} keepMounted>
|
171
|
+
<Box
|
172
|
+
sx={{
|
173
|
+
backgroundColor: 'background.default',
|
174
|
+
display: 'flex',
|
175
|
+
flexDirection: 'column',
|
176
|
+
height: '100%',
|
177
|
+
position: 'relative',
|
178
|
+
maxWidth: '100%',
|
179
|
+
transition: 'width 0.2s ease-in-out',
|
180
|
+
margin: 'auto',
|
181
|
+
p: 3,
|
182
|
+
gap: 2,
|
183
|
+
}}>
|
184
|
+
<CloseButton
|
185
|
+
onClose={handleClose}
|
186
|
+
sx={{
|
187
|
+
position: 'absolute',
|
188
|
+
right: 14,
|
189
|
+
top: 14,
|
190
|
+
}}
|
191
|
+
/>
|
192
|
+
<Typography
|
193
|
+
component="div"
|
194
|
+
variant="h4"
|
195
|
+
sx={{
|
196
|
+
fontWeight: 700,
|
197
|
+
fontFamily: 'Lexend',
|
198
|
+
display: 'flex',
|
199
|
+
alignItems: 'center',
|
200
|
+
gap: 1,
|
201
|
+
}}>
|
202
|
+
<Box component={Icon} icon={lockOutlineIcon} fontSize={28} sx={{ color: 'warning.main' }} />
|
203
|
+
{t('title')}
|
204
|
+
</Typography>
|
205
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
206
|
+
{/* 不需要随意更改以下内容的格式化,否则会影响到 UI 的展示 */}
|
207
|
+
<Typography>
|
208
|
+
{t('reason', {
|
209
|
+
site: (
|
210
|
+
<Chip
|
211
|
+
clickable
|
212
|
+
component="a"
|
213
|
+
href={currentState.origin}
|
214
|
+
label={currentState.host}
|
215
|
+
size="small"
|
216
|
+
deleteIcon={<Icon icon={externalLinkIcon} />}
|
217
|
+
onDelete={() => {}}
|
218
|
+
target="_blank"
|
219
|
+
/>
|
220
|
+
),
|
221
|
+
})}
|
222
|
+
</Typography>
|
223
|
+
<Typography component="div">
|
224
|
+
{t('clickAllow', {
|
225
|
+
allowButton: <Chip label={t('allow')} size="small" color="success" />,
|
226
|
+
})}
|
227
|
+
</Typography>
|
228
|
+
<Box sx={{ mt: 2 }}>
|
229
|
+
<Typography sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>
|
230
|
+
<Box component={Icon} icon={checkCircleIcon} fontSize={24} sx={{ color: 'success.main' }} />
|
231
|
+
{t('afterAllow.title')}
|
232
|
+
</Typography>
|
233
|
+
<List dense sx={{ py: 0, pl: 2 }}>
|
234
|
+
<ListItem sx={{ display: 'flex', alignItems: 'center', gap: 0.8 }}>
|
235
|
+
<Box component={Icon} icon={rocketLaunchRoundedIcon} fontSize={20} sx={{ color: 'success.main' }} />
|
236
|
+
{t('afterAllow.list1')}
|
237
|
+
</ListItem>
|
238
|
+
<ListItem sx={{ display: 'flex', alignItems: 'center', gap: 0.8 }}>
|
239
|
+
<Box component={Icon} icon={rocketLaunchRoundedIcon} fontSize={20} sx={{ color: 'success.main' }} />
|
240
|
+
{t('afterAllow.list2')}
|
241
|
+
</ListItem>
|
242
|
+
</List>
|
243
|
+
</Box>
|
244
|
+
|
245
|
+
<Typography component="div" variant="body2" color="grey.700">
|
246
|
+
{t('dataUsage')}
|
247
|
+
</Typography>
|
248
|
+
</Box>
|
249
|
+
|
250
|
+
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
|
251
|
+
<Box sx={{ position: 'relative', display: 'inline-block', cursor: 'pointer' }}>
|
252
|
+
<Button
|
253
|
+
variant="contained"
|
254
|
+
color="success"
|
255
|
+
onClick={handleAllow}
|
256
|
+
sx={{ minWidth: 100, letterSpacing: 1 }}>
|
257
|
+
{t('allow')}
|
258
|
+
</Button>
|
259
|
+
<SharedBridge
|
260
|
+
ref={sharedBridgeRef}
|
261
|
+
onClick={({ value, visitorId }) => {
|
262
|
+
if (visitorId) setVisitorId(visitorId);
|
263
|
+
|
264
|
+
currentState.callback(value, 'broswer');
|
265
|
+
}}
|
266
|
+
locale={locale}
|
267
|
+
src={src}
|
268
|
+
sx={{
|
269
|
+
zIndex: 1,
|
270
|
+
}}
|
271
|
+
/>
|
272
|
+
</Box>
|
273
|
+
</Box>
|
274
|
+
</Box>
|
275
|
+
</DIDConnectContainer>
|
276
|
+
);
|
277
|
+
}
|
278
|
+
);
|
279
|
+
|
280
|
+
export default memo(RequestStorageAccessApiDialog);
|
@@ -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);
|
@@ -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 {};
|