@arcblock/ux 2.7.13 → 2.7.15

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.
@@ -60,6 +60,21 @@ export default function CardSelector({
60
60
  transform: `translate(${-translateX}px, 0)`
61
61
  },
62
62
  children: list.map((e, i) => {
63
+ if (e instanceof Function) {
64
+ return /*#__PURE__*/_jsx("div", {
65
+ className: `card-item ${i === selectedId ? 'selected' : ''}`,
66
+ style: {
67
+ width,
68
+ height,
69
+ margin: cardSpace / 2
70
+ }
71
+ // eslint-disable-next-line react/no-array-index-key
72
+ ,
73
+
74
+ onClick: () => selectedItem(i),
75
+ children: e(i)
76
+ }, i);
77
+ }
63
78
  return /*#__PURE__*/_jsx("div", {
64
79
  className: `card-item ${i === selectedId ? 'selected' : ''}`,
65
80
  style: {
@@ -96,7 +111,8 @@ const Contianer = styled.div`
96
111
  align-items: center;
97
112
  flex-shrink: 0;
98
113
  cursor: pointer;
99
- img {
114
+ img,
115
+ svg {
100
116
  max-width: 100%;
101
117
  max-height: 100%;
102
118
  width: auto;
@@ -107,7 +123,8 @@ const Contianer = styled.div`
107
123
  }
108
124
  &.selected {
109
125
  cursor: default;
110
- img {
126
+ img,
127
+ svg {
111
128
  outline: #526ded solid 5px;
112
129
  }
113
130
  }
@@ -1,4 +1,8 @@
1
1
  import PropTypes from 'prop-types';
2
+ import { useContext, forwardRef, useRef, useImperativeHandle } from 'react';
3
+ import { useMemoizedFn, useReactive } from 'ahooks';
4
+ import noop from 'lodash/noop';
5
+ import { LocaleContext } from '../Locale/context';
2
6
  import Button from '../Button';
3
7
  import Dialog from './dialog';
4
8
 
@@ -12,7 +16,7 @@ import Dialog from './dialog';
12
16
  @property {boolean} [showCancelButton=true]
13
17
  @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [confirmButton={text: 'Confirm'}]
14
18
  @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [cancelButton={text: 'Cancel'}]
15
- @property {import('@mui/material').PaperProps} [PaperProps={}]
19
+ @property {import('@mui/material').PaperProps} [PaperProps={}]
16
20
  */
17
21
 
18
22
  // 注意排在 {...rest} 之后的 props 优先级更高
@@ -87,4 +91,96 @@ Confirm.defaultProps = {
87
91
  text: 'Cancel'
88
92
  },
89
93
  PaperProps: {}
90
- };
94
+ };
95
+ const ConfirmHolder = /*#__PURE__*/forwardRef((props, ref) => {
96
+ const {
97
+ t
98
+ } = useContext(LocaleContext);
99
+ const state = useReactive({
100
+ show: false,
101
+ title: '',
102
+ content: '',
103
+ onConfirm: noop,
104
+ onCancel: noop,
105
+ loading: false
106
+ });
107
+ const open = useMemoizedFn((params = {}) => {
108
+ state.show = true;
109
+ state.title = params.title;
110
+ state.content = params.content;
111
+ state.onConfirm = params.onConfirm || noop;
112
+ state.onCancel = params.onCancel || noop;
113
+ state.loading = false;
114
+ });
115
+ const reset = useMemoizedFn(() => {
116
+ state.title = '';
117
+ state.content = '';
118
+ state.onConfirm = noop;
119
+ state.onCancel = noop;
120
+ });
121
+ const close = useMemoizedFn(() => {
122
+ state.show = false;
123
+ setTimeout(() => {
124
+ reset();
125
+ }, 300);
126
+ });
127
+ const onCancel = useMemoizedFn(() => {
128
+ close();
129
+ state?.onCancel();
130
+ }, []);
131
+ const onConfirm = useMemoizedFn(async () => {
132
+ state.loading = true;
133
+ try {
134
+ await state?.onConfirm(close);
135
+ } finally {
136
+ state.loading = false;
137
+ }
138
+ }, []);
139
+ useImperativeHandle(ref, () => {
140
+ return {
141
+ open,
142
+ close
143
+ };
144
+ }, [open, close]);
145
+ return /*#__PURE__*/_jsx(Confirm, {
146
+ open: state.show,
147
+ title: state.title,
148
+ onConfirm: onConfirm,
149
+ onCancel: onCancel,
150
+ confirmButton: {
151
+ text: t('common.confirm'),
152
+ props: {
153
+ variant: 'contained',
154
+ color: 'primary',
155
+ loading: state.loading
156
+ }
157
+ },
158
+ cancelButton: {
159
+ text: t('common.cancel'),
160
+ props: {
161
+ variant: 'outlined',
162
+ color: 'primary'
163
+ }
164
+ },
165
+ children: state.content
166
+ });
167
+ });
168
+ export function useConfirm() {
169
+ const confirmRef = useRef(null);
170
+ const open = useMemoizedFn((...args) => {
171
+ confirmRef.current?.open(...args);
172
+ });
173
+ const close = useMemoizedFn((...args) => {
174
+ confirmRef.current?.close(...args);
175
+ });
176
+ const confirmApi = {
177
+ open,
178
+ close
179
+ };
180
+ return {
181
+ confirmHolder: /*#__PURE__*/_jsx(ConfirmHolder, {
182
+ ref: confirmRef
183
+ }),
184
+ confirmApi
185
+ };
186
+ }
@@ -1,3 +1,4 @@
1
1
  // eslint-disable-next-line no-restricted-exports
2
2
  export { default } from './dialog';
3
- export { default as Confirm } from './confirm';
3
+ export { default as Confirm } from './confirm';
4
+ export { useConfirm } from './confirm';
@@ -1,14 +1,7 @@
1
1
  /* eslint-disable react/jsx-no-bind */
2
2
  import { useState, useContext, useRef, useMemo } from 'react';
3
3
  import PropTypes from 'prop-types';
4
- import Button from '@mui/material/Button';
5
- import Typography from '@mui/material/Typography';
6
- import IconButton from '@mui/material/IconButton';
7
- import ClickAwayListener from '@mui/material/ClickAwayListener';
8
- import Popper from '@mui/material/Popper';
9
- import MenuItem from '@mui/material/MenuItem';
10
- import MenuList from '@mui/material/MenuList';
11
- import Box from '@mui/material/Box';
4
+ import { Button, Typography, IconButton, Popper, MenuItem, MenuList, Box, ClickAwayListener } from '@mui/material';
12
5
  import CheckIcon from '@mui/icons-material/Check';
13
6
  import GlobeIcon from '@arcblock/icons/lib/Globe';
14
7
  import { getColor, getBackground } from '../Util';
@@ -92,7 +85,7 @@ export default function LocaleSelector(props) {
92
85
  children: languages.find(x => x.code === locale).name
93
86
  }) : '']
94
87
  })
