@arcblock/ux 2.13.28 → 2.13.30
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/RelativeTime/index.d.ts +2 -1
- package/lib/RelativeTime/index.js +30 -21
- 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/RelativeTime/index.tsx +32 -16
- 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
@@ -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 {};
|
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
|
-
}
|
@@ -1,191 +0,0 @@
|
|
1
|
-
import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import { Box, Typography, Chip, List, ListItem } from '@mui/material';
|
3
|
-
import { Icon } from '@iconify/react';
|
4
|
-
import externalLinkIcon from '@iconify-icons/tabler/external-link';
|
5
|
-
import lockOutlineIcon from '@iconify-icons/material-symbols/lock-outline';
|
6
|
-
import checkCircleIcon from '@iconify-icons/material-symbols/check-circle';
|
7
|
-
import rocketLaunchRoundedIcon from '@iconify-icons/material-symbols/rocket-launch-rounded';
|
8
|
-
import { useMemoizedFn } from 'ahooks';
|
9
|
-
import { translate } from '../Locale/util';
|
10
|
-
const translations = {
|
11
|
-
en: {
|
12
|
-
allow: 'Allow',
|
13
|
-
dataUsage: 'Your data is only used for identity authentication, and will not be collected or used for any other purpose.',
|
14
|
-
title: 'Cross-site authorization request',
|
15
|
-
clickAllow: ({
|
16
|
-
allowButton
|
17
|
-
}) => {
|
18
|
-
return /*#__PURE__*/_jsxs(_Fragment, {
|
19
|
-
children: ["You only need to click the ", allowButton, " button above, and you will not see this request again."]
|
20
|
-
});
|
21
|
-
},
|
22
|
-
reason: ({
|
23
|
-
site
|
24
|
-
}) => {
|
25
|
-
return /*#__PURE__*/_jsxs(_Fragment, {
|
26
|
-
children: ["For a better login experience, we need to apply for the storage permission of the ", site, " site."]
|
27
|
-
});
|
28
|
-
},
|
29
|
-
afterAllow: {
|
30
|
-
title: 'After authorization, you will enjoy:',
|
31
|
-
list1: 'More convenient login experience',
|
32
|
-
list2: 'Faster access speed'
|
33
|
-
}
|
34
|
-
},
|
35
|
-
zh: {
|
36
|
-
allow: '允许',
|
37
|
-
dataUsage: '您的数据仅用于身份认证,不会被收集或用于其他用途。',
|
38
|
-
title: '跨站授权请求',
|
39
|
-
clickAllow: ({
|
40
|
-
allowButton
|
41
|
-
}) => {
|
42
|
-
return /*#__PURE__*/_jsxs(_Fragment, {
|
43
|
-
children: ["\u60A8\u53EA\u9700\u8981\u70B9\u51FB\u5C4F\u5E55\u4E0A\u65B9\u7684 ", allowButton, " \u6309\u94AE\uFF0C\u540E\u7EED\u5C06\u4E0D\u4F1A\u518D\u770B\u5230\u8FD9\u4E2A\u8BF7\u6C42\u3002"]
|
44
|
-
});
|
45
|
-
},
|
46
|
-
reason: ({
|
47
|
-
site
|
48
|
-
}) => {
|
49
|
-
return /*#__PURE__*/_jsxs(_Fragment, {
|
50
|
-
children: ["\u4E3A\u4E86\u8BA9\u60A8\u83B7\u5F97\u66F4\u597D\u7684\u767B\u5F55\u4F53\u9A8C\uFF0C\u6211\u4EEC\u9700\u8981\u7533\u8BF7 ", site, " \u7AD9\u70B9\u5B58\u50A8\u6743\u9650\u3002"]
|
51
|
-
});
|
52
|
-
},
|
53
|
-
afterAllow: {
|
54
|
-
title: '授权后,您将享受:',
|
55
|
-
list1: '更便捷的登录体验',
|
56
|
-
list2: '更快的访问速度'
|
57
|
-
}
|
58
|
-
}
|
59
|
-
};
|
60
|
-
export default function NeedStorageAccessApiDialog({
|
61
|
-
locale = 'en',
|
62
|
-
origin,
|
63
|
-
host
|
64
|
-
}) {
|
65
|
-
const t = useMemoizedFn((key, data = {}) => {
|
66
|
-
return translate(translations, key, locale, 'en', data);
|
67
|
-
});
|
68
|
-
return /*#__PURE__*/_jsxs(Box, {
|
69
|
-
sx: {
|
70
|
-
backgroundColor: 'background.default',
|
71
|
-
display: 'flex',
|
72
|
-
flexDirection: 'column',
|
73
|
-
height: '100%',
|
74
|
-
position: 'relative',
|
75
|
-
maxWidth: '100%',
|
76
|
-
transition: 'width 0.2s ease-in-out',
|
77
|
-
margin: 'auto',
|
78
|
-
p: 3,
|
79
|
-
gap: 2
|
80
|
-
},
|
81
|
-
children: [/*#__PURE__*/_jsxs(Typography, {
|
82
|
-
component: "h1",
|
83
|
-
variant: "h4",
|
84
|
-
sx: {
|
85
|
-
fontWeight: 700,
|
86
|
-
fontFamily: 'Lexend',
|
87
|
-
display: 'flex',
|
88
|
-
alignItems: 'center',
|
89
|
-
gap: 1
|
90
|
-
},
|
91
|
-
children: [/*#__PURE__*/_jsx(Box, {
|
92
|
-
component: Icon,
|
93
|
-
icon: lockOutlineIcon,
|
94
|
-
fontSize: 28,
|
95
|
-
sx: {
|
96
|
-
color: 'warning.main'
|
97
|
-
}
|
98
|
-
}), t('title')]
|
99
|
-
}), /*#__PURE__*/_jsxs(Box, {
|
100
|
-
sx: {
|
101
|
-
display: 'flex',
|
102
|
-
flexDirection: 'column',
|
103
|
-
gap: 1
|
104
|
-
},
|
105
|
-
children: [/*#__PURE__*/_jsx(Typography, {
|
106
|
-
children: t('reason', {
|
107
|
-
site: /*#__PURE__*/_jsx(Chip, {
|
108
|
-
clickable: true,
|
109
|
-
component: "a",
|
110
|
-
href: origin,
|
111
|
-
label: host,
|
112
|
-
size: "small",
|
113
|
-
deleteIcon: /*#__PURE__*/_jsx(Icon, {
|
114
|
-
icon: externalLinkIcon
|
115
|
-
}),
|
116
|
-
onDelete: () => {},
|
117
|
-
target: "_blank"
|
118
|
-
})
|
119
|
-
})
|
120
|
-
}), /*#__PURE__*/_jsx(Typography, {
|
121
|
-
children: t('clickAllow', {
|
122
|
-
allowButton: /*#__PURE__*/_jsx(Chip, {
|
123
|
-
label: t('allow'),
|
124
|
-
size: "small",
|
125
|
-
color: "success"
|
126
|
-
})
|
127
|
-
})
|
128
|
-
}), /*#__PURE__*/_jsxs(Box, {
|
129
|
-
sx: {
|
130
|
-
mt: 2
|
131
|
-
},
|
132
|
-
children: [/*#__PURE__*/_jsxs(Typography, {
|
133
|
-
sx: {
|
134
|
-
display: 'flex',
|
135
|
-
alignItems: 'center',
|
136
|
-
gap: 1,
|
137
|
-
mb: 0.5
|
138
|
-
},
|
139
|
-
children: [/*#__PURE__*/_jsx(Box, {
|
140
|
-
component: Icon,
|
141
|
-
icon: checkCircleIcon,
|
142
|
-
fontSize: 24,
|
143
|
-
sx: {
|
144
|
-
color: 'success.main'
|
145
|
-
}
|
146
|
-
}), t('afterAllow.title')]
|
147
|
-
}), /*#__PURE__*/_jsxs(List, {
|
148
|
-
dense: true,
|
149
|
-
sx: {
|
150
|
-
py: 0,
|
151
|
-
pl: 2
|
152
|
-
},
|
153
|
-
children: [/*#__PURE__*/_jsxs(ListItem, {
|
154
|
-
sx: {
|
155
|
-
display: 'flex',
|
156
|
-
alignItems: 'center',
|
157
|
-
gap: 0.8
|
158
|
-
},
|
159
|
-
children: [/*#__PURE__*/_jsx(Box, {
|
160
|
-
component: Icon,
|
161
|
-
icon: rocketLaunchRoundedIcon,
|
162
|
-
fontSize: 20,
|
163
|
-
sx: {
|
164
|
-
color: 'success.main'
|
165
|
-
}
|
166
|
-
}), t('afterAllow.list1')]
|
167
|
-
}), /*#__PURE__*/_jsxs(ListItem, {
|
168
|
-
sx: {
|
169
|
-
display: 'flex',
|
170
|
-
alignItems: 'center',
|
171
|
-
gap: 0.8
|
172
|
-
},
|
173
|
-
children: [/*#__PURE__*/_jsx(Box, {
|
174
|
-
component: Icon,
|
175
|
-
icon: rocketLaunchRoundedIcon,
|
176
|
-
fontSize: 20,
|
177
|
-
sx: {
|
178
|
-
color: 'success.main'
|
179
|
-
}
|
180
|
-
}), t('afterAllow.list2')]
|
181
|
-
})]
|
182
|
-
})]
|
183
|
-
}), /*#__PURE__*/_jsx(Typography, {
|
184
|
-
component: "div",
|
185
|
-
variant: "body2",
|
186
|
-
color: "grey.700",
|
187
|
-
children: t('dataUsage')
|
188
|
-
})]
|
189
|
-
})]
|
190
|
-
});
|
191
|
-
}
|
@@ -1,73 +0,0 @@
|
|
1
|
-
import { Box } from '@mui/material';
|
2
|
-
import { joinURL } from 'ufo';
|
3
|
-
import { useRef, useState } from 'react';
|
4
|
-
import { useMemoizedFn } from 'ahooks';
|
5
|
-
import { useBrowser } from '@arcblock/react-hooks';
|
6
|
-
|
7
|
-
import SharedBridge from '../SharedBridge';
|
8
|
-
import { setVisitorId } from '../Util';
|
9
|
-
import { getFederatedEnabled, getMaster } from '../Util/federated';
|
10
|
-
import { callIframe } from '../Util/iframe';
|
11
|
-
import { Locale } from '../type';
|
12
|
-
|
13
|
-
type LoginButtonProps = {
|
14
|
-
onClick: (options?: { openMode?: 'popup' | 'window' }) => void;
|
15
|
-
render: (options: { onClick: () => void }) => React.ReactNode;
|
16
|
-
locale?: Locale;
|
17
|
-
};
|
18
|
-
|
19
|
-
export default function LoginButton({ onClick, render, locale }: LoginButtonProps) {
|
20
|
-
const blocklet = window?.blocklet;
|
21
|
-
const federatedEnabled = getFederatedEnabled(blocklet);
|
22
|
-
const masterSite = getMaster(blocklet);
|
23
|
-
const sharedBridgeRef = useRef<HTMLIFrameElement>(null);
|
24
|
-
const [hasStorageAccess, setHasStorageAccess] = useState(false);
|
25
|
-
const browser = useBrowser();
|
26
|
-
|
27
|
-
const handleClick = useMemoizedFn(() => {
|
28
|
-
if (hasStorageAccess) {
|
29
|
-
onClick({ openMode: 'popup' });
|
30
|
-
} else {
|
31
|
-
onClick();
|
32
|
-
}
|
33
|
-
});
|
34
|
-
const handleLoad = useMemoizedFn(async () => {
|
35
|
-
const { value: visitorId } = await callIframe(sharedBridgeRef.current as HTMLIFrameElement, 'getVisitorId');
|
36
|
-
if (visitorId) {
|
37
|
-
setHasStorageAccess(true);
|
38
|
-
setVisitorId(visitorId);
|
39
|
-
}
|
40
|
-
});
|
41
|
-
const handleClickBridge = useMemoizedFn(({ value, visitorId }) => {
|
42
|
-
if (visitorId) {
|
43
|
-
setVisitorId(visitorId);
|
44
|
-
}
|
45
|
-
if (value) {
|
46
|
-
onClick({ openMode: 'popup' });
|
47
|
-
} else {
|
48
|
-
onClick();
|
49
|
-
}
|
50
|
-
});
|
51
|
-
|
52
|
-
if (browser.arcSphere || browser.wallet) {
|
53
|
-
return render({ onClick });
|
54
|
-
}
|
55
|
-
|
56
|
-
return (
|
57
|
-
<Box
|
58
|
-
sx={{
|
59
|
-
position: 'relative',
|
60
|
-
}}>
|
61
|
-
{render({ onClick: handleClick })}
|
62
|
-
{masterSite?.appUrl && federatedEnabled ? (
|
63
|
-
<SharedBridge
|
64
|
-
locale={locale}
|
65
|
-
iframeRef={sharedBridgeRef}
|
66
|
-
onLoad={handleLoad}
|
67
|
-
onClick={handleClickBridge}
|
68
|
-
src={joinURL(masterSite.appUrl, '/.well-known/service/share/shared-bridge.html')}
|
69
|
-
/>
|
70
|
-
) : null}
|
71
|
-
</Box>
|
72
|
-
);
|
73
|
-
}
|