@arcblock/ux 2.7.15 → 2.7.17

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 (57) hide show
  1. package/es/Dialog/confirm.js +10 -8
  2. package/es/Img/index.js +7 -7
  3. package/es/SessionManager/account-item.js +133 -0
  4. package/es/SessionManager/add-account-item.js +100 -0
  5. package/es/SessionManager/federated-login-detecter.js +37 -33
  6. package/es/SessionManager/index.js +119 -259
  7. package/es/SessionManager/manage-accounts.js +156 -0
  8. package/es/SessionManager/manage-blocklet.js +70 -0
  9. package/es/SessionManager/menu-accordion.js +104 -0
  10. package/es/SessionManager/translation.js +52 -0
  11. package/es/SessionManager/use-config.js +34 -0
  12. package/es/SessionManager/user-info.js +147 -0
  13. package/es/SessionManager/user-popper.js +10 -53
  14. package/es/SessionManager/utils.js +2 -0
  15. package/es/Typography/index.js +89 -0
  16. package/es/Util/federated.js +65 -0
  17. package/es/Util/index.js +7 -0
  18. package/lib/Dialog/confirm.js +9 -7
  19. package/lib/Img/index.js +7 -7
  20. package/lib/SessionManager/account-item.js +141 -0
  21. package/lib/SessionManager/add-account-item.js +108 -0
  22. package/lib/SessionManager/federated-login-detecter.js +38 -33
  23. package/lib/SessionManager/index.js +122 -272
  24. package/lib/SessionManager/manage-accounts.js +168 -0
  25. package/lib/SessionManager/manage-blocklet.js +86 -0
  26. package/lib/SessionManager/menu-accordion.js +112 -0
  27. package/lib/SessionManager/translation.js +59 -0
  28. package/lib/SessionManager/use-config.js +41 -0
  29. package/lib/SessionManager/user-info.js +163 -0
  30. package/lib/SessionManager/user-popper.js +8 -8
  31. package/lib/SessionManager/utils.js +16 -0
  32. package/lib/Typography/index.js +100 -0
  33. package/lib/Util/federated.js +85 -0
  34. package/lib/Util/index.js +11 -2
  35. package/package.json +12 -5
  36. package/src/Dialog/confirm.js +9 -6
  37. package/src/Img/index.js +5 -5
  38. package/src/SessionManager/account-item.jsx +109 -0
  39. package/src/SessionManager/add-account-item.jsx +97 -0
  40. package/src/SessionManager/federated-login-detecter.jsx +42 -29
  41. package/src/SessionManager/index.jsx +131 -259
  42. package/src/SessionManager/manage-accounts.jsx +157 -0
  43. package/src/SessionManager/manage-blocklet.jsx +70 -0
  44. package/src/SessionManager/menu-accordion.jsx +94 -0
  45. package/src/SessionManager/translation.js +52 -0
  46. package/src/SessionManager/use-config.js +33 -0
  47. package/src/SessionManager/user-info.jsx +116 -0
  48. package/src/SessionManager/user-popper.jsx +6 -51
  49. package/src/SessionManager/utils.js +3 -0
  50. package/src/Typography/index.jsx +79 -0
  51. package/src/Util/federated.js +73 -0
  52. package/src/Util/index.js +8 -0
  53. /package/src/Avatar/{did-motif.js → did-motif.jsx} +0 -0
  54. /package/src/Avatar/{index.js → index.jsx} +0 -0
  55. /package/src/Header/{auto-hidden.js → auto-hidden.jsx} +0 -0
  56. /package/src/Header/{header.js → header.jsx} +0 -0
  57. /package/src/Header/{responsive-header.js → responsive-header.jsx} +0 -0
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getSourceProvider = exports.getConnectedAccounts = void 0;
7
+ const getSourceProvider = user => {
8
+ var _user$extraConfigs;
9
+ return (user === null || user === void 0 ? void 0 : user.sourceProvider) || (user === null || user === void 0 ? void 0 : (_user$extraConfigs = user.extraConfigs) === null || _user$extraConfigs === void 0 ? void 0 : _user$extraConfigs.sourceProvider) || 'wallet';
10
+ };
11
+ exports.getSourceProvider = getSourceProvider;
12
+ const getConnectedAccounts = user => {
13
+ var _user$extraConfigs2;
14
+ return (user === null || user === void 0 ? void 0 : user.connectedAccounts) || (user === null || user === void 0 ? void 0 : (_user$extraConfigs2 = user.extraConfigs) === null || _user$extraConfigs2 === void 0 ? void 0 : _user$extraConfigs2.connectedAccounts) || [];
15
+ };
16
+ exports.getConnectedAccounts = getConnectedAccounts;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = Typography;
7
+ var _propTypes = _interopRequireDefault(require("prop-types"));
8
+ var _material = require("@mui/material");
9
+ var _ahooks = require("ahooks");
10
+ var _react = require("react");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ const _excluded = ["minFontSize", "fontSize", "children", "sx"];
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
15
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
16
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
17
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
18
+ function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
19
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
20
+ 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; }
21
+ function Typography(_ref) {
22
+ let {
23
+ minFontSize,
24
+ fontSize,
25
+ children,
26
+ sx
27
+ } = _ref,
28
+ rest = _objectWithoutProperties(_ref, _excluded);
29
+ const refMock = (0, _react.useRef)(null);
30
+ const refContainer = (0, _react.useRef)(null);
31
+ const state = (0, _ahooks.useReactive)({
32
+ fontSize,
33
+ loading: true,
34
+ initialSize: undefined
35
+ });
36
+ const mockSize = (0, _ahooks.useSize)(refMock.current);
37
+ const containerSize = (0, _ahooks.useSize)(refContainer.current);
38
+ (0, _react.useEffect)(() => {
39
+ if (state.loading) {
40
+ if (fontSize === 'auto') {
41
+ if (mockSize && !state.initialSize) {
42
+ const styleSize = getComputedStyle(refMock.current).fontSize;
43
+ state.initialSize = Number(styleSize.replace('px', ''));
44
+ state.fontSize = state.initialSize;
45
+ }
46
+ if (containerSize && mockSize) {
47
+ if (containerSize.width < mockSize.width && state.fontSize > minFontSize) {
48
+ state.fontSize--;
49
+ } else {
50
+ state.loading = false;
51
+ }
52
+ }
53
+ } else {
54
+ state.loading = false;
55
+ }
56
+ }
57
+ // eslint-disable-next-line react-hooks/exhaustive-deps
58
+ }, [fontSize, mockSize === null || mockSize === void 0 ? void 0 : mockSize.width, containerSize === null || containerSize === void 0 ? void 0 : containerSize.width]);
59
+ return state.loading ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Box, {
60
+ ref: refContainer,
61
+ flex: 1,
62
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, _objectSpread(_objectSpread({}, rest), {}, {
63
+ sx: sx,
64
+ noWrap: true,
65
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Skeleton, {
66
+ variant: "text",
67
+ sx: {
68
+ fontSize: '1rem'
69
+ }
70
+ })
71
+ })), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, _objectSpread(_objectSpread({
72
+ ref: refMock
73
+ }, rest), {}, {
74
+ sx: _objectSpread(_objectSpread({}, sx), {}, {
75
+ fontSize: "".concat(state.fontSize, "px !important"),
76
+ position: 'fixed',
77
+ top: -1000,
78
+ left: -1000
79
+ }),
80
+ noWrap: true,
81
+ children: children
82
+ }))]
83
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, _objectSpread(_objectSpread({}, rest), {}, {
84
+ sx: _objectSpread(_objectSpread({}, sx), {}, {
85
+ fontSize: "".concat(state.fontSize, "px !important")
86
+ }),
87
+ children: children
88
+ }));
89
+ }
90
+ Typography.propTypes = {
91
+ fontSize: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
92
+ children: _propTypes.default.any.isRequired,
93
+ minFontSize: _propTypes.default.number,
94
+ sx: _propTypes.default.object
95
+ };
96
+ Typography.defaultProps = {
97
+ fontSize: undefined,
98
+ minFontSize: 12,
99
+ sx: {}
100
+ };
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getAutoLoginFederated = getAutoLoginFederated;
7
+ exports.getConfig = getConfig;
8
+ exports.getCurrentApp = getCurrentApp;
9
+ exports.getFederatedApp = getFederatedApp;
10
+ exports.getMaster = getMaster;
11
+ exports.getSourceAppPid = getSourceAppPid;
12
+ var _isEmpty = _interopRequireDefault(require("lodash/isEmpty"));
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+ function getMaster() {
15
+ var _blocklet$settings;
16
+ let blocklet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.blocklet;
17
+ const federated = (blocklet === null || blocklet === void 0 ? void 0 : (_blocklet$settings = blocklet.settings) === null || _blocklet$settings === void 0 ? void 0 : _blocklet$settings.federated) || {};
18
+ return federated.master;
19
+ }
20
+ function getConfig() {
21
+ var _blocklet$settings2;
22
+ let blocklet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.blocklet;
23
+ const federated = (blocklet === null || blocklet === void 0 ? void 0 : (_blocklet$settings2 = blocklet.settings) === null || _blocklet$settings2 === void 0 ? void 0 : _blocklet$settings2.federated) || {};
24
+ return federated.config;
25
+ }
26
+ function getAutoLoginFederated() {
27
+ let blocklet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.blocklet;
28
+ const config = getConfig(blocklet);
29
+ return Boolean(config === null || config === void 0 ? void 0 : config.autoLogin) && (config === null || config === void 0 ? void 0 : config.status) === 'approved';
30
+ }
31
+ function getSourceAppPid() {
32
+ let blocklet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.blocklet;
33
+ const master = getMaster(blocklet);
34
+ return master === null || master === void 0 ? void 0 : master.appPid;
35
+ }
36
+ function getFederatedApp() {
37
+ let blocklet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.blocklet;
38
+ const master = getMaster(blocklet);
39
+ const isFederatedMode = !(0, _isEmpty.default)(master);
40
+ return isFederatedMode ? {
41
+ appId: master.appId,
42
+ appName: master.appName,
43
+ appDescription: master.appDescription,
44
+ appLogo: master.appLogo,
45
+ appPid: master.appPid,
46
+ appUrl: master.appUrl,
47
+ version: master.version,
48
+ sourceAppPid: master.appPid,
49
+ provider: 'wallet'
50
+ } : null;
51
+ }
52
+ function getCurrentApp() {
53
+ let blocklet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.blocklet;
54
+ // 适用于 blocklet 项目
55
+ if (blocklet) {
56
+ return {
57
+ appId: blocklet.appId,
58
+ appName: blocklet.appName,
59
+ appDescription: blocklet.appDescription,
60
+ appLogo: blocklet.appLogo,
61
+ appPid: blocklet.appPid,
62
+ appUrl: blocklet.appUrl,
63
+ version: blocklet.version,
64
+ // NOTICE: null 代表该值置空
65
+ sourceAppPid: null,
66
+ provider: 'wallet'
67
+ };
68
+ }
69
+ // HACK: 适用于 blockelt-server
70
+ if (window.env) {
71
+ // eslint-disable-next-line no-param-reassign
72
+ blocklet = window.env;
73
+ return {
74
+ appId: blocklet.appId,
75
+ appName: blocklet.appName,
76
+ appDescription: blocklet.appDescription,
77
+ appUrl: blocklet.baseUrl,
78
+ // NOTICE: null 代表该值置空
79
+ sourceAppPid: null,
80
+ provider: 'wallet',
81
+ type: 'server'
82
+ };
83
+ }
84
+ return null;
85
+ }
package/lib/Util/index.js CHANGED
@@ -16,7 +16,7 @@ exports.mergeProps = mergeProps;
16
16
  exports.openWebWallet = openWebWallet;
