@arcblock/ux 2.11.9 → 2.11.11

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.
@@ -5,9 +5,9 @@ export interface IBlockletStore extends CardProps {
5
5
  title: string;
6
6
  description?: string;
7
7
  cover?: string;
8
- avatar: string;
9
- author: string;
10
- download: string;
8
+ avatar?: string;
9
+ author?: string;
10
+ download?: string;
11
11
  official?: {
12
12
  tooltip: React.ReactNode;
13
13
  size?: number;
@@ -15,16 +15,16 @@ export interface IBlockletStore extends CardProps {
15
15
  };
16
16
  button?: React.ReactNode;
17
17
  buttonText?: string;
18
- buttonDisabled?: false | true;
19
- buttonLoading?: false | true;
18
+ buttonDisabled?: boolean;
19
+ buttonLoading?: boolean;
20
20
  onButtonClick?: Function;
21
21
  onMainClick?: Function;
22
22
  className?: string;
23
23
  status?: {
24
24
  key: string;
25
25
  icon: React.ReactNode;
26
- text: string;
27
- title?: string;
26
+ text: React.ReactNode;
27
+ title?: React.ReactNode;
28
28
  maxWidth?: number;
29
29
  color?: string;
30
30
  align?: 'left' | 'right';
@@ -32,7 +32,7 @@ export interface IBlockletStore extends CardProps {
32
32
  icons?: {
33
33
  key: string;
34
34
  icon: string | React.ReactElement;
35
- title: string;
35
+ title: React.ReactNode;
36
36
  color?: string;
37
37
  }[];
38
38
  }
@@ -8,7 +8,7 @@ import Avatar from '../Avatar';
8
8
  import Button from '../Button';
9
9
  import { useTheme } from '../Theme';
10
10
  import IconText from './components/icon-text';
11
- import TooltipIcon from './tooltip-icon';
11
+ import TooltipIcon from './components/tooltip-icon';
12
12
  import { formatDownloadCount, strippedString } from './utils';
13
13
  export default function BlockletStore(props) {
14
14
  const {
@@ -104,6 +104,7 @@ export default function BlockletStore(props) {
104
104
  textOverflow: 'ellipsis',
105
105
  whiteSpace: 'nowrap',
106
106
  overflow: 'hidden',
107
+ cursor: 'default',
107
108
  pl: 0.5,
108
109
  '&&': {
109
110
  flexShrink: 1
@@ -133,7 +134,7 @@ export default function BlockletStore(props) {
133
134
  }
134
135
  }) : item.icon
135
136
  }, item.key))]
136
- }), button || onButtonClick && /*#__PURE__*/_jsxs(Button, {
137
+ }), onButtonClick && /*#__PURE__*/_jsxs(Button, {
137
138
  color: "reverse",
138
139
  variant: "outlined",
139
140
  size: "small",
@@ -152,7 +153,7 @@ export default function BlockletStore(props) {
152
153
  color: 'inherit'
153
154
  }
154
155
  }), buttonText]