95
- }), /*#__PURE__*/_jsx(Popper, {
88
+ }), /*#__PURE__*/_jsx(StyledPopper, {
96
89
  open: open,
97
90
  anchorEl: anchorEl.current,
98
91
  ...popperProps,
@@ -179,4 +172,11 @@ const Div = styled('div', {
179
172
  visibility: visible;
180
173
  }
181
174
  }
175
+ `;
176
+ const StyledPopper = styled(Popper)`
177
+ z-index: ${({
178
+ theme
179
+ }) => {
180
+ return theme.zIndex.tooltip + 10;
181
+ }};
182
182
  `;
@@ -21,7 +21,7 @@ const translations = {
21
21
  member
22
22
  }) {
23
23
  return /*#__PURE__*/_jsxs(_Fragment, {
24
- children: ["Use ", master, " account to connect ", member]
24
+ children: ["Connect ", member, " with ", master, " account"]
25
25
  });
26
26
  },
27
27
  connect: 'Connect Account',
@@ -63,6 +63,14 @@ export default function FederatedLoginDetecter({
63
63
  mode: userInfo ? 'auto' : 'manual'
64
64
  });
65
65
  }, [session, userInfo, _locale]);
66
+ let appLogoUrl;
67
+ if (siteInfo) {
68
+ appLogoUrl = new URL(siteInfo.appLogo, siteInfo.appUrl);
69
+ appLogoUrl.searchParams.set('imageFilter', 'resize');
70
+ // HACK: 保持跟其他地方使用的尺寸一致,可以复用同一资源的缓存,减少网络请求
71
+ appLogoUrl.searchParams.set('w', '80');
72
+ appLogoUrl.searchParams.set('h', '80');
73
+ }
66
74
  return siteInfo && /*#__PURE__*/_jsx(UserPopper, {
67
75
  open: federatedLoginOpen,
68
76
  anchorEl: anchorEl,
@@ -77,7 +85,7 @@ export default function FederatedLoginDetecter({
77
85
  children: [/*#__PURE__*/_jsx(Box, {
78
86
  component: "img",
79
87
  mr: 2,
80
- src: `${siteInfo.appUrl}${siteInfo.appLogo}`,
88
+ src: appLogoUrl.href,
81
89
  alt: siteInfo.appName,
82
90
  width: "30px",
83
91
  height: "30px"
@@ -6,15 +6,14 @@ import { Box, IconButton, MenuList, MenuItem, SvgIcon, Button, Chip, Link, Circu
6
6
  import SwitchProfileIcon from '@mui/icons-material/PersonOutline';
7
7
  import BindWalletIcon from '@mui/icons-material/Link';
8
8
  import SwitchPassportIcon from '@mui/icons-material/VpnKeyOutlined';
9
- import ConnectWithoutContactIcon from '@mui/icons-material/ConnectWithoutContact';
10
9
  import ShieldCheck from 'mdi-material-ui/ShieldCheck';
11
10
  import AccountIcon from '@arcblock/icons/lib/Account';
12
11
  import OpenInIcon from '@arcblock/icons/lib/OpenIn';
13
12
  import DisconnectIcon from '@arcblock/icons/lib/Disconnect';
14
13
  import SwitchDidIcon from '@arcblock/icons/lib/Switch';
15
14
  import useBrowser from '@arcblock/react-hooks/lib/useBrowser';
16
- import isEmpty from 'lodash/isEmpty';
17
15
  import noop from 'lodash/noop';
16
+ import isEmpty from 'lodash/isEmpty';
18
17
  import DidAvatar from '../Avatar';
19
18
  import DidAddress from '../Address';
20
19
  import { getUserAvatar } from '../Util';
@@ -25,7 +24,9 @@ import { jsxs as _jsxs } from "react/jsx-runtime";
25
24
  import { Fragment as _Fragment } from "react/jsx-runtime";
26
25
  const translations = {
27
26
  en: {
27
+ account: 'account',
28
28
  switchDid: 'Switch DID',
29
+ switchTo: 'Switch to',
29
30
  switchProfile: 'Switch Profile',
30
31
  switchPassport: 'Switch Passport',
31
32
  disconnect: 'Disconnect',
@@ -37,7 +38,9 @@ const translations = {
37
38
  connectedWith: 'Connected with'
38
39
  },
39
40
  zh: {
41
+ account: '账号',
40
42
  switchDid: '切换账户',
43
+ switchTo: '切换至',
41
44
  switchProfile: '切换用户信息',
42
45
  switchPassport: '切换通行证',
43
46
  disconnect: '退出',
@@ -120,6 +123,7 @@ function SessionManager({
120
123
  // eslint-disable-next-line react/prop-types
121
124
  }, [session?.initialized, session?.loading]);
122
125
  const masterSiteInfo = window.blocklet?.settings?.federated?.master;
126
+ const currentSiteInfo = window.blocklet;
123
127
  if (!session.user) {
124
128
  return /*#__PURE__*/_jsxs(_Fragment, {
125
129
  children: [showText ? /*#__PURE__*/_jsxs(Button, {
@@ -195,7 +199,8 @@ function SessionManager({
195
199
  function _onLogout() {
196
200
  session.logout((...args) => {
197
201
  logoutOAuth({
198
- session
202
+ session,
203
+ hack: true
199
204
  }, ...args).then(() => {
200
205
  onLogout(...args);
201
206
  }).catch(err => {
@@ -205,10 +210,28 @@ function SessionManager({
205
210
  });
206
211
  });
207
212
  }
213
+ /**
214
+ * @name 切换账户
215
+ * @description 该功能仅在登录后才能使用,目前仅用于切换普通登录和统一登录的账户,所以会增加一些与统一登录相关的逻辑
216
+ */
208
217
  function _onSwitchDid() {
218
+ const {
219
+ provider,
220
+ user
221
+ } = session;
222
+ if (!user) return;
223
+ let targetProvider = provider;
224
+ if (provider === 'federated') {
225
+ targetProvider = 'wallet';
226
+ } else if (['auth0', 'wallet'].includes(provider)) {
227
+ targetProvider = 'federated';
228
+ }
209
229
  session.switchDid((...args) => {
210
230
  setUserOpen(false);
211
231
  onSwitchDid(...args);
232
+ }, {
233
+ provider: targetProvider,
234
+ providerMode: 'paramsFirst'
212
235
  });
213
236
  }
214
237
  function _onSwitchProfile() {
@@ -316,25 +339,6 @@ function SessionManager({
316
339
  })
317
340
  })]
318
341
  })]
319
- }), federatedAccount && !isEmpty(masterSiteInfo) && /*#__PURE__*/_jsx(MenuItem, {
320
- className: "session-manager-menu-item",
321
- "data-cy": "sessionManager-connectWithFederated",
322
- children: /*#__PURE__*/_jsxs(Box, {
323
- overflow: "hidden",
324
- textOverflow: "ellipsis",
325
- children: [/*#__PURE__*/_jsx(SvgIcon, {
326
- component: ConnectWithoutContactIcon,
327
- className: "session-manager-menu-icon"
328
- }), translation.connectedWith, /*#__PURE__*/_jsx(Link, {
329
- ml: 1,
330
- href: masterSiteInfo.appUrl,
331
- underline: "hover",
332
- target: "_blank",
333
- title: masterSiteInfo.appName,
334
- "aria-label": "Open federated master site url",
335
- children: masterSiteInfo.appName
336
- })]
337
- })
338
342
  }), Array.isArray(menu) && menu.map((menuItem, index) => {
339
343
  const {
340
344
  svgIcon,
@@ -366,7 +370,7 @@ function SessionManager({
366
370
  component: OpenInIcon,
367
371
  className: "session-manager-menu-icon"
368
372
  }), translation.openInWallet]
369
- }), !!switchDid && /*#__PURE__*/_jsxs(MenuItem, {
373
+ }), !isEmpty(masterSiteInfo) && !!switchDid && /*#__PURE__*/_jsxs(MenuItem, {
370
374
  className: "session-manager-menu-item",
371
375
  onClick: _onSwitchDid,
372
376
  "aria-label": translation.switchDid,
@@ -374,7 +378,29 @@ function SessionManager({
374
378
  children: [/*#__PURE__*/_jsx(SvgIcon, {
375
379
  component: SwitchDidIcon,
376
380
  className: "session-manager-menu-icon"
377
- }), translation.switchDid]
381
+ }), /*#__PURE__*/_jsxs(Box, {
382
+ sx: {
383
+ whiteSpace: 'normal',
384
+ wordBreak: 'break-all'
385
+ },
386
+ children: [translation.switchTo, session.provider === 'federated' ? /*#__PURE__*/_jsx(Link, {
387
+ mx: 1,
388
+ href: currentSiteInfo.appUrl,
389
+ underline: "hover",
390
+ target: "_blank",
391
+ title: currentSiteInfo.appName,
392
+ "aria-label": "Open current site url",
393
+ children: currentSiteInfo.appName
394
+ }) : /*#__PURE__*/_jsx(Link, {
395
+ mx: 1,
396
+ href: masterSiteInfo.appUrl,
397
+ underline: "hover",
398
+ target: "_blank",
399
+ title: masterSiteInfo.appName,
400
+ "aria-label": "Open federated master site url",
401
+ children: masterSiteInfo.appName
402
+ }), translation.account]
403
+ })]
378
404
  }), !!switchProfile && hasBindWallet && session.provider !== 'federated' && /*#__PURE__*/_jsxs(MenuItem, {
379
405
  className: "session-manager-menu-item",
380
406
  onClick: _onSwitchProfile,
@@ -82,7 +82,9 @@ UserPopper.defaultProps = {
82
82
  const StyledPopper = styled(Popper)`
83
83
  z-index: ${({
84
84
  theme
85
- }) => theme.zIndex.tooltip};
85
+ }) => {
86
+ return theme.zIndex.tooltip;
87
+ }};
86
88
  .MuiList-root {
87
89
  /* HACK: 需要288px 才能将 did 展示完整 */
88
90
  width: 290px;
@@ -70,6 +70,21 @@ function CardSelector(_ref) {
70
70
  transform: "translate(".concat(-translateX, "px, 0)")
71
71
  },
72
72
  children: list.map((e, i) => {
73
+ if (e instanceof Function) {
74
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
75
+ className: "card-item ".concat(i === selectedId ? 'selected' : ''),
76
+ style: {
77
+ width,
78
+ height,
79
+ margin: cardSpace / 2
80
+ }
81
+ // eslint-disable-next-line react/no-array-index-key
82
+ ,
83
+
84
+ onClick: () => selectedItem(i),
85
+ children: e(i)
86
+ }, i);
87
+ }
73
88
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
74
89
  className: "card-item ".concat(i === selectedId ? 'selected' : ''),
75
90
  style: {
@@ -90,7 +105,7 @@ function CardSelector(_ref) {
90
105
  })
91
106
  });