17
17
  exports.parseQuery = parseQuery;
18
18
  exports.setDateTool = setDateTool;
19
- exports.str2color = void 0;
19
+ exports.str2color = exports.sleep = void 0;
20
20
  exports.stringifyQuery = stringifyQuery;
21
21
  var _padStart = _interopRequireDefault(require("lodash/padStart"));
22
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -339,4 +339,13 @@ const getUserAvatar = function getUserAvatar(avatar) {
339
339
  }
340
340
  return avatar;
341
341
  };
342
- exports.getUserAvatar = getUserAvatar;
342
+ exports.getUserAvatar = getUserAvatar;
343
+ const sleep = function sleep() {
344
+ let time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
345
+ return new Promise(resolve => {
346
+ setTimeout(() => {
347
+ resolve();
348
+ }, time);
349
+ });
350
+ };
351
+ exports.sleep = sleep;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.7.15",
3
+ "version": "2.7.17",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -277,6 +277,10 @@
277
277
  "import": "./es/Toast/index.js",
278
278
  "require": "./lib/Toast/index.js"
279
279
  },
280
+ "./lib/Typography": {
281
+ "import": "./es/Typography/index.js",
282
+ "require": "./lib/Typography/index.js"
283
+ },
280
284
  "./lib/Util": {
281
285
  "import": "./es/Util/index.js",
282
286
  "require": "./lib/Util/index.js"
@@ -318,16 +322,19 @@
318
322
  "peerDependencies": {
319
323
  "react": ">=18.1.0"
320
324
  },
321
- "gitHead": "a40ed26cfd0cbf892b00f98c773eff8ad7a50570",
325
+ "gitHead": "3a169b96cef38680f727a9d0aa0dc4588eaf85fd",
322
326
  "dependencies": {
323
327
  "@arcblock/did-motif": "^1.1.13",
324
- "@arcblock/icons": "^2.7.15",
325
- "@arcblock/react-hooks": "^2.7.15",
328
+ "@arcblock/icons": "^2.7.17",
329
+ "@arcblock/react-hooks": "^2.7.17",
326
330
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
327
331
  "@emotion/react": "^11.10.4",
328
332
  "@emotion/styled": "^11.10.4",
329
333
  "@fontsource/lato": "^4.5.10",
330
334
  "@fontsource/ubuntu-mono": "^4.5.11",
335
+ "@iconify-icons/ion": "^1.2.10",
336
+ "@iconify-icons/mdi": "^1.2.47",
337
+ "@iconify/react": "^4.1.1",
331
338
  "@mui/icons-material": "^5.10.6",
332
339
  "@mui/material": "^5.10.8",
333
340
  "@solana/qr-code-styling": "^1.6.0-beta.0",
@@ -341,10 +348,10 @@
341
348
  "dayjs": "^1.11.5",
342
349
  "devices.css": "^0.1.15",
343
350
  "highlight.js": "^11.6.0",
351
+ "iconify-icon": "^1.0.8",
344
352
  "is-svg": "^4.3.2",
345
353
  "js-cookie": "^2.2.1",
346
354
  "lodash": "^4.17.21",
347
- "mdi-material-ui": "^7.5.0",
348
355
  "mui-datatables": "^4.2.2",
349
356
  "notistack": "^2.0.5",
350
357
  "pako": "^2.1.0",
@@ -1,9 +1,8 @@
1
1
  import PropTypes from 'prop-types';
2
- import { useContext, forwardRef, useRef, useImperativeHandle } from 'react';
2
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
3
3
  import { useMemoizedFn, useReactive } from 'ahooks';
4
4
  import noop from 'lodash/noop';
5
5
 
6
- import { LocaleContext } from '../Locale/context';
7
6
  import Button from '../Button';
8
7
  import Dialog from './dialog';
9
8
 
@@ -98,8 +97,6 @@ Confirm.defaultProps = {
98
97
  };
99
98
 
100
99
  const ConfirmHolder = forwardRef((props, ref) => {
101
- const { t } = useContext(LocaleContext);
102
-
103
100
  const state = useReactive({
104
101
  show: false,
105
102
  title: '',
@@ -107,6 +104,8 @@ const ConfirmHolder = forwardRef((props, ref) => {
107
104
  onConfirm: noop,
108
105
  onCancel: noop,
109
106
  loading: false,
107
+ confirmButtonText: 'Confirm',
108
+ cancelButtonText: 'Cancel',
110
109
  });
111
110
  const open = useMemoizedFn((params = {}) => {
112
111
  state.show = true;
@@ -114,6 +113,8 @@ const ConfirmHolder = forwardRef((props, ref) => {
114
113
  state.content = params.content;
115
114
  state.onConfirm = params.onConfirm || noop;
116
115
  state.onCancel = params.onCancel || noop;
116
+ if (params.confirmButtonText) state.confirmButtonText = params.confirmButtonText;
117
+ if (params.cancelButtonText) state.cancelButtonText = params.cancelButtonText;
117
118
  state.loading = false;
118
119
  });
119
120
  const reset = useMemoizedFn(() => {
@@ -121,6 +122,8 @@ const ConfirmHolder = forwardRef((props, ref) => {
121
122
  state.content = '';
122
123
  state.onConfirm = noop;
123
124
  state.onCancel = noop;
125
+ state.confirmButtonText = 'Confirm';
126
+ state.cancelButtonText = 'Cancel';
124
127
  });
125
128
  const close = useMemoizedFn(() => {
126
129
  state.show = false;
@@ -158,7 +161,7 @@ const ConfirmHolder = forwardRef((props, ref) => {
158
161
  onConfirm={onConfirm}
159
162
  onCancel={onCancel}
160
163
  confirmButton={{
161
- text: t('common.confirm'),
164
+ text: state.confirmButtonText,
162
165
  props: {
163
166
  variant: 'contained',
164
167
  color: 'primary',
@@ -166,7 +169,7 @@ const ConfirmHolder = forwardRef((props, ref) => {
166
169
  },
167
170
  }}
168
171
  cancelButton={{
169
- text: t('common.cancel'),
172
+ text: state.cancelButtonText,
170
173
  props: {
171
174
  variant: 'outlined',
172
175
  color: 'primary',
package/src/Img/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { useEffect, useMemo, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import SvgIcon from '@mui/material/SvgIcon';
4
3
  import { useInView } from 'react-intersection-observer';
5
- import Alert from 'mdi-material-ui/Alert';
6
- import ImageIcon from 'mdi-material-ui/Image';
4
+ import AlertIcon from '@iconify-icons/mdi/alert';
5
+ import ImageIcon from '@iconify-icons/mdi/image';
6
+ import { Icon } from '@iconify/react';
7
7
  import { styled } from '../Theme';
8
8
 
9
9
  /**
@@ -160,12 +160,12 @@ function Img({
160
160
  <div className={`image ${className} ${classes.root}`} style={mergedStyle}>
161
161
  {!fallback && imgState === 'error' && (
162
162
  <div className="image--state" title="loading image">
163
- <SvgIcon component={Alert} className="image--icon" />
163
+ <Icon icon={AlertIcon} className="image--icon" />
164
164
  </div>
165
165
  )}
166
166
  {!placeholder && imgState === 'loading' && (
167
167
  <div className="image--state" title="Image load error">
168
- <SvgIcon component={ImageIcon} className="image--icon" />
168
+ <Icon icon={ImageIcon} className="image--icon" />
169
169
  </div>
170
170
  )}
171
171
  {imgState === 'loaded' && <img className="image--img" src={src} alt={alt} />}
@@ -0,0 +1,109 @@
1
+ import { Box, IconButton, Link, MenuItem, Typography } from '@mui/material';
2
+ import PropTypes from 'prop-types';
3
+ import { Icon } from '@iconify/react';
4
+ import CheckIcon from '@iconify-icons/mdi/check';
5
+ import TrashCanOutlineIcon from '@iconify-icons/mdi/trash-can-outline';
6
+ import { useMemoizedFn } from 'ahooks';
7
+
8
+ import Avatar from '../Avatar';
9
+ import DID from '../DID';
10
+ import { translate } from '../Locale/util';
11
+ import { translations } from './translation';
12
+
13
+ export default function AccountItem({ account, active, onDelete, onChoose, locale }) {
14
+ const t = useMemoizedFn((key, data = {}) => {
15
+ return translate(translations, key, locale, 'en', data);
16
+ });
17
+
18
+ const _onChoose = useMemoizedFn(() => onChoose(account, { active }));
19
+
20
+ const _onDelete = useMemoizedFn((e) => {
21
+ e.preventDefault();
22
+ e.stopPropagation();
23
+ onDelete(account, { active });
24
+ });
25
+
26
+ if (!account?.did || !account?.appName) {
27
+ return null;
28
+ }
29
+
30
+ return (
31
+ <MenuItem
32
+ onClick={_onChoose}
33
+ sx={{
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ overflow: 'hidden',
37
+ gap: '8px',
38
+ position: 'relative',
39
+ '.account-item-actions': {
40
+ position: 'absolute',
41
+ right: 0,
42
+ top: 0,
43
+ bottom: 0,
44
+ marginRight: '12px',
45
+ display: 'flex',
46
+ alignItems: 'center',
47
+ },
48
+ '.account-item-action': {
49
+ alignItems: 'center',
50
+ display: 'none',
51
+ },
52
+ '&:hover .account-item-action': {
53
+ display: 'flex',
54
+ },
55
+ }}
56
+ className="session-manager-menu-item">
57
+ <Avatar did={account.did} size={42} />
58
+ <Box
59
+ sx={{
60
+ flex: 1,
61
+ overflow: 'hidden',
62
+ fontSize: 0,
63
+ '.did-address-avatar': {
64
+ display: 'none !important',
65
+ },
66
+ }}>
67
+ <DID did={account.did} copyable={false} size={14} responsive={false} compact sx={{ lineHeight: 1 }} />
68
+ {account.sourceAppPid && (
69
+ <Typography variant="caption">
70
+ {t('from')}{' '}
71
+ <Link href={account.appUrl} target="_blank" underline="none">
72
+ {account.appName}
73
+ </Link>
74
+ </Typography>
75
+ )}
76
+ </Box>
77
+ <Box className="account-item-actions">
78
+ {active ? (
79
+ <Box className="account-item-action" style={{ display: 'flex' }} key="CheckIcon">
80
+ <IconButton color="success">
81
+ <Icon icon={CheckIcon} color="success" />
82
+ </IconButton>
83
+ </Box>
84
+ ) : (
85
+ <Box className="account-item-action" key="TrashCanOutlineIcon">
86
+ <IconButton color="error" onClick={_onDelete}>
87
+ <Icon icon={TrashCanOutlineIcon} color="error" />
88
+ </IconButton>
89
+ </Box>
90
+ )}
91
+ </Box>
92
+ </MenuItem>
93
+ );
94
+ }
95
+
96
+ AccountItem.propTypes = {
97
+ account: PropTypes.object,
98
+ active: PropTypes.bool,
99
+ locale: PropTypes.string,
100
+ onChoose: PropTypes.func,
101
+ onDelete: PropTypes.func,
102
+ };
103
+ AccountItem.defaultProps = {
104
+ account: null,
105
+ active: false,
106
+ locale: 'en',
107
+ onChoose: () => {},
108
+ onDelete: () => {},
109
+ };
@@ -0,0 +1,97 @@
1
+ import { Icon } from '@iconify/react';
2
+ import PropTypes from 'prop-types';
3
+ import { Menu, MenuItem, Typography } from '@mui/material';
4
+ import AddIcon from '@iconify-icons/ion/ios-add-circle-outline';
5
+ import { useCreation, useMemoizedFn, useReactive } from 'ahooks';
6
+ import { useRef } from 'react';
7
+ import { translate } from '../Locale/util';
8
+ import { translations } from './translation';
9
+ import { getCurrentApp, getFederatedApp } from '../Util/federated';
10
+
11
+ export default function AddAccountItem({ onAdd, locale }) {
12
+ const addRef = useRef(null);
13
+ const state = useReactive({
14
+ open: false,
15
+ });
16
+
17
+ const t = useMemoizedFn((key, data = {}) => {
18
+ return translate(translations, key, locale, 'en', data);
19
+ });
20
+ const apps = useCreation(() => {
21
+ const appList = [];
22
+ if (typeof window === 'undefined') {
23
+ return appList;
24
+ }
25
+ const blocklet = window?.blocklet;
26
+
27
+ const masterApp = getFederatedApp(blocklet);
28
+ const currentApp = getCurrentApp(blocklet);
29
+
30
+ if (currentApp) {
31
+ appList.push(currentApp);
32
+ }
33
+ if (masterApp && masterApp?.appId !== currentApp?.appId) {
34
+ appList.push(masterApp);
35
+ }
36
+ // NOTICE: masterApp 应该排在前面
37
+ return appList.reverse();
38
+ }, [window.blocklet]);
39
+
40
+ const _onAdd = useMemoizedFn(() => {
41
+ if (apps.length <= 1) {
42
+ onAdd(apps[0]);
43
+ } else {
44
+ state.open = true;
45
+ }
46
+ });
47
+ const onClose = useMemoizedFn(() => {
48
+ state.open = false;
49
+ });
50
+
51
+ return (
52
+ <>
53
+ <MenuItem
54
+ ref={addRef}
55
+ onClick={_onAdd}
56
+ className="session-manager-menu-item"
57
+ sx={{ display: 'flex', gap: '8px' }}
58
+ data-cy="sessionManager-switch-trigger">
59
+ <Icon icon={AddIcon} width={24} height={24} />
60
+ <Typography>{t('addAnotherAccount')}</Typography>
61
+ </MenuItem>
62
+ {addRef.current ? (
63
+ <Menu
64
+ anchorEl={addRef.current}
65
+ open={state.open}
66
+ onClose={onClose}
67
+ elevation={0}
68
+ PaperProps={{
69
+ variant: 'outlined',
70
+ }}
71
+ anchorOrigin={{
72
+ vertical: 'top',
73
+ horizontal: 'left',
74
+ }}
75
+ transformOrigin={{
76
+ vertical: 'top',
77
+ horizontal: 'left',
78
+ }}>
79
+ {apps.map((app) => (
80
+ <MenuItem key={app.appId} onClick={() => onAdd(app)}>
81
+ {t('connectWithAccount', { name: app.appName })}
82
+ </MenuItem>
83
+ ))}
84
+ </Menu>
85
+ ) : null}
86
+ </>
87
+ );
88
+ }
89
+
90
+ AddAccountItem.propTypes = {
91
+ onAdd: PropTypes.func,
92
+ locale: PropTypes.string,
93
+ };
94
+ AddAccountItem.defaultProps = {
95
+ onAdd: () => {},
96
+ locale: 'en',
97
+ };