155
- })]
156
+ }), button]
156
157
  }), /*#__PURE__*/_jsx(Stack, {
157
158
  py: 2,
158
159
  children: /*#__PURE__*/_jsx(Typography, {
@@ -165,6 +166,7 @@ export default function BlockletStore(props) {
165
166
  WebkitLineClamp: 2,
166
167
  WebkitBoxOrient: 'vertical',
167
168
  overflow: 'hidden',
169
+ cursor: 'default',
168
170
  height: 40
169
171
  },
170
172
  ...descriptionProps
@@ -4,6 +4,6 @@ export default function IconText({ icon, children, maxWidth, title, sx, }: {
4
4
  icon?: React.ReactNode;
5
5
  children?: React.ReactNode;
6
6
  maxWidth?: number;
7
- title?: string;
7
+ title?: React.ReactNode;
8
8
  sx?: StackProps['sx'];
9
9
  }): false | "" | 0 | import("react/jsx-runtime").JSX.Element | null | undefined;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Stack, Typography } from '@mui/material';
3
3
  import React from 'react';
4
+ import TooltipIcon from './tooltip-icon';
4
5
  export default function IconText({
5
6
  icon,
6
7
  children,
@@ -16,16 +17,19 @@ export default function IconText({
16
17
  maxWidth,
17
18
  overflow: 'hidden'
18
19
  }, ...(Array.isArray(sx) ? sx : [sx])],
19
- children: [icon, /*#__PURE__*/_jsx(Typography, {
20
- flex: 1,
21
- variant: "body2",
22
- sx: {
23
- overflow: 'hidden',
24
- textOverflow: 'ellipsis',
25
- whiteSpace: 'nowrap'
26
- },
27
- title: title || (typeof children === 'string' ? children : undefined),
28
- children: children
20
+ children: [icon, /*#__PURE__*/_jsx(TooltipIcon, {
21
+ title: title || (typeof children === 'string' ? children : ''),
22
+ children: /*#__PURE__*/_jsx(Typography, {
23
+ flex: 1,
24
+ variant: "body2",
25
+ sx: {
26
+ overflow: 'hidden',
27
+ textOverflow: 'ellipsis',
28
+ whiteSpace: 'nowrap',
29
+ cursor: 'default'
30
+ },
31
+ children: children
32
+ })
29
33
  })]
30
34
  });
31
35
  }
@@ -4,4 +4,4 @@ export interface TooltipIconProps extends TooltipProps {
4
4
  fontWeight?: number | string;
5
5
  color?: string;
6
6
  }
7
- export default function TooltipIcon({ title, sx, children, PopperProps, fontSize, fontWeight, color, ...props }: TooltipIconProps): import("react/jsx-runtime").JSX.Element;
7
+ export default function TooltipIcon({ title, sx, children, slotProps, fontSize, fontWeight, color, ...props }: TooltipIconProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Tooltip, tooltipClasses } from '@mui/material';
3
+ export default function TooltipIcon({
4
+ title,
5
+ sx,
6
+ children,
7
+ slotProps,
8
+ fontSize = 12,
9
+ fontWeight = 500,
10
+ color = 'text.secondary',
11
+ ...props
12
+ }) {
13
+ return title ? /*#__PURE__*/_jsx(Tooltip, {
14
+ title: title,
15
+ placement: "top",
16
+ ...props,
17
+ slotProps: {
18
+ popper: {
19
+ ...slotProps?.popper,
20
+ sx: [{
21
+ [`& .${tooltipClasses.tooltip}`]: {
22
+ backgroundColor: 'common.white',
23
+ fontSize,
24
+ fontWeight,
25
+ boxShadow: '0px 4px 8px 0px #03071214, 0px 0px 0px 1px #03071214',
26
+ marginBottom: '6px !important',
27
+ borderRadius: '8px',
28
+ cursor: 'default',
29
+ color,
30
+ display: 'flex',
31
+ alignItems: 'center'
32
+ }
33
+ }, ...(Array.isArray(slotProps?.popper?.sx) ? slotProps.popper.sx : [slotProps?.popper?.sx])]
34
+ }
35
+ },
36
+ children: children
37
+ }) : children;
38
+ }
@@ -1,5 +1,5 @@
1
1
  import ActionButton, { strippedString } from './utils';
2
2
  import Blocklet from './blocklet';
3
- import TooltipIcon from './tooltip-icon';
3
+ import TooltipIcon from './components/tooltip-icon';
4
4
  export { ActionButton, strippedString, TooltipIcon };
5
5
  export default Blocklet;
@@ -1,5 +1,5 @@
1
1
  import ActionButton, { strippedString } from './utils';
2
2
  import Blocklet from './blocklet';
3
- import TooltipIcon from './tooltip-icon';
3
+ import TooltipIcon from './components/tooltip-icon';
4
4
  export { ActionButton, strippedString, TooltipIcon };
5
5
  export default Blocklet;
@@ -1,8 +1,3 @@
1
- export interface InternalErrorFallbackProps {
2
- title?: string;
3
- desc: string;
4
- retryFunc?: (() => void) | null;
5
- }
6
1
  export interface ErrorFallbackProps {
7
2
  error: Error;
8
3
  }
@@ -12,3 +7,4 @@ export interface ErrorFallbackRetryProps {
12
7
  resetErrorBoundary: () => void;
13
8
  }
14
9
  export declare function ErrorFallbackRetry({ error, resetErrorBoundary }: ErrorFallbackRetryProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function ReactRouterErrorFallback(): import("react/jsx-runtime").JSX.Element;
@@ -1,24 +1,48 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { red } from '@mui/material/colors';
2
+ import { Alert, AlertTitle, Box, Typography } from '@mui/material';
3
+ import { useRouteError } from 'react-router-dom';
3
4
  import Button from '../Button';
4
- import { styled } from '../Theme';
5
5
  function InternalErrorFallback({
6
6
  title = 'Something went wrong...',
7
7
  desc,
8
- retryFunc = null
8
+ extraContent = null,
9
+ severity = 'error'
9
10
  }) {
10
- return /*#__PURE__*/_jsxs(Root, {
11
- role: "alert",
12
- children: [/*#__PURE__*/_jsx("h3", {
11
+ const gotoHome = () => window.location.replace('/');
12
+ const refresh = () => window.location.reload();
13
+ return /*#__PURE__*/_jsxs(Alert, {
14
+ severity: severity,
15
+ variant: "outlined",
16
+ icon: false,
17
+ sx: {
18
+ justifyContent: 'center'
19
+ },
20
+ children: [title ? /*#__PURE__*/_jsx(AlertTitle, {
13
21
  children: title
14
- }), /*#__PURE__*/_jsx("pre", {
22
+ }) : null, desc ? /*#__PURE__*/_jsx(Typography, {
23
+ variant: "body2",
24
+ mb: 1,
15
25
  children: desc
16
- }), retryFunc && /*#__PURE__*/_jsx(Button, {
17
- variant: "contained",
18
- color: "error",
19
- size: "small",
20
- onClick: retryFunc,
21
- children: "Try again"
26
+ }) : null, extraContent ?? /*#__PURE__*/_jsxs(Box, {
27
+ sx: {
28
+ display: 'flex',
29
+ gap: 1,
30
+ justifyContent: 'center',
31
+ alignItems: 'center'
32
+ },
33
+ children: [/*#__PURE__*/_jsx(Button, {
34
+ variant: "outlined",
35
+ color: severity,
36
+ size: "small",
37
+ onClick: gotoHome,
38
+ children: "Home"
39
+ }), /*#__PURE__*/_jsx(Button, {
40
+ variant: "contained",
41
+ color: severity,
42
+ size: "small",
43
+ onClick: refresh,
44
+ children: "Refresh"
45
+ })]
22
46
  })]
23
47
  });
24
48
  }
@@ -35,21 +59,19 @@ export function ErrorFallbackRetry({
35
59
  }) {
36
60
  return /*#__PURE__*/_jsx(InternalErrorFallback, {
37
61
  desc: error.message,
38
- retryFunc: resetErrorBoundary
62
+ extraContent: /*#__PURE__*/_jsx(Button, {
63
+ variant: "contained",
64
+ color: "error",
65
+ size: "small",
66
+ onClick: resetErrorBoundary,
67
+ children: "Try again"
68
+ })
39
69
  });
40
70
  }
41
- const Root = styled('div')`
42
- padding: 16px;
43
- border: 2px solid ${props => props.theme.palette.error.main};
44
- border-radius: 4px;
45
- color: ${props => props.theme.palette.error.main};
46
- background-color: ${red[50]};
47
- font-size: 14px;
48
- h3 {
49
- margin: 0;
50
- font-size: 16px;
51
- }
52
- pre {
53
- white-space: normal;
54
- }
55
- `;
71
+ export function ReactRouterErrorFallback() {
72
+ const error = useRouteError();
73
+ return /*#__PURE__*/_jsx(InternalErrorFallback, {
74
+ title: "Current route occurred an error",
75
+ desc: error.message
76
+ });
77
+ }
@@ -86,4 +86,5 @@ export declare const getTranslation: (translations: TranslationsObject, locale:
86
86
  fallbackLocale?: Locale;
87
87
  defaultValue?: string;
88
88
  }) => string;
89
+ export declare const lazyRetry: (fn: () => Promise<any>) => import("react").LazyExoticComponent<import("react").ComponentType<any>>;
89
90
  export {};
package/lib/Util/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  /* eslint-disable no-bitwise */
2
+ import { lazy } from 'react';
2
3
  import padStart from 'lodash/padStart';
3
4
  import { getDIDMotifInfo, colors } from '@arcblock/did-motif';
4
5
  import isNil from 'lodash/isNil';
6
+ import pRetry from 'p-retry';
5
7
  import { DID_PREFIX, WELLKNOWN_SERVICE_PATH_PREFIX } from './constant';
6
8
  let dateTool = null;
7
9
  export function parseQuery(str) {
@@ -356,4 +358,22 @@ export const getTranslation = (translations, locale, options = {}) => {
356
358
  translation = defaultValue;
357
359
  }
358
360
  return translation;
359
- };
361
+ };
362
+ export const lazyRetry = fn => /*#__PURE__*/lazy(() => pRetry(async () => {
363
+ try {
364
+ return await fn();
365
+ } catch (error) {
366
+ // HACK: pRetry 不会对 TypeError 的错误进行重试,手动放行了部分 network error 的错误,但此处的错误是经过 react-router 包装过的,不适用于上述的判断,所以这里需要特殊逻辑来进行处理
367
+ if (error instanceof TypeError && !error.message.includes('Failed to fetch')) {
368
+ throw error;
369
+ }
370
+ if (error instanceof Error) {
371
+ throw new Error(error.message);
372
+ }
373
+ throw new Error('Unknown error');
374
+ }
375
+ },
376
+ // 只需要重试两次,加上原本的一次,总共三次
377
+ {
378
+ retries: 2
379
+ }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.11.9",
3
+ "version": "2.11.11",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -68,12 +68,12 @@
68
68
  "react": ">=18.2.0",
69
69
  "react-router-dom": ">=6.22.3"
70
70
  },
71
- "gitHead": "cc71a9dd666287cb70d1a7bd487d1930294b9765",
71
+ "gitHead": "fc251e65f592a96d6fe876dda5d6158f7fbd2613",
72
72
  "dependencies": {
73
73
  "@arcblock/did-motif": "^1.1.13",
74
- "@arcblock/icons": "^2.11.9",
75
- "@arcblock/nft-display": "^2.11.9",
76
- "@arcblock/react-hooks": "^2.11.9",
74
+ "@arcblock/icons": "^2.11.11",
75
+ "@arcblock/nft-display": "^2.11.11",
76
+ "@arcblock/react-hooks": "^2.11.11",
77
77
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
78
78
  "@fontsource/inter": "^5.0.16",
79
79
  "@fontsource/ubuntu-mono": "^5.0.18",
@@ -103,6 +103,7 @@
103
103
  "lodash": "^4.17.21",
104
104
  "mui-datatables": "^4.3.0",
105
105
  "notistack": "^2.0.5",
106
+ "p-retry": "^6.2.1",
106
107
  "pako": "^2.1.0",
107
108
  "qrcode.react": "^3.1.0",
108
109
  "react-cookie-consent": "^6.4.1",
@@ -8,7 +8,7 @@ import Avatar from '../Avatar';
8
8
  import Button from '../Button';
9
9
  import { useTheme } from '../Theme';
10
10
  import IconText from './components/icon-text';
11
- import TooltipIcon from './tooltip-icon';
11
+ import TooltipIcon from './components/tooltip-icon';
12
12
  import { formatDownloadCount, strippedString } from './utils';
13
13
 
14
14
  export interface IBlockletStore extends CardProps {
@@ -16,9 +16,9 @@ export interface IBlockletStore extends CardProps {
16
16
  title: string;
17
17
  description?: string;
18
18
  cover?: string;
19
- avatar: string;
20
- author: string;
21
- download: string;
19
+ avatar?: string;
20
+ author?: string;
21
+ download?: string;
22
22
  official?: {
23
23
  tooltip: React.ReactNode;
24
24
  size?: number;
@@ -26,16 +26,16 @@ export interface IBlockletStore extends CardProps {
26
26
  };
27
27
  button?: React.ReactNode;
28
28
  buttonText?: string;
29
- buttonDisabled?: false | true;
30
- buttonLoading?: false | true;
29
+ buttonDisabled?: boolean;
30
+ buttonLoading?: boolean;
31
31
  onButtonClick?: Function;
32
32
  onMainClick?: Function;
33
33
  className?: string;
34
34
  status?: {
35
35
  key: string;
36
36
  icon: React.ReactNode;
37
- text: string;
38
- title?: string;
37
+ text: React.ReactNode;
38
+ title?: React.ReactNode;
39
39
  maxWidth?: number;
40
40
  color?: string;
41
41
  align?: 'left' | 'right';
@@ -43,7 +43,7 @@ export interface IBlockletStore extends CardProps {
43
43
  icons?: {
44
44
  key: string;
45
45
  icon: string | React.ReactElement;
46
- title: string;
46
+ title: React.ReactNode;
47
47
  color?: string;
48
48
  }[];
49
49
  }
@@ -116,6 +116,7 @@ export default function BlockletStore(props: IBlockletStore) {
116
116
  textOverflow: 'ellipsis',
117
117
  whiteSpace: 'nowrap',
118
118
  overflow: 'hidden',
119
+ cursor: 'default',
119
120
  pl: 0.5,
120
121
  '&&': { flexShrink: 1 },
121
122
  }}
@@ -133,24 +134,24 @@ export default function BlockletStore(props: IBlockletStore) {
133
134
  </TooltipIcon>
134
135
  ))}
135
136
  </Box>
136
- {button ||
137
- (onButtonClick && (
138
- <Button
139
- color="reverse"
140
- variant="outlined"
141
- size="small"
142
- disabled={buttonDisabled || buttonLoading}
143
- style={{
144
- borderColor: theme.palette.grey[300],
145
- borderRadius: 8,
146
- fontSize: 13,
147
- fontWeight: theme.typography.fontWeightMedium,
148
- }}
149
- onClick={handleButtonClick}>
150
- {buttonLoading && <CircularProgress size={15} style={{ marginRight: 3, color: 'inherit' }} />}
151
- {buttonText}
152
- </Button>
153
- ))}
137
+ {onButtonClick && (
138
+ <Button
139
+ color="reverse"
140
+ variant="outlined"
141
+ size="small"
142
+ disabled={buttonDisabled || buttonLoading}
143
+ style={{
144
+ borderColor: theme.palette.grey[300],
145
+ borderRadius: 8,
146
+ fontSize: 13,
147
+ fontWeight: theme.typography.fontWeightMedium,
148
+ }}
149
+ onClick={handleButtonClick}>
150
+ {buttonLoading && <CircularProgress size={15} style={{ marginRight: 3, color: 'inherit' }} />}
151
+ {buttonText}
152
+ </Button>
153
+ )}
154
+ {button}
154
155
  </Stack>
155
156
  <Stack py={2}>
156
157
  <Typography
@@ -163,6 +164,7 @@ export default function BlockletStore(props: IBlockletStore) {
163
164
  WebkitLineClamp: 2,
164
165
  WebkitBoxOrient: 'vertical',
165
166
  overflow: 'hidden',
167
+ cursor: 'default',
166
168
  height: 40,
167
169
  }}
168
170
  {...descriptionProps}
@@ -1,5 +1,6 @@
1
1
  import { Stack, StackProps, Typography } from '@mui/material';
2
2
  import React from 'react';
3
+ import TooltipIcon from './tooltip-icon';
3
4
 
4
5
  export default function IconText({
5
6
  icon,
@@ -11,7 +12,7 @@ export default function IconText({
11
12
  icon?: React.ReactNode;
12
13
  children?: React.ReactNode;
13
14
  maxWidth?: number;
14
- title?: string;
15
+ title?: React.ReactNode;
15
16
  sx?: StackProps['sx'];
16
17
  }) {
17
18
  return (
@@ -22,13 +23,14 @@ export default function IconText({
22
23
  gap={0.5}
23
24
  sx={[{ maxWidth, overflow: 'hidden' }, ...(Array.isArray(sx) ? sx : [sx])]}>
24
25
  {icon}
25
- <Typography
26
- flex={1}
27
- variant="body2"
28
- sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}
29
- title={title || (typeof children === 'string' ? children : undefined)}>
30
- {children}
31
- </Typography>
26
+ <TooltipIcon title={title || (typeof children === 'string' ? children : '')}>
27
+ <Typography
28
+ flex={1}
29
+ variant="body2"
30
+ sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', cursor: 'default' }}>
31
+ {children}
32
+ </Typography>
33
+ </TooltipIcon>
32
34
  </Stack>
33
35
  )
34
36
  );
@@ -0,0 +1,51 @@
1
+ import { Tooltip, TooltipProps, tooltipClasses } from '@mui/material';
2
+
3
+ export interface TooltipIconProps extends TooltipProps {
4
+ fontSize?: number | string;
5
+ fontWeight?: number | string;
6
+ color?: string;
7
+ }
8
+
9
+ export default function TooltipIcon({
10
+ title,
11
+ sx,
12
+ children,
13
+ slotProps,
14
+ fontSize = 12,
15
+ fontWeight = 500,
16
+ color = 'text.secondary',
17
+ ...props
18
+ }: TooltipIconProps) {
19
+ return title ? (
20
+ <Tooltip
21
+ title={title}
22
+ placement="top"
23
+ {...props}
24
+ slotProps={{
25
+ popper: {
26
+ ...slotProps?.popper,
27
+ sx: [
28
+ {
29
+ [`& .${tooltipClasses.tooltip}`]: {
30
+ backgroundColor: 'common.white',
31
+ fontSize,
32
+ fontWeight,
33
+ boxShadow: '0px 4px 8px 0px #03071214, 0px 0px 0px 1px #03071214',
34
+ marginBottom: '6px !important',
35
+ borderRadius: '8px',
36
+ cursor: 'default',
37
+ color,
38
+ display: 'flex',
39
+ alignItems: 'center',
40
+ },
41
+ },
42
+ ...(Array.isArray(slotProps?.popper?.sx) ? slotProps.popper.sx : [slotProps?.popper?.sx]),
43
+ ],
44
+ },
45
+ }}>
46
+ {children}
47
+ </Tooltip>
48
+ ) : (
49
+ children
50
+ );
51
+ }
@@ -1,6 +1,6 @@
1
1
  import ActionButton, { strippedString } from './utils';
2
2
  import Blocklet from './blocklet';
3
- import TooltipIcon from './tooltip-icon';
3
+ import TooltipIcon from './components/tooltip-icon';
4
4
 
5
5
  export { ActionButton, strippedString, TooltipIcon };
6
6
  export default Blocklet;
@@ -1,28 +1,51 @@
1
- import { red } from '@mui/material/colors';
1
+ import { Alert, AlertTitle, Box, Typography, type AlertProps } from '@mui/material';
2
+ import { ReactNode } from 'react';
3
+ import { useRouteError } from 'react-router-dom';
4
+
2
5
  import Button from '../Button';
3
- import { styled } from '../Theme';
4
6
 
5
- export interface InternalErrorFallbackProps {
7
+ interface InternalErrorFallbackProps {
6
8
  title?: string;
7
9
  desc: string;
8
- retryFunc?: (() => void) | null;
10
+ extraContent?: ReactNode;
11
+ severity?: AlertProps['severity'];
9
12
  }
10
13
 
11
14
  function InternalErrorFallback({
12
15
  title = 'Something went wrong...',
13
16
  desc,
14
- retryFunc = null,
17
+ extraContent = null,
18
+ severity = 'error',
15
19
  }: InternalErrorFallbackProps) {
20
+ const gotoHome = () => window.location.replace('/');
21
+ const refresh = () => window.location.reload();
22
+
16
23
  return (
17
- <Root role="alert">
18
- <h3>{title}</h3>
19
- <pre>{desc}</pre>
20
- {retryFunc && (
21
- <Button variant="contained" color="error" size="small" onClick={retryFunc}>
22
- Try again
23
- </Button>
24
+ <Alert
25
+ severity={severity}
26
+ variant="outlined"
27
+ icon={false}
28
+ sx={{
29
+ justifyContent: 'center',
30
+ }}>
31
+ {title ? <AlertTitle>{title}</AlertTitle> : null}
32
+ {desc ? (
33
+ <Typography variant="body2" mb={1}>
34
+ {desc}
35
+ </Typography>
36
+ ) : null}
37
+ {extraContent ?? (
38
+ <Box sx={{ display: 'flex', gap: 1, justifyContent: 'center', alignItems: 'center' }}>
39
+ <Button variant="outlined" color={severity} size="small" onClick={gotoHome}>
40
+ Home
41
+ </Button>
42
+
43
+ <Button variant="contained" color={severity} size="small" onClick={refresh}>
44
+ Refresh
45
+ </Button>
46
+ </Box>
24
47
  )}
25
- </Root>
48
+ </Alert>
26
49
  );
27
50
  }
28
51
 
@@ -40,21 +63,19 @@ export interface ErrorFallbackRetryProps {
40
63
  }
41
64
 
42
65
  export function ErrorFallbackRetry({ error, resetErrorBoundary }: ErrorFallbackRetryProps) {
43
- return <InternalErrorFallback desc={error.message} retryFunc={resetErrorBoundary} />;
66
+ return (
67
+ <InternalErrorFallback
68
+ desc={error.message}
69
+ extraContent={
70
+ <Button variant="contained" color="error" size="small" onClick={resetErrorBoundary}>
71
+ Try again
72
+ </Button>
73
+ }
74
+ />
75
+ );
44
76
  }
45
77
 
46
- const Root = styled('div')`
47
- padding: 16px;
48
- border: 2px solid ${(props) => props.theme.palette.error.main};
49
- border-radius: 4px;
50
- color: ${(props) => props.theme.palette.error.main};
51
- background-color: ${red[50]};
52
- font-size: 14px;
53
- h3 {
54
- margin: 0;
55
- font-size: 16px;
56
- }
57
- pre {
58
- white-space: normal;
59
- }
60
- `;
78
+ export function ReactRouterErrorFallback() {
79
+ const error = useRouteError() as Error;
80
+ return <InternalErrorFallback title="Current route occurred an error" desc={error.message} />;
81
+ }
package/src/Util/index.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  /* eslint-disable no-bitwise */
2
+ import { lazy } from 'react';
2
3
  import padStart from 'lodash/padStart';
3
4
  import { getDIDMotifInfo, colors } from '@arcblock/did-motif';
4
5
  import isNil from 'lodash/isNil';
6
+ import pRetry from 'p-retry';
5
7
  import { DID_PREFIX, WELLKNOWN_SERVICE_PATH_PREFIX } from './constant';
6
8
  import type { $TSFixMe, Locale } from '../type';
7
9
 
@@ -456,3 +458,25 @@ export const getTranslation = (
456
458
 
457
459
  return translation;
458
460
  };
461
+
462
+ export const lazyRetry = (fn: () => Promise<any>) =>
463
+ lazy(() =>
464
+ pRetry(
465
+ async () => {
466
+ try {
467
+ return await fn();
468
+ } catch (error: unknown) {
469
+ // HACK: pRetry 不会对 TypeError 的错误进行重试,手动放行了部分 network error 的错误,但此处的错误是经过 react-router 包装过的,不适用于上述的判断,所以这里需要特殊逻辑来进行处理
470
+ if (error instanceof TypeError && !error.message.includes('Failed to fetch')) {
471
+ throw error;
472
+ }
473
+ if (error instanceof Error) {
474
+ throw new Error(error.message);
475
+ }
476
+ throw new Error('Unknown error');
477
+ }
478
+ },
479
+ // 只需要重试两次,加上原本的一次,总共三次
480
+ { retries: 2 }
481
+ )
482
+ );
@@ -1,33 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Tooltip, tooltipClasses } from '@mui/material';
3
- export default function TooltipIcon({
4
- title,
5
- sx,
6
- children,
7
- PopperProps,
8
- fontSize = 12,
9
- fontWeight = 500,
10
- color = 'text.secondary',
11
- ...props
12
- }) {
13
- return title ? /*#__PURE__*/_jsx(Tooltip, {
14
- title: title,
15
- placement: "top",
16
- ...props,
17
- PopperProps: {
18
- ...PopperProps,
19
- sx: [{
20
- [`& .${tooltipClasses.tooltip}`]: {
21
- backgroundColor: 'common.white',
22
- boxShadow: 1,
23
- fontSize,
24
- fontWeight,
25
- color,
26
- display: 'flex',
27
- alignItems: 'center'
28
- }
29
- }, ...(Array.isArray(PopperProps?.sx) ? PopperProps.sx : [PopperProps?.sx])]
30
- },
31
- children: children
32
- }) : children;
33
- }
@@ -1,46 +0,0 @@
1
- import { Tooltip, TooltipProps, tooltipClasses } from '@mui/material';
2
-
3
- export interface TooltipIconProps extends TooltipProps {
4
- fontSize?: number | string;
5
- fontWeight?: number | string;
6
- color?: string;
7
- }
8
-
9
- export default function TooltipIcon({
10
- title,
11
- sx,
12
- children,
13
- PopperProps,
14
- fontSize = 12,
15
- fontWeight = 500,
16
- color = 'text.secondary',
17
- ...props
18
- }: TooltipIconProps) {
19
- return title ? (
20
- <Tooltip
21
- title={title}
22
- placement="top"
23
- {...props}
24
- PopperProps={{
25
- ...PopperProps,
26
- sx: [
27
- {
28
- [`& .${tooltipClasses.tooltip}`]: {
29
- backgroundColor: 'common.white',
30
- boxShadow: 1,
31
- fontSize,
32
- fontWeight,
33
- color,
34
- display: 'flex',
35
- alignItems: 'center',
36
- },
37
- },
38
- ...(Array.isArray(PopperProps?.sx) ? PopperProps.sx : [PopperProps?.sx]),
39
- ],
40
- }}>
41
- {children}
42
- </Tooltip>
43
- ) : (
44
- children
45
- );
46
- }