@arcblock/ux 2.13.13 → 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.
Files changed (55) hide show
  1. package/lib/Address/responsive-did-address.js +3 -1
  2. package/lib/DIDConnect/app-icon.d.ts +8 -0
  3. package/lib/DIDConnect/app-icon.js +31 -0
  4. package/lib/DIDConnect/app-info-item.d.ts +7 -0
  5. package/lib/DIDConnect/app-info-item.js +73 -0
  6. package/lib/DIDConnect/did-connect-footer.d.ts +4 -0
  7. package/lib/DIDConnect/did-connect-footer.js +54 -0
  8. package/lib/DIDConnect/did-connect-logo.d.ts +1 -0
  9. package/lib/DIDConnect/did-connect-logo.js +11 -0
  10. package/lib/DIDConnect/index.d.ts +7 -0
  11. package/lib/DIDConnect/index.js +7 -0
  12. package/lib/DIDConnect/powered-by.d.ts +3 -0
  13. package/lib/DIDConnect/powered-by.js +46 -0
  14. package/lib/DIDConnect/with-container.d.ts +11 -0
  15. package/lib/DIDConnect/with-container.js +273 -0
  16. package/lib/DIDConnect/with-ux-theme.d.ts +1 -0
  17. package/lib/DIDConnect/with-ux-theme.js +23 -0
  18. package/lib/Dialog/confirm.d.ts +6 -1
  19. package/lib/Dialog/confirm.js +7 -3
  20. package/lib/Dialog/use-confirm.js +6 -0
  21. package/lib/Locale/util.d.ts +3 -3
  22. package/lib/Locale/util.js +6 -1
  23. package/lib/LoginButton/index.d.ts +12 -0
  24. package/lib/LoginButton/index.js +74 -0
  25. package/lib/SessionUser/components/un-login.js +42 -31
  26. package/lib/SharedBridge/index.d.ts +16 -0
  27. package/lib/SharedBridge/index.js +109 -0
  28. package/lib/SharedBridge/need-storage-access-api-dialog.d.ts +7 -0
  29. package/lib/SharedBridge/need-storage-access-api-dialog.js +212 -0
  30. package/lib/Theme/index.d.ts +2 -2
  31. package/lib/Theme/index.js +1 -1
  32. package/lib/Util/iframe.d.ts +5 -0
  33. package/lib/Util/iframe.js +24 -0
  34. package/lib/Util/index.d.ts +10 -1
  35. package/lib/Util/index.js +67 -4
  36. package/package.json +7 -6
  37. package/src/Address/responsive-did-address.tsx +11 -1
  38. package/src/DIDConnect/app-icon.tsx +36 -0
  39. package/src/DIDConnect/app-info-item.tsx +82 -0
  40. package/src/DIDConnect/did-connect-footer.tsx +51 -0
  41. package/src/DIDConnect/did-connect-logo.tsx +8 -0
  42. package/src/DIDConnect/index.ts +7 -0
  43. package/src/DIDConnect/powered-by.tsx +48 -0
  44. package/src/DIDConnect/with-container.tsx +307 -0
  45. package/src/DIDConnect/with-ux-theme.tsx +22 -0
  46. package/src/Dialog/confirm.jsx +31 -23
  47. package/src/Dialog/use-confirm.jsx +6 -0
  48. package/src/Locale/util.ts +7 -2
  49. package/src/LoginButton/index.tsx +73 -0
  50. package/src/SessionUser/components/un-login.tsx +34 -27
  51. package/src/SharedBridge/index.tsx +123 -0
  52. package/src/SharedBridge/need-storage-access-api-dialog.tsx +171 -0
  53. package/src/Theme/index.ts +2 -2
  54. package/src/Util/iframe.ts +19 -0
  55. package/src/Util/index.ts +77 -4