92
107
  }
93
- const Contianer = _styled.default.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n overflow: hidden;\n mask-image: linear-gradient(to left, transparent, black 3%, black 97%, transparent);\n overflow: hidden;\n .card-container {\n display: flex;\n white-space: nowrap;\n width: max-content;\n transition: all ease 0.3s;\n }\n .card-item {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: pointer;\n img {\n max-width: 100%;\n max-height: 100%;\n width: auto;\n height: auto;\n outline: #526ded solid 0;\n transition: all ease 0.2s;\n box-shadow: rgba(0, 0, 0, 0.2) 0 0 10px;\n }\n &.selected {\n cursor: default;\n img {\n outline: #526ded solid 5px;\n }\n }\n }\n"])));
108
+ const Contianer = _styled.default.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n overflow: hidden;\n mask-image: linear-gradient(to left, transparent, black 3%, black 97%, transparent);\n overflow: hidden;\n .card-container {\n display: flex;\n white-space: nowrap;\n width: max-content;\n transition: all ease 0.3s;\n }\n .card-item {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: pointer;\n img,\n svg {\n max-width: 100%;\n max-height: 100%;\n width: auto;\n height: auto;\n outline: #526ded solid 0;\n transition: all ease 0.2s;\n box-shadow: rgba(0, 0, 0, 0.2) 0 0 10px;\n }\n &.selected {\n cursor: default;\n img,\n svg {\n outline: #526ded solid 5px;\n }\n }\n }\n"])));
94
109
  CardSelector.propTypes = {
95
110
  list: _propTypes.default.array,
96
111
  width: _propTypes.default.number,
@@ -4,7 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = Confirm;
7
+ exports.useConfirm = useConfirm;
7
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
+ var _react = require("react");
10
+ var _ahooks = require("ahooks");
11
+ var _noop = _interopRequireDefault(require("lodash/noop"));
12
+ var _context = require("../Locale/context");
8
13
  var _Button = _interopRequireDefault(require("../Button"));
9
14
  var _dialog = _interopRequireDefault(require("./dialog"));
10
15
  var _jsxRuntime = require("react/jsx-runtime");
@@ -19,7 +24,7 @@ const _excluded = ["title", "children", "onConfirm", "onCancel", "showCancelButt
19
24
  @property {boolean} [showCancelButton=true]
20
25
  @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [confirmButton={text: 'Confirm'}]
21
26
  @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [cancelButton={text: 'Cancel'}]
22
- @property {import('@mui/material').PaperProps} [PaperProps={}]
27
+ @property {import('@mui/material').PaperProps} [PaperProps={}]
23
28
  */
24
29
  // 注意排在 {...rest} 之后的 props 优先级更高
25
30
  /**
@@ -99,4 +104,105 @@ Confirm.defaultProps = {
99
104
  text: 'Cancel'
100
105
  },
101
106
  PaperProps: {}
102
- };
107
+ };
108
+ const ConfirmHolder = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
109
+ const {
110
+ t
111
+ } = (0, _react.useContext)(_context.LocaleContext);
112
+ const state = (0, _ahooks.useReactive)({
113
+ show: false,
114
+ title: '',
115
+ content: '',
116
+ onConfirm: _noop.default,
117
+ onCancel: _noop.default,
118
+ loading: false
119
+ });
120
+ const open = (0, _ahooks.useMemoizedFn)(function () {
121
+ let params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
122
+ state.show = true;
123
+ state.title = params.title;
124
+ state.content = params.content;
125
+ state.onConfirm = params.onConfirm || _noop.default;
126
+ state.onCancel = params.onCancel || _noop.default;
127
+ state.loading = false;
128
+ });
129
+ const reset = (0, _ahooks.useMemoizedFn)(() => {
130
+ state.title = '';
131
+ state.content = '';
132
+ state.onConfirm = _noop.default;
133
+ state.onCancel = _noop.default;
134
+ });
135
+ const close = (0, _ahooks.useMemoizedFn)(() => {
136
+ state.show = false;
137
+ setTimeout(() => {
138
+ reset();
139
+ }, 300);
140
+ });
141
+ const onCancel = (0, _ahooks.useMemoizedFn)(() => {
142
+ close();
143
+ state === null || state === void 0 ? void 0 : state.onCancel();
144
+ }, []);
145
+ const onConfirm = (0, _ahooks.useMemoizedFn)(async () => {
146
+ state.loading = true;
147
+ try {
148
+ await (state === null || state === void 0 ? void 0 : state.onConfirm(close));
149
+ } finally {
150
+ state.loading = false;
151
+ }
152
+ }, []);
153
+ (0, _react.useImperativeHandle)(ref, () => {
154
+ return {
155
+ open,
156
+ close
157
+ };
158
+ }, [open, close]);
159
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(Confirm, {
160
+ open: state.show,
161
+ title: state.title,
162
+ onConfirm: onConfirm,
163
+ onCancel: onCancel,
164
+ confirmButton: {
165
+ text: t('common.confirm'),
166
+ props: {
167
+ variant: 'contained',
168
+ color: 'primary',
169
+ loading: state.loading
170
+ }
171
+ },
172
+ cancelButton: {
173
+ text: t('common.cancel'),
174
+ props: {
175
+ variant: 'outlined',
176
+ color: 'primary'
177
+ }
178
+ },
179
+ children: state.content
180
+ });
181
+ });
182
+ function useConfirm() {
183
+ const confirmRef = (0, _react.useRef)(null);
184
+ const open = (0, _ahooks.useMemoizedFn)(function () {
185
+ var _confirmRef$current;
186
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
187
+ args[_key] = arguments[_key];
188
+ }
189
+ (_confirmRef$current = confirmRef.current) === null || _confirmRef$current === void 0 ? void 0 : _confirmRef$current.open(...args);
190
+ });
191
+ const close = (0, _ahooks.useMemoizedFn)(function () {
192
+ var _confirmRef$current2;
193
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
194
+ args[_key2] = arguments[_key2];
195
+ }
196
+ (_confirmRef$current2 = confirmRef.current) === null || _confirmRef$current2 === void 0 ? void 0 : _confirmRef$current2.close(...args);
197
+ });
198
+ const confirmApi = {
199
+ open,
200
+ close
201
+ };
202
+ return {
203
+ confirmHolder: /*#__PURE__*/(0, _jsxRuntime.jsx)(ConfirmHolder, {
204
+ ref: confirmRef
205
+ }),
206
+ confirmApi
207
+ };
208
+ }
@@ -15,6 +15,14 @@ Object.defineProperty(exports, "default", {
15
15
  return _dialog.default;
16
16
  }
17
17
  });
18
+ Object.defineProperty(exports, "useConfirm", {
19
+ enumerable: true,
20
+ get: function get() {
21
+ return _confirm.useConfirm;
22
+ }
23
+ });
18
24
  var _dialog = _interopRequireDefault(require("./dialog"));
19
- var _confirm = _interopRequireDefault(require("./confirm"));
25
+ var _confirm = _interopRequireWildcard(require("./confirm"));
26
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
27
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
20
28
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -6,21 +6,14 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = LocaleSelector;
7
7
  var _react = require("react");
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
- var _Button = _interopRequireDefault(require("@mui/material/Button"));
10
- var _Typography = _interopRequireDefault(require("@mui/material/Typography"));
11
- var _IconButton = _interopRequireDefault(require("@mui/material/IconButton"));
12
- var _ClickAwayListener = _interopRequireDefault(require("@mui/material/ClickAwayListener"));
13
- var _Popper = _interopRequireDefault(require("@mui/material/Popper"));
14
- var _MenuItem = _interopRequireDefault(require("@mui/material/MenuItem"));
15
- var _MenuList = _interopRequireDefault(require("@mui/material/MenuList"));
16
- var _Box = _interopRequireDefault(require("@mui/material/Box"));
9
+ var _material = require("@mui/material");
17
10
  var _Check = _interopRequireDefault(require("@mui/icons-material/Check"));
18
11
  var _Globe = _interopRequireDefault(require("@arcblock/icons/lib/Globe"));
19
12
  var _Util = require("../Util");
20
13
  var _context = require("./context");
21
14
  var _Theme = require("../Theme");
22
15
  var _jsxRuntime = require("react/jsx-runtime");
23
- var _templateObject;
16
+ var _templateObject, _templateObject2;
24
17
  const _excluded = ["showText", "popperProps", "popperType", "icon", "size"];
25
18
  /* eslint-disable react/jsx-no-bind */
26
19
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -65,7 +58,7 @@ function LocaleSelector(props) {
65
58
  }
66
59
  setOpen(false);
67
60
  };
68
- const ButtonComponent = showText ? _Button.default : _IconButton.default;
61
+ const ButtonComponent = showText ? _material.Button : _material.IconButton;
69
62
  const handleEventProps = popperType === 'hover' ? {
70
63
  onMouseEnter: () => {
71
64
  setOpen(true);
@@ -100,31 +93,31 @@ function LocaleSelector(props) {
100
93
  className: "trigger",
101
94
  role: "button",
102
95
  "aria-label": "Locale selector button",
103
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
96
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Box, {
104
97
  display: "flex",
105
98
  alignItems: "center",
106
- children: [renderIcon, showText ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
99
+ children: [renderIcon, showText ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
107
100
  component: "strong",
108
101
  className: "trigger-text",
109
102
  children: languages.find(x => x.code === locale).name
110
103
  }) : '']
111
104
  })
112
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Popper.default, _objectSpread(_objectSpread({
105
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledPopper, _objectSpread(_objectSpread({
113
106
  open: open,
114
107
  anchorEl: anchorEl.current
115
108
  }, popperProps), {}, {
116
109
  disablePortal: true,
117
110
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
118
111
  className: "locales",
119
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ClickAwayListener.default, {
112
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.ClickAwayListener, {
120
113
  onClickAway: onClose,
121
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_MenuList.default, {
114
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuList, {
122
115
  children: languages.map(_ref => {
123
116
  let {
124
117
  code,
125
118
  name
126
119
  } = _ref;
127
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_MenuItem.default, {
120
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.MenuItem, {
128
121
  className: "locale-item",
129
122
  onClick: () => onSelect(code, name),
130
123
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Check.default, {
@@ -157,4 +150,10 @@ LocaleSelector.defaultProps = {
157
150
  };
158
151
  const Div = (0, _Theme.styled)('div', {
159
152
  shouldForwardProp: prop => prop !== 'dark'
160
- })(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: inline-block;\n\n .trigger {\n display: flex;\n flex-direction: column;\n justify-content: center;\n font-size: 14px;\n white-space: nowrap;\n\n .trigger-text {\n margin-left: 5px;\n font-size: 14px;\n color: ", ";\n }\n }\n\n .locales {\n background: ", ";\n box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);\n }\n\n .locale-item {\n font-size: 16px;\n font-style: normal;\n font-stretch: normal;\n line-height: normal;\n letter-spacing: 2px;\n text-align: center;\n color: ", ";\n cursor: pointer;\n display: flex;\n padding: 16px;\n align-items: center;\n .check-icon {\n visibility: hidden;\n margin-right: 4px;\n }\n .check-icon-visible {\n visibility: visible;\n }\n }\n"])), props => (0, _Util.getColor)(props), props => (0, _Util.getBackground)(props), props => (0, _Util.getColor)(props));
153
+ })(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: inline-block;\n\n .trigger {\n display: flex;\n flex-direction: column;\n justify-content: center;\n font-size: 14px;\n white-space: nowrap;\n\n .trigger-text {\n margin-left: 5px;\n font-size: 14px;\n color: ", ";\n }\n }\n\n .locales {\n background: ", ";\n box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);\n }\n\n .locale-item {\n font-size: 16px;\n font-style: normal;\n font-stretch: normal;\n line-height: normal;\n letter-spacing: 2px;\n text-align: center;\n color: ", ";\n cursor: pointer;\n display: flex;\n padding: 16px;\n align-items: center;\n .check-icon {\n visibility: hidden;\n margin-right: 4px;\n }\n .check-icon-visible {\n visibility: visible;\n }\n }\n"])), props => (0, _Util.getColor)(props), props => (0, _Util.getBackground)(props), props => (0, _Util.getColor)(props));
154
+ const StyledPopper = (0, _Theme.styled)(_material.Popper)(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n z-index: ", ";\n"])), _ref2 => {
155
+ let {
156
+ theme
157
+ } = _ref2;
158
+ return theme.zIndex.tooltip + 10;
159
+ });
@@ -27,7 +27,7 @@ const translations = {
27
27
  member
28
28
  } = _ref;
29
29
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
30
- children: ["Use ", master, " account to connect ", member]
30
+ children: ["Connect ", member, " with ", master, " account"]
31
31
  });
32
32
  },
33
33
  connect: 'Connect Account',
@@ -72,6 +72,14 @@ function FederatedLoginDetecter(_ref3) {
72
72
  mode: userInfo ? 'auto' : 'manual'
73
73
  });
74
74
  }, [session, userInfo, _locale]);
75
+ let appLogoUrl;
76
+ if (siteInfo) {
77
+ appLogoUrl = new URL(siteInfo.appLogo, siteInfo.appUrl);
78
+ appLogoUrl.searchParams.set('imageFilter', 'resize');
79
+ // HACK: 保持跟其他地方使用的尺寸一致,可以复用同一资源的缓存,减少网络请求
80
+ appLogoUrl.searchParams.set('w', '80');
81
+ appLogoUrl.searchParams.set('h', '80');
82
+ }
75
83
  return siteInfo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_userPopper.default, {
76
84
  open: federatedLoginOpen,
77
85
  anchorEl: anchorEl,
@@ -86,7 +94,7 @@ function FederatedLoginDetecter(_ref3) {
86
94
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
87
95
  component: "img",
88
96
  mr: 2,
89
- src: "".concat(siteInfo.appUrl).concat(siteInfo.appLogo),
97
+ src: appLogoUrl.href,
90
98
  alt: siteInfo.appName,
91
99
  width: "30px",
92
100
  height: "30px"
@@ -10,15 +10,14 @@ var _material = require("@mui/material");
10
10
  var _PersonOutline = _interopRequireDefault(require("@mui/icons-material/PersonOutline"));
11
11
  var _Link = _interopRequireDefault(require("@mui/icons-material/Link"));
12
12
  var _VpnKeyOutlined = _interopRequireDefault(require("@mui/icons-material/VpnKeyOutlined"));
13
- var _ConnectWithoutContact = _interopRequireDefault(require("@mui/icons-material/ConnectWithoutContact"));
14
13
  var _ShieldCheck = _interopRequireDefault(require("mdi-material-ui/ShieldCheck"));
15
14
  var _Account = _interopRequireDefault(require("@arcblock/icons/lib/Account"));
16
15
  var _OpenIn = _interopRequireDefault(require("@arcblock/icons/lib/OpenIn"));
17
16
  var _Disconnect = _interopRequireDefault(require("@arcblock/icons/lib/Disconnect"));
18
17
  var _Switch = _interopRequireDefault(require("@arcblock/icons/lib/Switch"));
19
18
  var _useBrowser = _interopRequireDefault(require("@arcblock/react-hooks/lib/useBrowser"));
20
- var _isEmpty = _interopRequireDefault(require("lodash/isEmpty"));
21
19
  var _noop = _interopRequireDefault(require("lodash/noop"));
20
+ var _isEmpty = _interopRequireDefault(require("lodash/isEmpty"));
22
21
  var _Avatar = _interopRequireDefault(require("../Avatar"));
23
22
  var _Address = _interopRequireDefault(require("../Address"));
24
23
  var _Util = require("../Util");
@@ -39,7 +38,9 @@ function _objectWithoutProperties(source, excluded) { if (source == null) return
39
38
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
40
39
  const translations = {
41
40
  en: {
41
+ account: 'account',
42
42
  switchDid: 'Switch DID',
43
+ switchTo: 'Switch to',
43
44
  switchProfile: 'Switch Profile',
44
45
  switchPassport: 'Switch Passport',
45
46
  disconnect: 'Disconnect',
@@ -51,7 +52,9 @@ const translations = {
51
52
  connectedWith: 'Connected with'
52
53
  },
53
54
  zh: {
55
+ account: '账号',
54
56
  switchDid: '切换账户',
57
+ switchTo: '切换至',
55
58
  switchProfile: '切换用户信息',
56
59
  switchPassport: '切换通行证',
57
60
  disconnect: '退出',
@@ -145,6 +148,7 @@ function SessionManager(_ref) {
145
148
  // eslint-disable-next-line react/prop-types
146
149
  }, [session === null || session === void 0 ? void 0 : session.initialized, session === null || session === void 0 ? void 0 : session.loading]);
147
150
  const masterSiteInfo = (_window$blocklet = window.blocklet) === null || _window$blocklet === void 0 ? void 0 : (_window$blocklet$sett = _window$blocklet.settings) === null || _window$blocklet$sett === void 0 ? void 0 : (_window$blocklet$sett2 = _window$blocklet$sett.federated) === null || _window$blocklet$sett2 === void 0 ? void 0 : _window$blocklet$sett2.master;
151
+ const currentSiteInfo = window.blocklet;
148
152
  if (!session.user) {
149
153
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
150
154
  children: [showText ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Button, _objectSpread(_objectSpread({
@@ -223,7 +227,8 @@ function SessionManager(_ref) {
223
227
  args[_key] = arguments[_key];
224
228
  }
225
229
  logoutOAuth({
226
- session
230
+ session,
231
+ hack: true
227
232
  }, ...args).then(() => {
228
233
  onLogout(...args);
229
234
  }).catch(err => {
@@ -233,10 +238,28 @@ function SessionManager(_ref) {
233
238
  });
234
239
  });
235
240
  }
241
+ /**
242
+ * @name 切换账户
243
+ * @description 该功能仅在登录后才能使用,目前仅用于切换普通登录和统一登录的账户,所以会增加一些与统一登录相关的逻辑
244
+ */
236
245
  function _onSwitchDid() {
246
+ const {
247
+ provider,
248
+ user
249
+ } = session;
250
+ if (!user) return;
251
+ let targetProvider = provider;
252
+ if (provider === 'federated') {
253
+ targetProvider = 'wallet';
254
+ } else if (['auth0', 'wallet'].includes(provider)) {
255
+ targetProvider = 'federated';
256
+ }
237
257
  session.switchDid(function () {
238
258
  setUserOpen(false);
239
259
  onSwitchDid(...arguments);
260
+ }, {
261
+ provider: targetProvider,
262
+ providerMode: 'paramsFirst'
240
263
  });
241
264
  }
242
265
  function _onSwitchProfile() {
@@ -344,25 +367,6 @@ function SessionManager(_ref) {
344
367
  })
345
368
  })]
346
369
  })]
347
- }), federatedAccount && !(0, _isEmpty.default)(masterSiteInfo) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.MenuItem, {
348
- className: "session-manager-menu-item",
349
- "data-cy": "sessionManager-connectWithFederated",
350
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Box, {
351
- overflow: "hidden",
352
- textOverflow: "ellipsis",
353
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.SvgIcon, {
354
- component: _ConnectWithoutContact.default,
355
- className: "session-manager-menu-icon"
356
- }), translation.connectedWith, /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Link, {
357
- ml: 1,
358
- href: masterSiteInfo.appUrl,
359
- underline: "hover",
360
- target: "_blank",
361
- title: masterSiteInfo.appName,
362
- "aria-label": "Open federated master site url",
363
- children: masterSiteInfo.appName
364
- })]
365
- })
366
370
  }), Array.isArray(menu) && menu.map((menuItem, index) => {
367
371
  const {
368
372
  svgIcon
@@ -395,7 +399,7 @@ function SessionManager(_ref) {
395
399
  component: _OpenIn.default,
396
400
  className: "session-manager-menu-icon"
397
401
  }), translation.openInWallet]
398
- }), !!switchDid && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.MenuItem, {
402
+ }), !(0, _isEmpty.default)(masterSiteInfo) && !!switchDid && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.MenuItem, {
399
403
  className: "session-manager-menu-item",
400
404
  onClick: _onSwitchDid,
401
405
  "aria-label": translation.switchDid,
@@ -403,7 +407,29 @@ function SessionManager(_ref) {
403
407
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.SvgIcon, {
404
408
  component: _Switch.default,
405
409
  className: "session-manager-menu-icon"
406
- }), translation.switchDid]
410
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Box, {
411
+ sx: {
412
+ whiteSpace: 'normal',
413
+ wordBreak: 'break-all'
414
+ },
415
+ children: [translation.switchTo, session.provider === 'federated' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Link, {
416
+ mx: 1,
417
+ href: currentSiteInfo.appUrl,
418
+ underline: "hover",
419
+ target: "_blank",
420
+ title: currentSiteInfo.appName,
421
+ "aria-label": "Open current site url",
422
+ children: currentSiteInfo.appName
423
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Link, {
424
+ mx: 1,
425
+ href: masterSiteInfo.appUrl,
426
+ underline: "hover",
427
+ target: "_blank",
428
+ title: masterSiteInfo.appName,
429
+ "aria-label": "Open federated master site url",
430
+ children: masterSiteInfo.appName
431
+ }), translation.account]
432
+ })]
407
433
  }), !!switchProfile && hasBindWallet && session.provider !== 'federated' && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.MenuItem, {
408
434
  className: "session-manager-menu-item",
409
435
  onClick: _onSwitchProfile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.7.13",
3
+ "version": "2.7.15",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -318,11 +318,11 @@
318
318
  "peerDependencies": {
319
319
  "react": ">=18.1.0"
320
320
  },
321
- "gitHead": "8e85f20d1c7a24261811c482cd763065fb2e422a",
321
+ "gitHead": "a40ed26cfd0cbf892b00f98c773eff8ad7a50570",
322
322
  "dependencies": {
323
323
  "@arcblock/did-motif": "^1.1.13",
324
- "@arcblock/icons": "^2.7.13",
325
- "@arcblock/react-hooks": "^2.7.13",
324
+ "@arcblock/icons": "^2.7.15",
325
+ "@arcblock/react-hooks": "^2.7.15",
326
326
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
327
327
  "@emotion/react": "^11.10.4",
328
328
  "@emotion/styled": "^11.10.4",
@@ -54,6 +54,18 @@ export default function CardSelector({ list, width, height, cardSpace, onSelect,
54
54
  <Contianer ref={outterCon} onTouchStart={touchstart} onTouchEnd={touchend}>
55
55
  <div className="card-container" style={{ transform: `translate(${-translateX}px, 0)` }}>
56
56
  {list.map((e, i) => {
57
+ if (e instanceof Function) {
58
+ return (
59
+ <div
60
+ className={`card-item ${i === selectedId ? 'selected' : ''}`}
61
+ style={{ width, height, margin: cardSpace / 2 }}
62
+ // eslint-disable-next-line react/no-array-index-key
63
+ key={i}
64
+ onClick={() => selectedItem(i)}>
65
+ {e(i)}
66
+ </div>
67
+ );
68
+ }
57
69
  return (
58
70
  <div
59
71
  className={`card-item ${i === selectedId ? 'selected' : ''}`}
@@ -86,7 +98,8 @@ const Contianer = styled.div`
86
98
  align-items: center;
87
99
  flex-shrink: 0;
88
100
  cursor: pointer;
89
- img {
101
+ img,
102
+ svg {
90
103
  max-width: 100%;
91
104
  max-height: 100%;
92
105
  width: auto;
@@ -97,7 +110,8 @@ const Contianer = styled.div`
97
110
  }
98
111
  &.selected {
99
112
  cursor: default;
100
- img {
113
+ img,
114
+ svg {
101
115
  outline: #526ded solid 5px;
102
116
  }
103
117
  }
@@ -1,4 +1,9 @@
1
1
  import PropTypes from 'prop-types';
2
+ import { useContext, forwardRef, useRef, useImperativeHandle } from 'react';
3
+ import { useMemoizedFn, useReactive } from 'ahooks';
4
+ import noop from 'lodash/noop';
5
+
6
+ import { LocaleContext } from '../Locale/context';
2
7
  import Button from '../Button';
3
8
  import Dialog from './dialog';
4
9
 
@@ -12,7 +17,7 @@ import Dialog from './dialog';
12
17
  @property {boolean} [showCancelButton=true]
13
18
  @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [confirmButton={text: 'Confirm'}]
14
19
  @property {{text: string, props?: import('../Button/wrap').ButtonProps}} [cancelButton={text: 'Cancel'}]
15
- @property {import('@mui/material').PaperProps} [PaperProps={}]
20
+ @property {import('@mui/material').PaperProps} [PaperProps={}]
16
21
  */
17
22
 
18
23
  // 注意排在 {...rest} 之后的 props 优先级更高
@@ -91,3 +96,103 @@ Confirm.defaultProps = {
91
96
  },
92
97
  PaperProps: {},
93
98
  };
99
+
100
+ const ConfirmHolder = forwardRef((props, ref) => {
101
+ const { t } = useContext(LocaleContext);
102
+
103
+ const state = useReactive({
104
+ show: false,
105
+ title: '',
106
+ content: '',
107
+ onConfirm: noop,
108
+ onCancel: noop,
109
+ loading: false,
110
+ });
111
+ const open = useMemoizedFn((params = {}) => {
112
+ state.show = true;
113
+ state.title = params.title;
114
+ state.content = params.content;
115
+ state.onConfirm = params.onConfirm || noop;
116
+ state.onCancel = params.onCancel || noop;
117
+ state.loading = false;
118
+ });
119
+ const reset = useMemoizedFn(() => {
120
+ state.title = '';
121
+ state.content = '';
122
+ state.onConfirm = noop;
123
+ state.onCancel = noop;
124
+ });
125
+ const close = useMemoizedFn(() => {
126
+ state.show = false;
127
+ setTimeout(() => {
128
+ reset();
129
+ }, 300);
130
+ });
131
+ const onCancel = useMemoizedFn(() => {
132
+ close();
133
+ state?.onCancel();
134
+ }, []);
135
+ const onConfirm = useMemoizedFn(async () => {
136
+ state.loading = true;
137
+ try {
138
+ await state?.onConfirm(close);
139
+ } finally {
140
+ state.loading = false;
141
+ }
142
+ }, []);
143
+ useImperativeHandle(
144
+ ref,
145
+ () => {
146
+ return {
147
+ open,
148
+ close,
149
+ };
150
+ },
151
+ [open, close]
152
+ );
153
+
154
+ return (
155
+ <Confirm
156
+ open={state.show}
157
+ title={state.title}
158
+ onConfirm={onConfirm}
159
+ onCancel={onCancel}
160
+ confirmButton={{
161
+ text: t('common.confirm'),
162
+ props: {
163
+ variant: 'contained',
164
+ color: 'primary',
165
+ loading: state.loading,
166
+ },
167
+ }}
168
+ cancelButton={{
169
+ text: t('common.cancel'),
170
+ props: {
171
+ variant: 'outlined',
172
+ color: 'primary',
173
+ },
174
+ }}>
175
+ {state.content}
176
+ </Confirm>
177
+ );
178
+ });
179
+
180
+ export function useConfirm() {
181
+ const confirmRef = useRef(null);
182
+
183
+ const open = useMemoizedFn((...args) => {
184
+ confirmRef.current?.open(...args);
185
+ });
186
+ const close = useMemoizedFn((...args) => {
187
+ confirmRef.current?.close(...args);
188
+ });
189
+ const confirmApi = {
190
+ open,
191
+ close,
192
+ };
193
+
194
+ return {
195
+ confirmHolder: <ConfirmHolder ref={confirmRef} />,
196
+ confirmApi,
197
+ };
198
+ }
@@ -1,3 +1,4 @@
1
1
  // eslint-disable-next-line no-restricted-exports
2
2
  export { default } from './dialog';
3
3
  export { default as Confirm } from './confirm';
4
+ export { useConfirm } from './confirm';
@@ -1,14 +1,7 @@
1
1
  /* eslint-disable react/jsx-no-bind */
2
2
  import { useState, useContext, useRef, useMemo } from 'react';
3
3
  import PropTypes from 'prop-types';
4
- import Button from '@mui/material/Button';
5
- import Typography from '@mui/material/Typography';
6
- import IconButton from '@mui/material/IconButton';
7
- import ClickAwayListener from '@mui/material/ClickAwayListener';
8
- import Popper from '@mui/material/Popper';
9
- import MenuItem from '@mui/material/MenuItem';
10
- import MenuList from '@mui/material/MenuList';
11
- import Box from '@mui/material/Box';
4
+ import { Button, Typography, IconButton, Popper, MenuItem, MenuList, Box, ClickAwayListener } from '@mui/material';
12
5
  import CheckIcon from '@mui/icons-material/Check';
13
6
  import GlobeIcon from '@arcblock/icons/lib/Globe';
14
7
 
@@ -82,7 +75,7 @@ export default function LocaleSelector(props) {
82
75
  </Box>
83
76
  </ButtonComponent>
84
77
 
85
- <Popper open={open} anchorEl={anchorEl.current} {...popperProps} disablePortal>
78
+ <StyledPopper open={open} anchorEl={anchorEl.current} {...popperProps} disablePortal>
86
79
  <div className="locales">
87
80
  <ClickAwayListener onClickAway={onClose}>
88
81
  <MenuList>
@@ -98,7 +91,7 @@ export default function LocaleSelector(props) {
98
91
  </MenuList>
99
92
  </ClickAwayListener>
100
93
  </div>
101
- </Popper>
94
+ </StyledPopper>
102
95
  </Div>
103
96
  );
104
97
  }
@@ -166,3 +159,9 @@ const Div = styled('div', {
166
159
  }
167
160
  }
168
161
  `;
162
+
163
+ const StyledPopper = styled(Popper)`
164
+ z-index: ${({ theme }) => {
165
+ return theme.zIndex.tooltip + 10;
166
+ }};
167
+ `;
@@ -18,7 +18,7 @@ const translations = {
18
18
  useToConnect({ master, member }) {
19
19
  return (
20
20
  <>
21
- Use {master} account to connect {member}
21
+ Connect {member} with {master} account
22
22
  </>
23
23
  );
24
24
  },
@@ -63,6 +63,15 @@ export default function FederatedLoginDetecter({ session, anchorEl, dark, locale
63
63
  );
64
64
  }, [session, userInfo, _locale]);
65
65
 
66
+ let appLogoUrl;
67
+ if (siteInfo) {
68
+ appLogoUrl = new URL(siteInfo.appLogo, siteInfo.appUrl);
69
+ appLogoUrl.searchParams.set('imageFilter', 'resize');
70
+ // HACK: 保持跟其他地方使用的尺寸一致,可以复用同一资源的缓存,减少网络请求
71
+ appLogoUrl.searchParams.set('w', '80');
72
+ appLogoUrl.searchParams.set('h', '80');
73
+ }
74
+
66
75
  return (
67
76
  siteInfo && (
68
77
  <UserPopper
@@ -74,14 +83,7 @@ export default function FederatedLoginDetecter({ session, anchorEl, dark, locale
74
83
  <Box p={2}>
75
84
  {siteInfo && (
76
85
  <Box display="flex" alignItems="center">
77
- <Box
78
- component="img"
79
- mr={2}
80
- src={`${siteInfo.appUrl}${siteInfo.appLogo}`}
81
- alt={siteInfo.appName}
82
- width="30px"
83
- height="30px"
84
- />
86
+ <Box component="img" mr={2} src={appLogoUrl.href} alt={siteInfo.appName} width="30px" height="30px" />
85
87
  <Box sx={{ maxWidth: '260px' }}>
86
88
  {translations[locale].useToConnect({
87
89
  master: (
@@ -6,15 +6,14 @@ import { Box, IconButton, MenuList, MenuItem, SvgIcon, Button, Chip, Link, Circu
6
6
  import SwitchProfileIcon from '@mui/icons-material/PersonOutline';
7
7
  import BindWalletIcon from '@mui/icons-material/Link';
8
8
  import SwitchPassportIcon from '@mui/icons-material/VpnKeyOutlined';
9
- import ConnectWithoutContactIcon from '@mui/icons-material/ConnectWithoutContact';
10
9
  import ShieldCheck from 'mdi-material-ui/ShieldCheck';
11
10
  import AccountIcon from '@arcblock/icons/lib/Account';
12
11
  import OpenInIcon from '@arcblock/icons/lib/OpenIn';
13
12
  import DisconnectIcon from '@arcblock/icons/lib/Disconnect';
14
13
  import SwitchDidIcon from '@arcblock/icons/lib/Switch';
15
14
  import useBrowser from '@arcblock/react-hooks/lib/useBrowser';
16
- import isEmpty from 'lodash/isEmpty';
17
15
  import noop from 'lodash/noop';
16
+ import isEmpty from 'lodash/isEmpty';
18
17
 
19
18
  import DidAvatar from '../Avatar';
20
19
  import DidAddress from '../Address';
@@ -24,7 +23,9 @@ import UserPopper from './user-popper';
24
23
 
25
24
  const translations = {
26
25
  en: {
26
+ account: 'account',
27
27
  switchDid: 'Switch DID',
28
+ switchTo: 'Switch to',
28
29
  switchProfile: 'Switch Profile',
29
30
  switchPassport: 'Switch Passport',
30
31
  disconnect: 'Disconnect',
@@ -36,7 +37,9 @@ const translations = {
36
37
  connectedWith: 'Connected with',
37
38
  },
38
39
  zh: {
40
+ account: '账号',
39
41
  switchDid: '切换账户',
42
+ switchTo: '切换至',
40
43
  switchProfile: '切换用户信息',
41
44
  switchPassport: '切换通行证',
42
45
  disconnect: '退出',
@@ -118,6 +121,7 @@ function SessionManager({
118
121
  }, [session?.initialized, session?.loading]);
119
122
 
120
123
  const masterSiteInfo = window.blocklet?.settings?.federated?.master;
124
+ const currentSiteInfo = window.blocklet;
121
125
 
122
126
  if (!session.user) {
123
127
  return (
@@ -177,7 +181,7 @@ function SessionManager({
177
181
  }
178
182
  function _onLogout() {
179
183
  session.logout((...args) => {
180
- logoutOAuth({ session }, ...args)
184
+ logoutOAuth({ session, hack: true }, ...args)
181
185
  .then(() => {
182
186
  onLogout(...args);
183
187
  })
@@ -189,11 +193,29 @@ function SessionManager({
189
193
  });
190
194
  });
191
195
  }
196
+ /**
197
+ * @name 切换账户
198
+ * @description 该功能仅在登录后才能使用,目前仅用于切换普通登录和统一登录的账户,所以会增加一些与统一登录相关的逻辑
199
+ */
192
200
  function _onSwitchDid() {
193
- session.switchDid((...args) => {
194
- setUserOpen(false);
195
- onSwitchDid(...args);
196
- });
201
+ const { provider, user } = session;
202
+ if (!user) return;
203
+ let targetProvider = provider;
204
+ if (provider === 'federated') {
205
+ targetProvider = 'wallet';
206
+ } else if (['auth0', 'wallet'].includes(provider)) {
207
+ targetProvider = 'federated';
208
+ }
209
+ session.switchDid(
210
+ (...args) => {
211
+ setUserOpen(false);
212
+ onSwitchDid(...args);
213
+ },
214
+ {
215
+ provider: targetProvider,
216
+ providerMode: 'paramsFirst',
217
+ }
218
+ );
197
219
  }
198
220
  function _onSwitchProfile() {
199
221
  session.switchProfile((...args) => {
@@ -274,23 +296,6 @@ function SessionManager({
274
296
  )}
275
297
  </div>
276
298
  </div>
277
- {federatedAccount && !isEmpty(masterSiteInfo) && (
278
- <MenuItem className="session-manager-menu-item" data-cy="sessionManager-connectWithFederated">
279
- <Box overflow="hidden" textOverflow="ellipsis">
280
- <SvgIcon component={ConnectWithoutContactIcon} className="session-manager-menu-icon" />
281
- {translation.connectedWith}
282
- <Link
283
- ml={1}
284
- href={masterSiteInfo.appUrl}
285
- underline="hover"
286
- target="_blank"
287
- title={masterSiteInfo.appName}
288
- aria-label="Open federated master site url">
289
- {masterSiteInfo.appName}
290
- </Link>
291
- </Box>
292
- </MenuItem>
293
- )}
294
299
  {Array.isArray(menu) &&
295
300
  menu.map((menuItem, index) => {
296
301
  const { svgIcon, ...menuProps } = menuItem;
@@ -328,14 +333,38 @@ function SessionManager({
328
333
  {translation.openInWallet}
329
334
  </MenuItem>
330
335
  )}
331
- {!!switchDid && (
336
+ {!isEmpty(masterSiteInfo) && !!switchDid && (
332
337
  <MenuItem
333
338
  className="session-manager-menu-item"
334
339
  onClick={_onSwitchDid}
335
340
  aria-label={translation.switchDid}
336
341
  data-cy="sessionManager-switch-trigger">
337
342
  <SvgIcon component={SwitchDidIcon} className="session-manager-menu-icon" />
338
- {translation.switchDid}
343
+ <Box sx={{ whiteSpace: 'normal', wordBreak: 'break-all' }}>
344
+ {translation.switchTo}
345
+ {session.provider === 'federated' ? (
346
+ <Link
347
+ mx={1}
348
+ href={currentSiteInfo.appUrl}
349
+ underline="hover"
350
+ target="_blank"
351
+ title={currentSiteInfo.appName}
352
+ aria-label="Open current site url">
353
+ {currentSiteInfo.appName}
354
+ </Link>
355
+ ) : (
356
+ <Link
357
+ mx={1}
358
+ href={masterSiteInfo.appUrl}
359
+ underline="hover"
360
+ target="_blank"
361
+ title={masterSiteInfo.appName}
362
+ aria-label="Open federated master site url">
363
+ {masterSiteInfo.appName}
364
+ </Link>
365
+ )}
366
+ {translation.account}
367
+ </Box>
339
368
  </MenuItem>
340
369
  )}
341
370
  {/* NOTE: federated 登录方式不允许切换 profile */}
@@ -71,7 +71,9 @@ UserPopper.defaultProps = {
71
71
  };
72
72
 
73
73
  const StyledPopper = styled(Popper)`
74
- z-index: ${({ theme }) => theme.zIndex.tooltip};
74
+ z-index: ${({ theme }) => {
75
+ return theme.zIndex.tooltip;
76
+ }};
75
77
  .MuiList-root {
76
78
  /* HACK: 需要288px 才能将 did 展示完整 */
77
79
  width: 290px;
File without changes