@arcblock/did-connect-react 3.1.0

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 (183) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +134 -0
  3. package/lib/Address/index.js +4 -0
  4. package/lib/Avatar/index.js +4 -0
  5. package/lib/Button/index.js +17 -0
  6. package/lib/Connect/assets/locale.js +143 -0
  7. package/lib/Connect/assets/login-bg.png +0 -0
  8. package/lib/Connect/assets/login-slogan.js +9 -0
  9. package/lib/Connect/components/action-button.js +26 -0
  10. package/lib/Connect/components/app-tips.js +132 -0
  11. package/lib/Connect/components/auto-height.js +31 -0
  12. package/lib/Connect/components/back-button.js +24 -0
  13. package/lib/Connect/components/connect-status.js +263 -0
  14. package/lib/Connect/components/did-connect-title.js +126 -0
  15. package/lib/Connect/components/download-tips.js +52 -0
  16. package/lib/Connect/components/loading.js +26 -0
  17. package/lib/Connect/components/login-item/connect-choose-list.js +249 -0
  18. package/lib/Connect/components/login-item/login-method-item.js +129 -0
  19. package/lib/Connect/components/login-item/mobile-login-item.js +114 -0
  20. package/lib/Connect/components/login-item/passkey-login-item.js +44 -0
  21. package/lib/Connect/components/login-item/web-login-item.js +97 -0
  22. package/lib/Connect/components/mask-overlay.js +34 -0
  23. package/lib/Connect/components/refresh-overlay.js +57 -0
  24. package/lib/Connect/components/switch-app.js +70 -0
  25. package/lib/Connect/contexts/state.js +142 -0
  26. package/lib/Connect/fullpage.js +5 -0
  27. package/lib/Connect/hooks/auth-url.js +23 -0
  28. package/lib/Connect/hooks/method-list.js +46 -0
  29. package/lib/Connect/hooks/page-show.js +17 -0
  30. package/lib/Connect/hooks/security.js +27 -0
  31. package/lib/Connect/hooks/token.js +305 -0
  32. package/lib/Connect/hooks/use-apps.js +19 -0
  33. package/lib/Connect/hooks/use-quick-connect.js +97 -0
  34. package/lib/Connect/index.js +498 -0
  35. package/lib/Connect/landing-page.js +5 -0
  36. package/lib/Connect/plugins/email/index.js +62 -0
  37. package/lib/Connect/plugins/email/list-item.js +28 -0
  38. package/lib/Connect/plugins/email/placeholder.js +283 -0
  39. package/lib/Connect/plugins/index.js +4 -0
  40. package/lib/Connect/use-connect.js +164 -0
  41. package/lib/Connect/with-blocklet.js +15 -0
  42. package/lib/Connect/with-bridge-call.js +108 -0
  43. package/lib/Federated/context.js +61 -0
  44. package/lib/Federated/index.js +7 -0
  45. package/lib/Logo/index.js +4 -0
  46. package/lib/OAuth/context.js +234 -0
  47. package/lib/OAuth/guest.svg.js +5 -0
  48. package/lib/OAuth/index.js +7 -0
  49. package/lib/OAuth/passport-switcher.js +114 -0
  50. package/lib/Passkey/actions.js +165 -0
  51. package/lib/Passkey/constants.js +4 -0
  52. package/lib/Passkey/context.js +266 -0
  53. package/lib/Passkey/dialog.js +277 -0
  54. package/lib/Passkey/icon.js +13 -0
  55. package/lib/Passkey/index.js +9 -0
  56. package/lib/Service/index.js +62 -0
  57. package/lib/Session/assets/did-spaces-guide-cover.svg.js +135 -0
  58. package/lib/Session/assets/did-spaces-guide-icon.svg.js +9 -0
  59. package/lib/Session/context.js +5 -0
  60. package/lib/Session/did-spaces-guide.js +136 -0
  61. package/lib/Session/hooks/use-federated.js +64 -0
  62. package/lib/Session/hooks/use-mobile.js +8 -0
  63. package/lib/Session/hooks/use-protected-routes.js +11 -0
  64. package/lib/Session/hooks/use-session-token.js +169 -0
  65. package/lib/Session/hooks/use-verify.js +45 -0
  66. package/lib/Session/index.js +896 -0
  67. package/lib/Session/libs/constants.js +15 -0
  68. package/lib/Session/libs/did-spaces.js +10 -0
  69. package/lib/Session/libs/federated.js +42 -0
  70. package/lib/Session/libs/index.js +15 -0
  71. package/lib/Session/libs/locales.js +161 -0
  72. package/lib/Session/libs/login-mobile.js +55 -0
  73. package/lib/Session/window-focus-aware.js +17 -0
  74. package/lib/SessionManager/index.js +4 -0
  75. package/lib/Storage/engine/cookie.js +21 -0
  76. package/lib/Storage/engine/local-storage.js +36 -0
  77. package/lib/Storage/index.js +23 -0
  78. package/lib/User/index.js +6 -0
  79. package/lib/User/use-did.js +59 -0
  80. package/lib/User/wrap-did.js +13 -0
  81. package/lib/WebWalletSWKeeper/index.js +5 -0
  82. package/lib/constant.js +22 -0
  83. package/lib/error.js +8 -0
  84. package/lib/hooks/use-locale.js +7 -0
  85. package/lib/index.js +33 -0
  86. package/lib/locales/en.js +17 -0
  87. package/lib/locales/index.js +10 -0
  88. package/lib/locales/zh.js +17 -0
  89. package/lib/package.json.js +7 -0
  90. package/lib/types.d.ts +355 -0
  91. package/lib/utils.js +214 -0
  92. package/package.json +84 -0
  93. package/src/Address/index.jsx +2 -0
  94. package/src/Avatar/index.jsx +2 -0
  95. package/src/Button/Button.stories.jsx +7 -0
  96. package/src/Button/index.jsx +21 -0
  97. package/src/Connect/Connect.stories.jsx +34 -0
  98. package/src/Connect/assets/locale.js +145 -0
  99. package/src/Connect/assets/login-bg.png +0 -0
  100. package/src/Connect/assets/login-slogan.js +7 -0
  101. package/src/Connect/components/action-button.jsx +22 -0
  102. package/src/Connect/components/app-tips.jsx +156 -0
  103. package/src/Connect/components/auto-height.jsx +38 -0
  104. package/src/Connect/components/back-button.jsx +23 -0
  105. package/src/Connect/components/connect-status.jsx +259 -0
  106. package/src/Connect/components/did-connect-title.jsx +106 -0
  107. package/src/Connect/components/download-tips.jsx +55 -0
  108. package/src/Connect/components/loading.jsx +25 -0
  109. package/src/Connect/components/login-item/connect-choose-list.jsx +304 -0
  110. package/src/Connect/components/login-item/login-method-item.jsx +118 -0
  111. package/src/Connect/components/login-item/mobile-login-item.jsx +179 -0
  112. package/src/Connect/components/login-item/passkey-login-item.jsx +52 -0
  113. package/src/Connect/components/login-item/web-login-item.jsx +149 -0
  114. package/src/Connect/components/mask-overlay.jsx +32 -0
  115. package/src/Connect/components/refresh-overlay.jsx +52 -0
  116. package/src/Connect/components/switch-app.jsx +69 -0
  117. package/src/Connect/contexts/state.jsx +219 -0
  118. package/src/Connect/fullpage.jsx +3 -0
  119. package/src/Connect/hooks/auth-url.js +31 -0
  120. package/src/Connect/hooks/method-list.js +121 -0
  121. package/src/Connect/hooks/page-show.js +24 -0
  122. package/src/Connect/hooks/security.js +40 -0
  123. package/src/Connect/hooks/token.js +639 -0
  124. package/src/Connect/hooks/use-apps.js +69 -0
  125. package/src/Connect/hooks/use-quick-connect.js +130 -0
  126. package/src/Connect/index.jsx +600 -0
  127. package/src/Connect/landing-page.jsx +3 -0
  128. package/src/Connect/plugins/email/index.jsx +82 -0
  129. package/src/Connect/plugins/email/list-item.jsx +31 -0
  130. package/src/Connect/plugins/email/placeholder.jsx +365 -0
  131. package/src/Connect/plugins/index.js +2 -0
  132. package/src/Connect/use-connect.jsx +321 -0
  133. package/src/Connect/with-blocklet.jsx +26 -0
  134. package/src/Connect/with-bridge-call.jsx +138 -0
  135. package/src/Federated/context.jsx +93 -0
  136. package/src/Federated/index.jsx +1 -0
  137. package/src/Logo/index.jsx +2 -0
  138. package/src/OAuth/context.jsx +346 -0
  139. package/src/OAuth/guest.svg +20 -0
  140. package/src/OAuth/index.jsx +1 -0
  141. package/src/OAuth/passport-switcher.jsx +133 -0
  142. package/src/Passkey/actions.jsx +212 -0
  143. package/src/Passkey/constants.js +2 -0
  144. package/src/Passkey/context.jsx +381 -0
  145. package/src/Passkey/dialog.jsx +391 -0
  146. package/src/Passkey/icon.jsx +10 -0
  147. package/src/Passkey/index.jsx +2 -0
  148. package/src/Service/index.jsx +96 -0
  149. package/src/Session/assets/did-spaces-guide-cover.svg +128 -0
  150. package/src/Session/assets/did-spaces-guide-icon.svg +7 -0
  151. package/src/Session/context.jsx +7 -0
  152. package/src/Session/did-spaces-guide.jsx +173 -0
  153. package/src/Session/hooks/use-federated.js +88 -0
  154. package/src/Session/hooks/use-mobile.jsx +6 -0
  155. package/src/Session/hooks/use-protected-routes.js +16 -0
  156. package/src/Session/hooks/use-session-token.js +365 -0
  157. package/src/Session/hooks/use-verify.jsx +76 -0
  158. package/src/Session/index.jsx +1687 -0
  159. package/src/Session/libs/constants.js +14 -0
  160. package/src/Session/libs/did-spaces.js +38 -0
  161. package/src/Session/libs/federated.js +79 -0
  162. package/src/Session/libs/index.js +5 -0
  163. package/src/Session/libs/locales.js +160 -0
  164. package/src/Session/libs/login-mobile.js +80 -0
  165. package/src/Session/window-focus-aware.jsx +28 -0
  166. package/src/SessionManager/index.jsx +2 -0
  167. package/src/Storage/engine/cookie.js +23 -0
  168. package/src/Storage/engine/local-storage.js +55 -0
  169. package/src/Storage/index.js +25 -0
  170. package/src/User/index.js +4 -0
  171. package/src/User/use-did.js +80 -0
  172. package/src/User/wrap-did.jsx +18 -0
  173. package/src/WebWalletSWKeeper/index.jsx +3 -0
  174. package/src/constant.js +26 -0
  175. package/src/error.js +6 -0
  176. package/src/hooks/use-locale.jsx +6 -0
  177. package/src/index.js +43 -0
  178. package/src/locales/en.jsx +15 -0
  179. package/src/locales/index.jsx +13 -0
  180. package/src/locales/zh.jsx +15 -0
  181. package/src/types.d.ts +355 -0
  182. package/src/utils.js +395 -0
  183. package/vite.config.mjs +29 -0