@@ -0,0 +1,307 @@
1
+ import { forwardRef, memo, useRef, useState } from 'react';
2
+ import { Dialog, DialogContent, useMediaQuery, Box, Backdrop, SwipeableDrawer, Drawer } from '@mui/material';
3
+ import { useDebounce, useMemoizedFn } from 'ahooks';
4
+ import { useBrowser } from '@arcblock/react-hooks';
5
+ import colorConvert from 'color-convert';
6
+
7
+ import { useTheme } from '../Theme';
8
+ import { mergeSx } from '../Util/style';
9
+ import { hexToRgba } from '../Util';
10
+ import { Locale } from '../type';
11
+
12
+ const BackdropWrap = memo(
13
+ forwardRef((backdropProps, ref) => {
14
+ return (
15
+ <Backdrop
16
+ open
17
+ ref={ref}
18
+ style={{
19
+ backgroundColor: 'rgba(0, 0, 0, 0.6)',
20
+ backdropFilter: 'blur(3px)',
21
+ touchAction: 'none',
22
+ }}
23
+ {...backdropProps}
24
+ key="background"
25
+ />
26
+ );
27
+ })
28
+ );
29
+
30
+ export default function withContainer(Component: React.ComponentType<any>) {
31
+ function WithContainerComponent({
32
+ popup = false,
33
+ open = false,
34
+ hideCloseButton = false,
35
+ ...rest
36
+ }: {
37
+ // 是否弹出显示, true 表示在 Dialog 中渲染, 并可以通过 open/onClose 控制 dialog 的显示/隐藏, false 表示直接渲染原内容
38
+ popup?: boolean;
39
+ open?: boolean;
40
+ hideCloseButton?: boolean;
41
+ onClose: () => void;
42
+ blocklet?: any;
43
+ origin?: string;
44
+ host?: string;
45
+ locale?: Locale;
46
+ }) {
47
+ const [color, setColor] = useState('#fff');
48
+
49
+ const drawerDragger = useRef(null);
50
+ const browser = useBrowser();
51
+ // 屏宽小于 sm 且在 mobile 设备中全屏显示 dialog (PC 端屏宽小于 sm 的情况正常弹窗, 不全屏显示)
52
+ const matchSm = useMediaQuery('(max-width:640px)');
53
+ let openVariant = 'page';
54
+ if (popup) {
55
+ openVariant = 'dialog';
56
+ if (matchSm && browser.mobile.any) {
57
+ openVariant = 'drawer';
58
+ }
59
+ }
60
+
61
+ const theme = useTheme();
62
+
63
+ // 兼容 did-react 版本中存在的 responsive prop, responsive=true 则让 dialog 始终保持 open 状态, 否则遵循外部传入的 open prop
64
+ const isOpen = open;
65
+
66
+ const leavingScreenDelay = theme?.transitions?.duration?.leavingScreen || 500; // 默认值是 195
67
+ const debouncedShow = useDebounce(isOpen, {
68
+ wait: leavingScreenDelay,
69
+ });
70
+
71
+ const removeMagicToken = useMemoizedFn(() => {
72
+ const searchParams = new URLSearchParams(window.location.search);
73
+ if (searchParams.get('magicToken')) {
74
+ searchParams.delete('magicToken');
75
+ }
76
+ window.history.replaceState({}, '', `${window.location.pathname}?${searchParams.toString()}`);
77
+ });
78
+
79
+ // eslint-disable-next-line no-unused-vars
80
+ const handleOnClose = (e: React.MouseEvent<HTMLElement>, reason: string) => {
81
+ if (['backdropClick', 'escapeKeyDown'].includes(reason)) return;
82
+ removeMagicToken();
83
+ rest?.onClose();
84
+ };
85
+
86
+ const showModal = debouncedShow || isOpen;
87
+
88
+ const DrawerComponent = hideCloseButton ? Drawer : SwipeableDrawer;
89
+
90
+ const hslColor = colorConvert.hex.hsl(color);
91
+
92
+ const [h, s, l] = hslColor;
93
+ const percentageList = [0, 30, 60, 30, 0, 30, 60, 30];
94
+ const maxPercentage = Math.max(...percentageList);
95
+ const minPercentage = Math.min(...percentageList);
96
+ let useAlpha = false;
97
+ if ((l * (100 + maxPercentage)) / 100 > 100 || (l * (100 + minPercentage)) / 100 < 0) {
98
+ // 超出范围,使用 alpha 通道变化
99
+ useAlpha = true;
100
+ }
101
+ const colorList = percentageList.map((percentageItem) => {
102
+ let finalL = (l * (100 + percentageItem)) / 100;
103
+ let finalAlpha = 0.6;
104
+ if (useAlpha) {
105
+ finalAlpha = (0.5 * (100 + percentageItem)) / 100;
106
+ } else {
107
+ finalL = (l * (100 + percentageItem)) / 100;
108
+ }
109
+ return `hsla(${h}, ${s}%, ${finalL}%, ${finalAlpha})`;
110
+ });
111
+ const background = `linear-gradient(45deg, ${colorList.join(', ')})`;
112
+ const colorListGlow = percentageList.map((percentageItem) => {
113
+ let finalL = (l * (100 + percentageItem)) / 100;
114
+ let finalAlpha = 0.2;
115
+ if (useAlpha) {
116
+ finalAlpha = (0.3 * (100 + percentageItem)) / 100;
117
+ } else {
118
+ finalL = (l * (100 + percentageItem)) / 100;
119
+ }
120
+ return `hsla(${h}, ${s}%, ${finalL}%, ${finalAlpha})`;
121
+ });
122
+
123
+ const backgroundGlow = `linear-gradient(45deg, ${colorListGlow.join(', ')})`;
124
+
125
+ const glowStyle = {
126
+ overflow: 'visible',
127
+ '&::before, &::after': {
128
+ content: '""',
129
+ position: 'absolute',
130
+ top: '-3px',
131
+ right: '-3px',
132
+ bottom: '-3px',
133
+ left: '-3px',
134
+ background,
135
+ backgroundSize: '300% 300%',
136
+ backgroundRepeat: 'no-repeat',
137
+ animation: 'glowRotate 10s linear infinite',
138
+ borderRadius: '14px !important',
139
+ zIndex: 0,
140
+ },
141
+ '&::after': {
142
+ background: backgroundGlow,
143
+ filter: 'blur(15px)',
144
+ },
145
+
146
+ '@keyframes glowRotate': {
147
+ '0%': {
148
+ backgroundPosition: '0 0',
149
+ },
150
+ '50%': {
151
+ backgroundPosition: '100% 0',
152
+ },
153
+ '100%': {
154
+ backgroundPosition: '0 0',
155
+ },
156
+ },
157
+ };
158
+
159
+ const wrapOnClose = useMemoizedFn(() => {
160
+ removeMagicToken();
161
+ rest?.onClose();
162
+ });
163
+
164
+ if (openVariant === 'page') {
165
+ return (
166
+ <Box
167
+ className="did-connect__container-page"
168
+ sx={mergeSx(glowStyle, {
169
+ borderRadius: 1,
170
+ position: 'relative',
171
+ zIndex: 1,
172
+ })}>
173
+ <Box
174
+ sx={{
175
+ border: `1px solid ${hexToRgba(color, 0.1)}`,
176
+ m: '-1px',
177
+ position: 'relative',
178
+ borderRadius: '12px',
179
+ zIndex: 2,
180
+ overflow: 'hidden',
181
+ }}>
182
+ <Component {...rest} onClose={wrapOnClose} setColor={setColor} hideCloseButton mode={openVariant} />
183
+ </Box>
184
+ </Box>
185
+ );
186
+ }
187
+
188
+ if (openVariant === 'drawer') {
189
+ return (
190
+ <DrawerComponent
191
+ className="did-connect__container-drawer"
192
+ disableSwipeToOpen
193
+ open={isOpen}
194
+ anchor="bottom"
195
+ drawerDragger={drawerDragger.current}
196
+ // @ts-ignore
197
+ onClose={handleOnClose}
198
+ slots={{
199
+ backdrop: BackdropWrap,
200
+ }}
201
+ PaperProps={{
202
+ sx: {
203
+ borderRadius: 3, // 保持跟 DID Wallet 一致
204
+ borderBottomLeftRadius: 0,
205
+ borderBottomRightRadius: 0,
206
+ p: '2px',
207
+ animation: 'glowBreathe 7s linear infinite',
208
+ '.did-connect__root': {
209
+ backgroundColor: 'transparent',
210
+ },
211
+ overflow: 'hidden',
212
+ '@keyframes glowBreathe': {
213
+ '0%, 100%': {
214
+ boxShadow: `
215
+ inset 0 0 7px ${hexToRgba(color, 0.3)},
216
+ inset 0 0 12px ${hexToRgba(color, 0.3)}`,
217
+ },
218
+ '50%': {
219
+ boxShadow: `
220
+ inset 0 0 18px ${hexToRgba(color, 0.7)},
221
+ inset 0 0 24px ${hexToRgba(color, 0.5)}`,
222
+ },
223
+ },
224
+ },
225
+ }}>
226
+ {hideCloseButton ? null : (
227
+ <Box
228
+ ref={drawerDragger}
229
+ sx={{
230
+ px: 1,
231
+ pt: 2,
232
+ m: 'auto',
233
+ mt: -1,
234
+ mb: -2,
235
+ zIndex: 2,
236
+ }}>
237
+ <Box
238
+ sx={{
239
+ width: '48px',
240
+ height: '4px',
241
+ borderRadius: '100vw',
242
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
243
+ }}
244
+ />
245
+ </Box>
246
+ )}
247
+ <Box
248
+ sx={{
249
+ touchAction: 'none',
250
+ maxWidth: '100%',
251
+ width: 500,
252
+ height: 'auto',
253
+ }}>
254
+ {/* HACK: 由于 MUI 文档中描述 使用 keepMounted: false 可能会造成问题,所以采用下面的方案进行 HACK */}
255
+ {/* https://mui.com/material-ui/react-drawer/#keep-mounted */}
256
+ {showModal ? (
257
+ <Component {...rest} onClose={wrapOnClose} setColor={setColor} hideCloseButton mode={openVariant} />
258
+ ) : null}
259
+ </Box>
260
+ </DrawerComponent>
261
+ );
262
+ }
263
+
264
+ return (
265
+ <Dialog
266
+ open={isOpen}
267
+ slots={{
268
+ backdrop: BackdropWrap,
269
+ }}
270
+ className="did-connect__container-dialog"
271
+ onClose={handleOnClose}
272
+ PaperProps={{
273
+ sx: {
274
+ // 避免样式被 server 中的定义覆盖
275
+ '&.MuiPaper-rounded': {
276
+ borderRadius: '12px !important',
277
+ },
278
+ position: 'relative',
279
+ ...glowStyle,
280
+ },
281
+ }}>
282
+ <DialogContent
283
+ sx={{
284
+ maxWidth: 'calc(100vw - 18px)',
285
+ maxHeight: 'calc(100vh - 18px)',
286
+ p: '0px !important',
287
+ height: 'auto',
288
+ backgroundColor: 'background.default',
289
+ borderRadius: '12px !important',
290
+ zIndex: 1,
291
+ }}>
292
+ {showModal ? (
293
+ <Component
294
+ {...rest}
295
+ onClose={wrapOnClose}
296
+ setColor={setColor}
297
+ hideCloseButton={hideCloseButton}
298
+ mode={openVariant}
299
+ />
300
+ ) : null}
301
+ </DialogContent>
302
+ </Dialog>
303
+ );
304
+ }
305
+
306
+ return WithContainerComponent;
307
+ }
@@ -0,0 +1,22 @@
1
+ import { createTheme, useTheme } from '@mui/material';
2
+ import { DID_CONNECT_THEME_LIGHT, DID_CONNECT_THEME_DARK } from '@blocklet/theme';
3
+ import { ThemeProvider } from '../Theme';
4
+
5
+ // DID Connect 使用自己的 Theme 配置,不受 Blocklet theme 影响
6
+ const themeLight = createTheme(DID_CONNECT_THEME_LIGHT);
7
+ const themeDark = createTheme(DID_CONNECT_THEME_DARK);
8
+
9
+ export default function withUxTheme(Component: React.ComponentType<any>) {
10
+ function WithUxThemeComponent(props: any) {
11
+ const { palette } = useTheme();
12
+ const theme = palette.mode === 'dark' ? themeDark : themeLight;
13
+
14
+ return (
15
+ <ThemeProvider theme={theme}>
16
+ <Component {...props} />
17
+ </ThemeProvider>
18
+ );
19
+ }
20
+
21
+ return WithUxThemeComponent;
22
+ }
@@ -15,6 +15,7 @@ import Dialog from './dialog';
15
15
  * children?: React.ReactNode,