@@ -0,0 +1,31 @@
1
+ import PropTypes from 'prop-types';
2
+ import { useMemoizedFn } from 'ahooks';
3
+ import mailOutlineRoundedIcon from '@iconify-icons/material-symbols/mail-outline-rounded';
4
+ import { LOGIN_PROVIDER, LOGIN_PROVIDER_NAME } from '@arcblock/ux/lib/Util/constant';
5
+
6
+ import LoginMethodItem from '../../components/login-item/login-method-item';
7
+ import { useStateContext } from '../../contexts/state';
8
+
9
+ export default function EmailListItem({ ...rest }) {
10
+ const { setSelectedPlugin, getPlugin, connectState } = useStateContext();
11
+ const handleConnect = useMemoizedFn(() => {
12
+ const plugin = getPlugin(LOGIN_PROVIDER.EMAIL);
13
+ plugin.state.reset();
14
+ plugin.state.status = 'creating';
15
+ connectState.chooseMethod = LOGIN_PROVIDER.EMAIL;
16
+ setSelectedPlugin(plugin);
17
+ });
18
+
19
+ return (
20
+ <LoginMethodItem
21
+ {...rest}
22
+ title={LOGIN_PROVIDER_NAME[LOGIN_PROVIDER.EMAIL]}
23
+ icon={mailOutlineRoundedIcon}
24
+ onClick={handleConnect}
25
+ />
26
+ );
27
+ }
28
+
29
+ EmailListItem.propTypes = {
30
+ onClick: PropTypes.func,
31
+ };
@@ -0,0 +1,365 @@
1
+ import LoadingMask from '@arcblock/ux/lib/LoadingMask';
2
+ import { Box, CircularProgress, TextField, Typography } from '@mui/material';
3
+ import { useCreation, useInterval, useMemoizedFn, useReactive } from 'ahooks';
4
+ import PropTypes from 'prop-types';
5
+ import { joinURL, withQuery } from 'ufo';
6
+ import Toast from '@arcblock/ux/lib/Toast';
7
+ import VerificationCode from '@arcblock/ux/lib/VerificationCode';
8
+ import { useEffect } from 'react';
9
+ import noop from 'lodash/noop';
10
+ import ProviderIcon from '@arcblock/ux/lib/DIDConnect/provider-icon';
11
+
12
+ import BackButton from '../../components/back-button';
13
+ import ActionButton from '../../components/action-button';
14
+ import { useStateContext } from '../../contexts/state';
15
+ import { BLOCKLET_SERVICE_PATH_PREFIX, CHECK_STATUS_INTERVAL, VERIFY_CODE_LENGTH } from '../../../constant';
16
+ import { createAxios, debug } from '../../../utils';
17
+
18
+ export default function EmailPlaceholder({
19
+ fallback = null,
20
+ state,
21
+ forceUpdate = noop,
22
+ onSuccess = noop,
23
+ t: rawT = noop,
24
+ }) {
25
+ const { setSelectedPlugin, locale, connectState, action, extraParams } = useStateContext();
26
+ const t = useMemoizedFn((key, data = {}) => {
27
+ return rawT(key, data, locale);
28
+ });
29
+ const api = useCreation(() => {
30
+ return createAxios({
31
+ baseURL: joinURL(state.baseUrl, BLOCKLET_SERVICE_PATH_PREFIX, '/api/user'),
32
+ });
33
+ }, [state.baseUrl]);
34
+
35
+ const currentState = useReactive({
36
+ email: '',
37
+ code: '',
38
+ codeId: '',
39
+ defaultVerifyMode: 'magicLink',
40
+ verifyMode: 'magicLink', // magicLink, code
41
+ loadingSendCode: false,
42
+ loadingVerifyCode: false,
43
+ error: '',
44
+ });
45
+
46
+ const reset = useMemoizedFn(() => {
47
+ currentState.email = '';
48
+ currentState.code = '';
49
+ currentState.codeId = '';
50
+ currentState.verifyMode = currentState.defaultVerifyMode;
51
+ currentState.loadingSendCode = false;
52
+ currentState.loadingVerifyCode = false;
53
+ currentState.error = '';
54
+ });
55
+
56
+ const sendCode = useMemoizedFn(async () => {
57
+ if (!currentState.email || !currentState.email.trim()) {
58
+ currentState.error = t('emailRequired');
59
+ return;
60
+ }
61
+
62
+ // 检查邮箱格式
63
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
64
+ if (!emailRegex.test(currentState.email)) {
65
+ currentState.error = t('emailInvalid');
66
+ return;
67
+ }
68
+ currentState.error = '';
69
+
70
+ try {
71
+ currentState.loadingSendCode = true;
72
+ let useMagicLink = false;
73
+ // FIXME: @zhanghan 暂时只允许登录时使用 magicLink,否则其他的事件无法调用正确的回调
74
+ if (['login'].includes(action)) {
75
+ // FIXME: @zhanghan 如果 sourceAppPid 存在,则不使用 magicLink,暂无法获得正确的 magicLink 地址
76
+ if (!connectState.sourceAppPid) {
77
+ useMagicLink = true;
78
+ }
79
+ }
80
+ const { data } = await api.post(withQuery('/email/sendCode', { locale }), {
81
+ email: currentState.email,
82
+ sourceAppPid: connectState.sourceAppPid,
83
+ useMagicLink,
84
+ });
85
+ currentState.verifyMode = currentState.defaultVerifyMode;
86
+ currentState.codeId = data.id;
87
+ state.status = 'sending';
88
+ } catch (error) {
89
+ const errorMessage = error?.response?.data?.error || error?.message;
90
+ state.status = 'error';
91
+ state.error = errorMessage;
92
+ } finally {
93
+ currentState.loadingSendCode = false;
94
+ forceUpdate();
95
+ }
96
+ });
97
+ const verifyCode = useMemoizedFn(async () => {
98
+ if (currentState.code.length !== VERIFY_CODE_LENGTH) {
99
+ return;
100
+ }
101
+
102
+ try {
103
+ currentState.loadingVerifyCode = true;
104
+ const { data: loginResult } = await api.post(withQuery('/email/login', { locale }), {
105
+ ...extraParams,
106
+ action,
107
+ code: currentState.code,
108
+ sourceAppPid: connectState.sourceAppPid,
109
+ });
110
+ debug('Email login succeed (use code)', { loginResult });
111
+ await onSuccess(
112
+ {
113
+ ...loginResult,
114
+ encrypted: false,
115
+ },
116
+ (val) => val
117
+ );
118
+ state.status = 'succeed';
119
+ } catch (error) {
120
+ const errorMessage = error?.response?.data || error?.message;
121
+ Toast.error(errorMessage);
122
+ debug('Email login failed (use code)', { error });
123
+ } finally {
124
+ currentState.loadingVerifyCode = false;
125
+ forceUpdate();
126
+ }
127
+ });
128
+ const verifyMagicToken = useMemoizedFn(async () => {
129
+ state.status = 'verifying';
130
+ forceUpdate();
131
+ try {
132
+ const { data: loginResult } = await api.post(withQuery('/email/login', { locale }), {
133
+ ...extraParams,
134
+ action,
135
+ magicToken: state.magicToken,
136
+ });
137
+ debug('Email login succeed (use magic link)', { loginResult });
138
+ await onSuccess(
139
+ {
140
+ ...loginResult,
141
+ encrypted: false,
142
+ },
143
+ (val) => val
144
+ );
145
+ state.status = 'succeed';
146
+ } catch (error) {
147
+ const errorMessage = error?.response?.data || error?.message;
148
+ state.status = 'error';
149
+ state.error = errorMessage;
150
+ debug('Email login failed (use magic link)', { error });
151
+ }
152
+ forceUpdate();
153
+ });
154
+
155
+ const shouldPoll =
156
+ currentState.verifyMode === 'magicLink' &&
157
+ state.status === 'sending' &&
158
+ // 如果正在校验验证码,则不轮询状态
159
+ !currentState.loadingVerifyCode &&
160
+ currentState.codeId;
161
+
162
+ const checkStatus = useMemoizedFn(async () => {
163
+ if (!shouldPoll) {
164
+ return;
165
+ }
166
+ try {
167
+ const { data } = await api.get('/email/status', {
168
+ params: {
169
+ codeId: currentState.codeId,
170
+ },
171
+ });
172
+ if (data.verified) {
173
+ state.status = 'succeed';
174
+ reset();
175
+ await onSuccess({ encrypted: false }, (val) => val);
176
+ }
177
+ } catch (error) {
178
+ // 只做记录
179
+ console.error('check status error', error);
180
+ }
181
+ forceUpdate();
182
+ });
183
+
184
+ useInterval(checkStatus, shouldPoll ? CHECK_STATUS_INTERVAL : undefined);
185
+
186
+ useEffect(() => {
187
+ reset();
188
+ // FIXME: @zhanghan 暂不支持子站进行统一登录时使用 magicLink 登录
189
+ if (connectState.sourceAppPid || !['login'].includes(action)) {
190
+ currentState.defaultVerifyMode = 'code';
191
+ }
192
+ if (state.magicToken) {
193
+ verifyMagicToken();
194
+ }
195
+ // 由于存在 email 插件被重置的情况,所以需要监听 state 是否被重新赋值来执行 init 操作
196
+ // eslint-disable-next-line react-hooks/exhaustive-deps
197
+ }, [state]);
198
+
199
+ let content = null;
200
+ if (state.status === 'creating') {
201
+ content = (
202
+ <>
203
+ <Typography
204
+ variant="body2"
205
+ sx={{
206
+ textAlign: 'center',
207
+ color: 'text.secondary',
208
+ }}>
209
+ {t('emailPlaceholder')}
210
+ </Typography>
211
+ <TextField
212
+ name="email"
213
+ fullWidth
214
+ type="email"
215
+ variant="outlined"
216
+ label={t('email')}
217
+ placeholder={t('emailPlaceholder')}
218
+ size="small"
219
+ value={currentState.email}
220
+ onChange={(e) => {
221
+ currentState.email = e.target.value;
222
+ }}
223
+ onKeyDown={(e) => {
224
+ if (e.key === 'Enter') {
225
+ sendCode(currentState.email);
226
+ }
227
+ }}
228
+ sx={{
229
+ maxWidth: 320,
230
+ '& .MuiOutlinedInput-root': {
231
+ borderRadius: 1,
232
+ },
233
+ }}
234
+ error={!!currentState.error}
235
+ helperText={currentState.error}
236
+ slotProps={{
237
+ htmlInput: {
238
+ sx: {
239
+ boxSizing: 'content-box !important',
240
+ },
241
+ },
242
+ }}
243
+ />
244
+ <Box sx={{ display: 'flex', gap: 1 }}>
245
+ <BackButton
246
+ onClick={() => {
247
+ state.reset();
248
+ setSelectedPlugin();
249
+ }}
250
+ />
251
+ <ActionButton
252
+ sx={{
253
+ color: 'primary.main',
254
+ borderColor: 'primary.light',
255
+ }}
256
+ disabled={currentState.loadingSendCode}
257
+ onClick={() => {
258
+ sendCode(currentState.email);
259
+ }}>
260
+ {currentState.loadingSendCode ? <CircularProgress color="inherit" size={14} sx={{ mr: 1 }} /> : null}
261
+ {t('sendCode')}
262
+ </ActionButton>
263
+ </Box>
264
+ </>
265
+ );
266
+ } else if (state.status === 'sending') {
267
+ content = (
268
+ <>
269
+ <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
270
+ <Typography variant="body2" sx={{ textAlign: 'center', color: 'text.secondary' }}>
271
+ {currentState.verifyMode === 'magicLink' ? (
272
+ <>
273
+ {t('verifyEmail')}
274
+ <br />
275
+ {t('orUseCodePlaceholder')}
276
+ </>
277
+ ) : (
278
+ t('codePlaceholder')
279
+ )}
280
+ </Typography>
281
+ <>
282
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
283
+ {/* 暂时保留代码,防止后期需要再使用 */}
284
+ {/* <Link
285
+ underline="none"
286
+ variant="caption"
287
+ component="button"
288
+ sx={{ mb: 2 }}
289
+ onClick={() => {
290
+ currentState.verifyMode = 'code';
291
+ forceUpdate();
292
+ }}>
293
+ {t('useCode')}
294
+ </Link>
295
+ <BackButton
296
+ onClick={() => {
297
+ state.status = 'creating';
298
+ forceUpdate();
299
+ }}
300
+ /> */}
301
+ </>
302
+ </Box>
303
+ <>
304
+ <VerificationCode
305
+ code={currentState.code}
306
+ onChange={(code) => {
307
+ currentState.code = code;
308
+ }}
309
+ onComplete={() => {
310
+ verifyCode();
311
+ }}
312
+ />
313
+ <Box sx={{ display: 'flex', gap: 1 }}>
314
+ <BackButton
315
+ onClick={() => {
316
+ currentState.code = '';
317
+ state.status = 'creating';
318
+ forceUpdate();
319
+ }}
320
+ />
321
+ <ActionButton
322
+ sx={{
323
+ color: 'primary.main',
324
+ borderColor: 'primary.light',
325
+ }}
326
+ disabled={currentState.loadingVerifyCode}
327
+ onClick={() => {
328
+ verifyCode();
329
+ }}>
330
+ {currentState.loadingVerifyCode ? <CircularProgress color="inherit" size={14} sx={{ mr: 1 }} /> : null}
331
+ {t('confirm')}
332
+ </ActionButton>
333
+ </Box>
334
+ </>
335
+ </>
336
+ );
337
+ } else {
338
+ return fallback;
339
+ }
340
+
341
+ return (
342
+ <Box
343
+ sx={{
344
+ display: 'flex',
345
+ flexDirection: 'column',
346
+ alignItems: 'center',
347
+ justifyContent: 'center',
348
+ gap: 2,
349
+ pb: 1,
350
+ }}>
351
+ <LoadingMask size={52} borderRadius={12}>
352
+ <ProviderIcon provider="email" />
353
+ </LoadingMask>
354
+ {content}
355
+ </Box>
356
+ );
357
+ }
358
+
359
+ EmailPlaceholder.propTypes = {
360
+ fallback: PropTypes.any,
361
+ state: PropTypes.object.isRequired,
362
+ forceUpdate: PropTypes.func,
363
+ onSuccess: PropTypes.func,
364
+ t: PropTypes.func,
365
+ };
@@ -0,0 +1,2 @@
1
+ /* eslint-disable import/prefer-default-export */
2
+ export { default as useEmailPlugin } from './email';