16
16
  * showCancelButton?: true | false,
17
17
  * showCloseButton?: true | false,
18
+ * showConfirmButton?: true | false,
18
19
  * fullScreen?: false | true,
19
20
  * confirmButton?: {text: React.ReactNode, props?: ButtonProps}
20
21
  * cancelButton?: {text: React.ReactNode, props?: ButtonProps}
@@ -35,6 +36,7 @@ export default function Confirm({
35
36
  onCancel,
36
37
  showCloseButton,
37
38
  showCancelButton,
39
+ showConfirmButton,
38
40
  fullScreen,
39
41
  confirmButton,
40
42
  cancelButton,
@@ -81,29 +83,33 @@ export default function Confirm({
81
83
  },
82
84
  }}
83
85
  actions={
84
- <>
85
- {showCancelButton && (
86
- <Button
87
- onClick={(e) => {
88
- e.stopPropagation();
89
- onCancel(e, 'closeButton');
90
- }}
91
- color="primary"
92
- {...cancelButton.props}>
93
- {cancelButton.text}
94
- </Button>
95
- )}
96
- <Button
97
- onClick={(e) => {
98
- e.stopPropagation();
99
- onConfirm(e);
100
- }}
101
- color="primary"
102
- autoFocus
103
- {...confirmButton.props}>
104
- {confirmButton.text}
105
- </Button>
106
- </>
86
+ showCancelButton || showConfirmButton ? (
87
+ <>
88
+ {showCancelButton && (
89
+ <Button
90
+ onClick={(e) => {
91
+ e.stopPropagation();
92
+ onCancel(e, 'closeButton');
93
+ }}
94
+ color="primary"
95
+ {...cancelButton.props}>
96
+ {cancelButton.text}
97
+ </Button>
98
+ )}
99
+ {showConfirmButton && (
100
+ <Button
101
+ onClick={(e) => {
102
+ e.stopPropagation();
103
+ onConfirm(e);
104
+ }}
105
+ color="primary"
106
+ autoFocus
107
+ {...confirmButton.props}>
108
+ {confirmButton.text}
109
+ </Button>
110
+ )}
111
+ </>
112
+ ) : null
107
113
  }>
108
114
  {children}
109
115
  </Dialog>
@@ -117,6 +123,7 @@ Confirm.propTypes = {
117
123
  onCancel: PropTypes.func.isRequired,
118
124
  children: PropTypes.node,
119
125
  showCancelButton: PropTypes.bool,
126
+ showConfirmButton: PropTypes.bool,
120
127
  showCloseButton: PropTypes.bool,
121
128
  fullScreen: PropTypes.bool,
122
129
  // 可以传入 {text: ..., props: ...}
@@ -133,6 +140,7 @@ Confirm.propTypes = {
133
140
 
134
141
  Confirm.defaultProps = {
135
142
  showCancelButton: true,
143
+ showConfirmButton: true,
136
144
  showCloseButton: true,
137
145
  fullScreen: false,
138
146
  confirmButton: {
@@ -19,6 +19,7 @@ const ConfirmHolder = forwardRef((props, ref) => {
19
19
  loading: false,
20
20
  showCancelButton: true,
21
21
  showCloseButton: true,
22
+ showConfirmButton: true,
22
23
  confirmButtonText: 'Confirm',
23
24
  confirmButtonProps: {},
24
25
  cancelButtonText: 'Cancel',
@@ -43,6 +44,7 @@ const ConfirmHolder = forwardRef((props, ref) => {
43
44
  state.onCancel = params.onCancel || noop;
44
45
  state.showCloseButton = params.showCloseButton ?? true;
45
46
  state.showCancelButton = params.showCancelButton ?? true;
47
+ state.showConfirmButton = params.showConfirmButton ?? true;
46
48
  if (params.confirmButtonText) state.confirmButtonText = params.confirmButtonText;
47
49
  if (params.confirmButtonProps) state.confirmButtonProps = params.confirmButtonProps;
48
50
  if (params.cancelButtonText) state.cancelButtonText = params.cancelButtonText;
@@ -62,6 +64,9 @@ const ConfirmHolder = forwardRef((props, ref) => {
62
64
  state.confirmButtonProps = {};
63
65
  state.cancelButtonText = 'Cancel';
64
66
  state.cancelButtonProps = {};
67
+ state.showConfirmButton = true;
68
+ state.showCancelButton = true;
69
+ state.showCloseButton = true;
65
70
  });
66
71
  const close = useMemoizedFn(() => {
67
72
  state.show = false;
@@ -130,6 +135,7 @@ const ConfirmHolder = forwardRef((props, ref) => {
130
135
  }}
131
136
  showCloseButton={state.showCloseButton}
132
137
  showCancelButton={state.showCancelButton}
138
+ showConfirmButton={state.showConfirmButton}
133
139
  cancelButton={{
134
140
  text: state.cancelButtonText,
135
141
  props: {
@@ -2,8 +2,13 @@ import get from 'lodash/get';
2
2
  import type { Locale, Translations } from '../type';
3
3
 
4
4
  /* eslint-disable no-prototype-builtins */
5
- export const replace = (template: string, data: Record<string, any>) =>
6
- template.replace(/{(\w*)}/g, (m, key) => (data.hasOwnProperty(key) ? data[key] : ''));
5
+ export const replace = (template: string | Function, data: Record<string, any>) => {
6
+ if (typeof template === 'function') {
7
+ return template(data);
8
+ }
9
+
10
+ return template.replace(/{(\w*)}/g, (m, key) => (data.hasOwnProperty(key) ? data[key] : ''));
11
+ };
7
12
 
8
13
  export const translate = (
9
14
  translations: Translations,
@@ -0,0 +1,73 @@
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
+ }
@@ -27,6 +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 LoginButton from '../../LoginButton';
30
31
 
31
32
  export interface UnLoginProps {
32
33
  session: Session;
@@ -43,7 +44,6 @@ export default function UnLogin({ session, onLogin = noop, size = 24, dark = fal
43
44
  });
44
45
  const searchParams = new URLSearchParams(window.location.search);
45
46
  const browser = useBrowser();
46
-
47
47
  const isFirstLoading = false;
48
48
  const userAnchorRef = useRef(null);
49
49
  const currentState = useReactive({
@@ -55,17 +55,18 @@ export default function UnLogin({ session, onLogin = noop, size = 24, dark = fal
55
55
  const onTogglePopper = useMemoizedFn((value = !currentState.open) => {
56
56
  currentState.open = value;
57
57
  });
58
- const _onLogin = useMemoizedFn(() => {
58
+
59
+ const _onLogin = useMemoizedFn(({ openMode } = {}) => {
59
60
  if (isFirstLoading) {
60
61
  return;
61
62
  }
62
- session.login(onLogin);
63
+ session.login(onLogin, { openMode });
63
64
  });
64
65
 
65
66
  const blocklet = window?.blocklet;
66
67
  const federatedEnabled = getFederatedEnabled(blocklet);
67
- const master = getMaster(blocklet);
68
- const loginApp = federatedEnabled && master ? master : blocklet;
68
+ const masterSite = getMaster(blocklet);
69
+ const loginApp = federatedEnabled && masterSite ? masterSite : blocklet;
69
70
  const loginAppName = loginApp?.appName || 'DID Connect';
70
71
  const loginAppLogo = joinURL(
71
72
  loginApp?.appUrl || '/',
@@ -104,28 +105,34 @@ export default function UnLogin({ session, onLogin = noop, size = 24, dark = fal
104
105
 
105
106
  return (
106
107
  <>
107
- <Box>
108
- <IconButton
109
- ref={userAnchorRef}
110
- onClick={_onLogin}
111
- data-cy="sessionManager-login"
112
- className="arc-session-user-unlogin"
113
- size="medium"
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>
128
- </Box>
108
+ <LoginButton
109
+ locale={locale}
110
+ onClick={_onLogin}
111
+ render={({ onClick }) => {
112
+ return (
113
+ <IconButton
114
+ ref={userAnchorRef}
115
+ data-cy="sessionManager-login"
116
+ className="arc-session-user-unlogin"
117
+ size="medium"
118
+ onClick={onClick}
119
+ aria-label="Login button">
120
+ {isFirstLoading ? (
121
+ <Box width={size} height={size} display="flex" justifyContent="center" alignItems="center">
122
+ <CircularProgress style={{ width: size - 4, height: size - 4, color: dark ? '#fff' : '' }} />
123
+ </Box>
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
+ />
129
136
  <Popper
130
137
  open={currentState.open}
131
138
  anchorEl={userAnchorRef.current}