@arcblock/ux 2.13.13 → 2.13.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.
Files changed (72) hide show
  1. package/lib/Address/responsive-did-address.js +3 -1
  2. package/lib/Config/theme-mode-toggle.js +1 -1
  3. package/lib/DIDConnect/app-icon.d.ts +8 -0
  4. package/lib/DIDConnect/app-icon.js +31 -0
  5. package/lib/DIDConnect/app-info-item.d.ts +7 -0
  6. package/lib/DIDConnect/app-info-item.js +73 -0
  7. package/lib/DIDConnect/did-connect-footer.d.ts +4 -0
  8. package/lib/DIDConnect/did-connect-footer.js +54 -0
  9. package/lib/DIDConnect/did-connect-logo.d.ts +1 -0
  10. package/lib/DIDConnect/did-connect-logo.js +11 -0
  11. package/lib/DIDConnect/index.d.ts +7 -0
  12. package/lib/DIDConnect/index.js +7 -0
  13. package/lib/DIDConnect/powered-by.d.ts +3 -0
  14. package/lib/DIDConnect/powered-by.js +46 -0
  15. package/lib/DIDConnect/with-container.d.ts +11 -0
  16. package/lib/DIDConnect/with-container.js +273 -0
  17. package/lib/DIDConnect/with-ux-theme.d.ts +1 -0
  18. package/lib/DIDConnect/with-ux-theme.js +23 -0
  19. package/lib/Datatable/CustomToolbar.js +0 -3
  20. package/lib/Datatable/index.d.ts +3 -0
  21. package/lib/Datatable/index.js +36 -20
  22. package/lib/Dialog/confirm.d.ts +6 -1
  23. package/lib/Dialog/confirm.js +7 -3
  24. package/lib/Dialog/use-confirm.js +6 -0
  25. package/lib/LoadingMask/index.js +1 -1
  26. package/lib/Locale/util.d.ts +3 -3
  27. package/lib/Locale/util.js +6 -1
  28. package/lib/LoginButton/index.d.ts +12 -0
  29. package/lib/LoginButton/index.js +74 -0
  30. package/lib/NavMenu/style.js +0 -1
  31. package/lib/SessionUser/components/un-login.js +42 -31
  32. package/lib/SharedBridge/index.d.ts +16 -0
  33. package/lib/SharedBridge/index.js +109 -0
  34. package/lib/SharedBridge/need-storage-access-api-dialog.d.ts +7 -0
  35. package/lib/SharedBridge/need-storage-access-api-dialog.js +212 -0
  36. package/lib/Theme/index.d.ts +2 -2
  37. package/lib/Theme/index.js +1 -1
  38. package/lib/Util/iframe.d.ts +5 -0
  39. package/lib/Util/iframe.js +24 -0
  40. package/lib/Util/index.d.ts +10 -1
  41. package/lib/Util/index.js +67 -4
  42. package/lib/hooks/use-blocklet-logo.d.ts +8 -0
  43. package/lib/hooks/use-blocklet-logo.js +31 -0
  44. package/lib/hooks/use-mobile.d.ts +4 -0
  45. package/lib/hooks/use-mobile.js +7 -0
  46. package/package.json +7 -6
  47. package/src/Address/responsive-did-address.tsx +11 -1
  48. package/src/Config/theme-mode-toggle.tsx +1 -1
  49. package/src/DIDConnect/app-icon.tsx +36 -0
  50. package/src/DIDConnect/app-info-item.tsx +82 -0
  51. package/src/DIDConnect/did-connect-footer.tsx +51 -0
  52. package/src/DIDConnect/did-connect-logo.tsx +8 -0
  53. package/src/DIDConnect/index.ts +7 -0
  54. package/src/DIDConnect/powered-by.tsx +48 -0
  55. package/src/DIDConnect/with-container.tsx +307 -0
  56. package/src/DIDConnect/with-ux-theme.tsx +22 -0
  57. package/src/Datatable/CustomToolbar.jsx +0 -1
  58. package/src/Datatable/index.jsx +32 -20
  59. package/src/Dialog/confirm.jsx +31 -23
  60. package/src/Dialog/use-confirm.jsx +6 -0
  61. package/src/LoadingMask/index.tsx +1 -1
  62. package/src/Locale/util.ts +7 -2
  63. package/src/LoginButton/index.tsx +73 -0
  64. package/src/NavMenu/style.ts +0 -1
  65. package/src/SessionUser/components/un-login.tsx +34 -27
  66. package/src/SharedBridge/index.tsx +123 -0
  67. package/src/SharedBridge/need-storage-access-api-dialog.tsx +171 -0
  68. package/src/Theme/index.ts +2 -2
  69. package/src/Util/iframe.ts +19 -0
  70. package/src/Util/index.ts +77 -4
  71. package/src/hooks/use-blocklet-logo.tsx +32 -0
  72. package/src/hooks/use-mobile.tsx +6 -0
@@ -0,0 +1,51 @@
1
+ import { Box, useMediaQuery } from '@mui/material';
2
+
3
+ import PoweredBy from './powered-by';
4
+ import AppInfoItem from './app-info-item';
5
+ import AppIcon from './app-icon';
6
+ import { getDIDColor, hexToRgba } from '../Util';
7
+
8
+ export default function DIDConnectFooter({
9
+ currentAppInfo = globalThis.blocklet,
10
+ currentAppColor = globalThis.blocklet?.appPid ? getDIDColor(globalThis.blocklet?.appPid) : '#fff',
11
+ }: {
12
+ currentAppInfo?: any;
13
+ currentAppColor?: string;
14
+ }) {
15
+ const isSmallView = useMediaQuery('(max-width:640px)');
16
+
17
+ return (
18
+ <Box
19
+ sx={{
20
+ display: 'flex',
21
+ justifyContent: 'space-between',
22
+ alignItems: 'center',
23
+ gap: 1,
24
+ fontSize: 12,
25
+ backgroundColor: hexToRgba(currentAppColor, 0.08),
26
+ // 需要保持跟 .did-connect__root 的规则一样
27
+ mx: isSmallView ? -2 : -3,
28
+ px: isSmallView ? 2 : 3,
29
+ py: 1.5,
30
+ // HACK: 极限条件下,footer 会溢出,使用隐藏的滚动条来处理这种情况(屏幕宽度小于 360 时会出现)
31
+ overflow: 'auto',
32
+ '&::-webkit-scrollbar': {
33
+ display: 'none', // 隐藏滚动条 (Webkit 浏览器)
34
+ },
35
+ '-ms-overflow-style': 'none', // 隐藏滚动条 (IE 浏览器)
36
+ 'scrollbar-width': 'none', // 隐藏滚动条 (Firefox)
37
+ }}
38
+ className="did-connect__footer">
39
+ <AppInfoItem
40
+ appInfo={currentAppInfo}
41
+ appLogo={<AppIcon appInfo={currentAppInfo} size={24} sx={{ flexShrink: 0 }} />}
42
+ sx={{
43
+ flex: 1,
44
+ overflow: 'hidden',
45
+ }}
46
+ />
47
+
48
+ <PoweredBy sx={{ maxWidth: '100%', justifyContent: 'end' }} />
49
+ </Box>
50
+ );
51
+ }
@@ -0,0 +1,8 @@
1
+ import DidBrandConnect from '@arcblock/icons/lib/DidBrandConnect';
2
+ import { useTheme } from '@mui/material';
3
+
4
+ export default function DidConnectLogo() {
5
+ const theme = useTheme();
6
+
7
+ return <DidBrandConnect style={{ filter: theme.palette.mode === 'dark' ? 'invert(1)' : 'none' }} />;
8
+ }
@@ -0,0 +1,7 @@
1
+ export { default as DIDConnectFooter } from './did-connect-footer';
2
+ export { default as AppInfoItem } from './app-info-item';
3
+ export { default as AppIcon } from './app-icon';
4
+ export { default as PoweredBy } from './powered-by';
5
+ export { default as withContainer } from './with-container';
6
+ export { default as withUxTheme } from './with-ux-theme';
7
+ export { default as DIDConnectLogo } from './did-connect-logo';
@@ -0,0 +1,48 @@
1
+ import { Box, useTheme } from '@mui/material';
2
+ import { Icon } from '@iconify/react';
3
+ import shieldCheckIcon from '@iconify-icons/mdi/shield-check';
4
+
5
+ import DidConnectLogo from './did-connect-logo';
6
+ import { mergeSx } from '../Util/style';
7
+
8
+ export default function PoweredBy({ ...rest }) {
9
+ const { palette } = useTheme();
10
+
11
+ return (
12
+ <Box
13
+ {...rest}
14
+ sx={mergeSx(
15
+ {
16
+ display: 'flex',
17
+ alignItems: 'center',
18
+ justifyContent: 'center',
19
+ color: 'text.secondary',
20
+ gap: 0.5,
21
+ fontSize: 12,
22
+ fontFamily: 'Lexend',
23
+ whiteSpace: 'nowrap',
24
+ },
25
+ rest?.sx
26
+ )}>
27
+ <Icon icon={shieldCheckIcon} color={palette.success.main} />
28
+ Secured by
29
+ <Box
30
+ component="a"
31
+ href="https://www.didconnect.io/"
32
+ target="_blank"
33
+ rel="noopener"
34
+ sx={{
35
+ color: 'initial',
36
+ display: 'flex',
37
+ alignItems: 'center',
38
+ gap: 0.5,
39
+ textDecoration: 'none',
40
+ '&:hover': {
41
+ textDecoration: 'underline',
42
+ },
43
+ }}>
44
+ <DidConnectLogo />
45
+ </Box>
46
+ </Box>
47
+ );
48
+ }
@@ -0,0 +1,307 @@
1
+ import { forwardRef, memo, useRef, useState } from 'react';
2
+ import { Dialog, DialogContent, useMediaQuery, Box, Backdrop, SwipeableDrawer, Drawer } from '@mui/material';
3
+ import { useDebounce, useMemoizedFn } from 'ahooks';
4
+ import { useBrowser } from '@arcblock/react-hooks';
5
+ import colorConvert from 'color-convert';
6
+
7
+ import { useTheme } from '../Theme';
8
+ import { mergeSx } from '../Util/style';
9
+ import { hexToRgba } from '../Util';
10
+ import { Locale } from '../type';
11
+
12
+ const BackdropWrap = memo(
13
+ forwardRef((backdropProps, ref) => {
14
+ return (
15
+ <Backdrop
16
+ open
17
+ ref={ref}
18
+ style={{
19
+ backgroundColor: 'rgba(0, 0, 0, 0.6)',
20
+ backdropFilter: 'blur(3px)',
21
+ touchAction: 'none',
22
+ }}
23
+ {...backdropProps}
24
+ key="background"
25
+ />
26
+ );
27
+ })
28
+ );
29
+
30
+ export default function withContainer(Component: React.ComponentType<any>) {
31
+ function WithContainerComponent({
32
+ popup = false,
33
+ open = false,
34
+ hideCloseButton = false,
35
+ ...rest
36
+ }: {
37
+ // 是否弹出显示, true 表示在 Dialog 中渲染, 并可以通过 open/onClose 控制 dialog 的显示/隐藏, false 表示直接渲染原内容
38
+ popup?: boolean;
39
+ open?: boolean;
40
+ hideCloseButton?: boolean;
41
+ onClose: () => void;
42
+ blocklet?: any;
43
+ origin?: string;
44
+ host?: string;
45
+ locale?: Locale;
46
+ }) {
47
+ const [color, setColor] = useState('#fff');
48
+
49
+ const drawerDragger = useRef(null);
50
+ const browser = useBrowser();
51
+ // 屏宽小于 sm 且在 mobile 设备中全屏显示 dialog (PC 端屏宽小于 sm 的情况正常弹窗, 不全屏显示)
52
+ const matchSm = useMediaQuery('(max-width:640px)');
53
+ let openVariant = 'page';
54
+ if (popup) {
55
+ openVariant = 'dialog';
56
+ if (matchSm && browser.mobile.any) {
57
+ openVariant = 'drawer';
58
+ }
59
+ }
60
+
61
+ const theme = useTheme();
62
+
63
+ // 兼容 did-react 版本中存在的 responsive prop, responsive=true 则让 dialog 始终保持 open 状态, 否则遵循外部传入的 open prop
64
+ const isOpen = open;
65
+
66
+ const leavingScreenDelay = theme?.transitions?.duration?.leavingScreen || 500; // 默认值是 195
67
+ const debouncedShow = useDebounce(isOpen, {
68
+ wait: leavingScreenDelay,
69
+ });
70
+
71
+ const removeMagicToken = useMemoizedFn(() => {
72
+ const searchParams = new URLSearchParams(window.location.search);
73
+ if (searchParams.get('magicToken')) {
74
+ searchParams.delete('magicToken');
75
+ }
76
+ window.history.replaceState({}, '', `${window.location.pathname}?${searchParams.toString()}`);
77
+ });
78
+
79
+ // eslint-disable-next-line no-unused-vars
80
+ const handleOnClose = (e: React.MouseEvent<HTMLElement>, reason: string) => {
81
+ if (['backdropClick', 'escapeKeyDown'].includes(reason)) return;
82
+ removeMagicToken();
83
+ rest?.onClose();
84
+ };
85
+
86
+ const showModal = debouncedShow || isOpen;
87
+
88
+ const DrawerComponent = hideCloseButton ? Drawer : SwipeableDrawer;
89
+
90
+ const hslColor = colorConvert.hex.hsl(color);
91
+
92
+ const [h, s, l] = hslColor;
93
+ const percentageList = [0, 30, 60, 30, 0, 30, 60, 30];
94
+ const maxPercentage = Math.max(...percentageList);
95
+ const minPercentage = Math.min(...percentageList);
96
+ let useAlpha = false;
97
+ if ((l * (100 + maxPercentage)) / 100 > 100 || (l * (100 + minPercentage)) / 100 < 0) {
98
+ // 超出范围,使用 alpha 通道变化
99
+ useAlpha = true;
100
+ }
101
+ const colorList = percentageList.map((percentageItem) => {
102
+ let finalL = (l * (100 + percentageItem)) / 100;
103
+ let finalAlpha = 0.6;
104
+ if (useAlpha) {
105
+ finalAlpha = (0.5 * (100 + percentageItem)) / 100;
106
+ } else {
107
+ finalL = (l * (100 + percentageItem)) / 100;
108
+ }
109
+ return `hsla(${h}, ${s}%, ${finalL}%, ${finalAlpha})`;
110
+ });
111
+ const background = `linear-gradient(45deg, ${colorList.join(', ')})`;
112
+ const colorListGlow = percentageList.map((percentageItem) => {
113
+ let finalL = (l * (100 + percentageItem)) / 100;
114
+ let finalAlpha = 0.2;
115
+ if (useAlpha) {
116
+ finalAlpha = (0.3 * (100 + percentageItem)) / 100;
117
+ } else {
118
+ finalL = (l * (100 + percentageItem)) / 100;
119
+ }
120
+ return `hsla(${h}, ${s}%, ${finalL}%, ${finalAlpha})`;
121
+ });
122
+
123
+ const backgroundGlow = `linear-gradient(45deg, ${colorListGlow.join(', ')})`;
124
+
125
+ const glowStyle = {
126
+ overflow: 'visible',
127
+ '&::before, &::after': {
128
+ content: '""',
129
+ position: 'absolute',
130
+ top: '-3px',
131
+ right: '-3px',
132
+ bottom: '-3px',
133
+ left: '-3px',
134
+ background,
135
+ backgroundSize: '300% 300%',
136
+ backgroundRepeat: 'no-repeat',
137
+ animation: 'glowRotate 10s linear infinite',
138
+ borderRadius: '14px !important',
139
+ zIndex: 0,
140
+ },
141
+ '&::after': {
142
+ background: backgroundGlow,
143
+ filter: 'blur(15px)',
144
+ },
145
+
146
+ '@keyframes glowRotate': {
147
+ '0%': {
148
+ backgroundPosition: '0 0',
149
+ },
150
+ '50%': {
151
+ backgroundPosition: '100% 0',
152
+ },
153
+ '100%': {
154
+ backgroundPosition: '0 0',
155
+ },
156
+ },
157
+ };
158
+
159
+ const wrapOnClose = useMemoizedFn(() => {
160
+ removeMagicToken();
161
+ rest?.onClose();
162
+ });
163
+
164
+ if (openVariant === 'page') {
165
+ return (
166
+ <Box
167
+ className="did-connect__container-page"
168
+ sx={mergeSx(glowStyle, {
169
+ borderRadius: 1,
170
+ position: 'relative',
171
+ zIndex: 1,
172
+ })}>
173
+ <Box
174
+ sx={{
175
+ border: `1px solid ${hexToRgba(color, 0.1)}`,
176
+ m: '-1px',
177
+ position: 'relative',
178
+ borderRadius: '12px',
179
+ zIndex: 2,
180
+ overflow: 'hidden',
181
+ }}>
182
+ <Component {...rest} onClose={wrapOnClose} setColor={setColor} hideCloseButton mode={openVariant} />
183
+ </Box>
184
+ </Box>
185
+ );
186
+ }
187
+
188
+ if (openVariant === 'drawer') {
189
+ return (
190
+ <DrawerComponent
191
+ className="did-connect__container-drawer"
192
+ disableSwipeToOpen
193
+ open={isOpen}
194
+ anchor="bottom"
195
+ drawerDragger={drawerDragger.current}
196
+ // @ts-ignore
197
+ onClose={handleOnClose}
198
+ slots={{
199
+ backdrop: BackdropWrap,
200
+ }}
201
+ PaperProps={{
202
+ sx: {
203
+ borderRadius: 3, // 保持跟 DID Wallet 一致
204
+ borderBottomLeftRadius: 0,
205
+ borderBottomRightRadius: 0,
206
+ p: '2px',
207
+ animation: 'glowBreathe 7s linear infinite',
208
+ '.did-connect__root': {
209
+ backgroundColor: 'transparent',
210
+ },
211
+ overflow: 'hidden',
212
+ '@keyframes glowBreathe': {
213
+ '0%, 100%': {
214
+ boxShadow: `
215
+ inset 0 0 7px ${hexToRgba(color, 0.3)},
216
+ inset 0 0 12px ${hexToRgba(color, 0.3)}`,
217
+ },
218
+ '50%': {
219
+ boxShadow: `
220
+ inset 0 0 18px ${hexToRgba(color, 0.7)},
221
+ inset 0 0 24px ${hexToRgba(color, 0.5)}`,
222
+ },
223
+ },
224
+ },
225
+ }}>
226
+ {hideCloseButton ? null : (
227
+ <Box
228
+ ref={drawerDragger}
229
+ sx={{
230
+ px: 1,
231
+ pt: 2,
232
+ m: 'auto',
233
+ mt: -1,
234
+ mb: -2,
235
+ zIndex: 2,
236
+ }}>
237
+ <Box
238
+ sx={{
239
+ width: '48px',
240
+ height: '4px',
241
+ borderRadius: '100vw',
242
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
243
+ }}
244
+ />
245
+ </Box>
246
+ )}
247
+ <Box
248
+ sx={{
249
+ touchAction: 'none',
250
+ maxWidth: '100%',
251
+ width: 500,
252
+ height: 'auto',
253
+ }}>
254
+ {/* HACK: 由于 MUI 文档中描述 使用 keepMounted: false 可能会造成问题,所以采用下面的方案进行 HACK */}
255
+ {/* https://mui.com/material-ui/react-drawer/#keep-mounted */}
256
+ {showModal ? (
257
+ <Component {...rest} onClose={wrapOnClose} setColor={setColor} hideCloseButton mode={openVariant} />
258
+ ) : null}
259
+ </Box>
260
+ </DrawerComponent>
261
+ );
262
+ }
263
+
264
+ return (
265
+ <Dialog
266
+ open={isOpen}
267
+ slots={{
268
+ backdrop: BackdropWrap,
269
+ }}
270
+ className="did-connect__container-dialog"
271
+ onClose={handleOnClose}
272
+ PaperProps={{
273
+ sx: {
274
+ // 避免样式被 server 中的定义覆盖
275
+ '&.MuiPaper-rounded': {
276
+ borderRadius: '12px !important',
277
+ },
278
+ position: 'relative',
279
+ ...glowStyle,
280
+ },
281
+ }}>
282
+ <DialogContent
283
+ sx={{
284
+ maxWidth: 'calc(100vw - 18px)',
285
+ maxHeight: 'calc(100vh - 18px)',
286
+ p: '0px !important',
287
+ height: 'auto',
288
+ backgroundColor: 'background.default',
289
+ borderRadius: '12px !important',
290
+ zIndex: 1,
291
+ }}>
292
+ {showModal ? (
293
+ <Component
294
+ {...rest}
295
+ onClose={wrapOnClose}
296
+ setColor={setColor}
297
+ hideCloseButton={hideCloseButton}
298
+ mode={openVariant}
299
+ />
300
+ ) : null}
301
+ </DialogContent>
302
+ </Dialog>
303
+ );
304
+ }
305
+
306
+ return WithContainerComponent;
307
+ }
@@ -0,0 +1,22 @@
1
+ import { createTheme, useTheme } from '@mui/material';
2
+ import { DID_CONNECT_THEME_LIGHT, DID_CONNECT_THEME_DARK } from '@blocklet/theme';
3
+ import { ThemeProvider } from '../Theme';
4
+
5
+ // DID Connect 使用自己的 Theme 配置,不受 Blocklet theme 影响
6
+ const themeLight = createTheme(DID_CONNECT_THEME_LIGHT);
7
+ const themeDark = createTheme(DID_CONNECT_THEME_DARK);
8
+
9
+ export default function withUxTheme(Component: React.ComponentType<any>) {
10
+ function WithUxThemeComponent(props: any) {
11
+ const { palette } = useTheme();
12
+ const theme = palette.mode === 'dark' ? themeDark : themeLight;
13
+
14
+ return (
15
+ <ThemeProvider theme={theme}>
16
+ <Component {...props} />
17
+ </ThemeProvider>
18
+ );
19
+ }
20
+
21
+ return WithUxThemeComponent;
22
+ }
@@ -356,7 +356,6 @@ const Container = styled('div')`
356
356
  display: flex;
357
357
  align-items: center;
358
358
  height: 56px;
359
- background-color: ${({ theme }) => theme.palette.background.default};
360
359
  .custom-toobar-title {
361
360
  position: relative;
362
361
  flex: 1;
@@ -57,7 +57,10 @@ import { styled } from '../Theme';
57
57
  * components?: ModifiedMUIDataTableProps['components'],
58
58
  * emptyNode?: import('react').ReactNode,
59
59
  * durable?: string,
60
- * durableKeys?: 'page' | 'rowsPerPage' | 'searchText' | 'sortOrder'
60
+ * durableKeys?: 'page' | 'rowsPerPage' | 'searchText' | 'sortOrder',
61
+ * bgColor?: string,
62
+ * hoverColor?: string,
63
+ * stripColor?: string
61
64
  * } & ModifiedMUIDataTableProps} DataTableProps
62
65
  */
63
66
 
@@ -179,6 +182,9 @@ function ReDataTable({
179
182
  emptyNode,
180
183
  durable,
181
184
  durableKeys,
185
+ bgColor = 'transparent',
186
+ hoverColor,
187
+ stripColor,
182
188
  ...rest
183
189
  }) {
184
190
  const oldState = useRef(null);
@@ -405,6 +411,9 @@ function ReDataTable({
405
411
  return (
406
412
  <TableContainer
407
413
  verticalKeyWidth={verticalKeyWidth}
414
+ bgColor={bgColor}
415
+ hoverColor={hoverColor}
416
+ stripColor={stripColor}
408
417
  className={clsx({
409
418
  'datatable-stripped': stripped,
410
419
  'datatable-hide-header': hideTableHeader,
@@ -433,6 +442,9 @@ ReDataTable.propTypes = {
433
442
  emptyNode: PropTypes.node,
434
443
  durable: PropTypes.string,
435
444
  durableKeys: PropTypes.array,
445
+ bgColor: PropTypes.string,
446
+ hoverColor: PropTypes.string,
447
+ stripColor: PropTypes.string,
436
448
  };
437
449
 
438
450
  ReDataTable.defaultProps = {
@@ -451,6 +463,9 @@ ReDataTable.defaultProps = {
451
463
  emptyNode: '',
452
464
  durable: '',
453
465
  durableKeys: ['page', 'rowsPerPage', 'searchText', 'sortOrder'],
466
+ bgColor: 'transparent',
467
+ hoverColor: '',
468
+ stripColor: '',
454
469
  };
455
470
 
456
471
  const alignCss = css`
@@ -488,14 +503,12 @@ const alignCss = css`
488
503
  }
489
504
  `;
490
505
 
491
- const TableContainer = styled('div', { shouldForwardProp: (prop) => prop !== 'verticalKeyWidth' })(({
492
- theme,
493
- verticalKeyWidth,
494
- }) => {
506
+ const TableContainer = styled('div', {
507
+ shouldForwardProp: (prop) => !['verticalKeyWidth', 'bgColor', 'hoverColor', 'stripColor'].includes(prop),
508
+ })(({ theme, verticalKeyWidth, bgColor, hoverColor, stripColor }) => {
495
509
  const primaryTextColor = theme.palette.text.primary;
496
- const defaultBgColor = theme.palette.background.default;
497
- const hoverBgColor = theme.palette.action.hover;
498
- const oddRowBgColor = theme.palette.grey[50];
510
+ const defaultHoverColor = theme.palette.action.hover;
511
+ const defaultStripColor = theme.palette.grey[50];
499
512
 
500
513
  const verticalKeyWidthStyle = verticalKeyWidth
501
514
  ? `
@@ -541,7 +554,7 @@ const TableContainer = styled('div', { shouldForwardProp: (prop) => prop !== 've
541
554
  height: 100%;
542
555
  box-shadow: none;
543
556
  background: none;
544
- background-color: ${defaultBgColor};
557
+ background-color: ${bgColor};
545
558
  }
546
559
  ${theme.breakpoints.down('md')} {
547
560
  td.MuiTableCell-body {
@@ -582,7 +595,7 @@ const TableContainer = styled('div', { shouldForwardProp: (prop) => prop !== 've
582
595
 
583
596
  .MuiTableCell-head {
584
597
  color: ${primaryTextColor};
585
- background-color: ${defaultBgColor};
598
+ background-color: ${bgColor};
586
599
  }
587
600
 
588
601
  .MuiTableCell-root {
@@ -590,26 +603,26 @@ const TableContainer = styled('div', { shouldForwardProp: (prop) => prop !== 've
590
603
  }
591
604
 
592
605
  .MuiTableRow-root {
593
- background-color: ${defaultBgColor};
594
- &:nth-of-type(even) {
595
- background-color: ${defaultBgColor};
596
- }
606
+ background-color: ${bgColor};
597
607
  &:hover {
598
- background-color: ${hoverBgColor};
608
+ background-color: ${hoverColor || defaultHoverColor};
599
609
  }
600
610
  &.MuiTableRow-footer {
601
- background-color: ${defaultBgColor};
611
+ background-color: ${bgColor};
602
612
  }
603
613
  }
604
614
 
605
615
  &.datatable-stripped {
606
616
  .MuiTableRow-root:nth-of-type(odd) {
607
- background-color: ${oddRowBgColor};
617
+ background-color: ${stripColor || defaultStripColor};
608
618
  &:hover {
609
- background-color: ${hoverBgColor};
619
+ background-color: ${hoverColor || defaultHoverColor};
620
+ }
621
+ &.MuiTableRow-head {
622
+ background-color: ${bgColor};
610
623
  }
611
624
  &.MuiTableRow-footer {
612
- background-color: ${defaultBgColor};
625
+ background-color: ${bgColor};
613
626
  }
614
627
  }
615
628
  }
@@ -619,7 +632,6 @@ const TableContainer = styled('div', { shouldForwardProp: (prop) => prop !== 've
619
632
  const FooterContainer = styled('div')`
620
633
  display: flex;
621
634
  align-items: center;
622
- background-color: ${(props) => props.theme.palette.background.default};
623
635
  .datatable-footer {
624
636
  position: relative;
625
637
  margin-left: auto;
@@ -15,6 +15,7 @@ import Dialog from './dialog';
15
15
  * children?: React.ReactNode,
16
16
  * showCancelButton?: true | false,
17
17
  * showCloseButton?: true | false,
18
+ * showConfirmButton?: true | false,
18
19
  * fullScreen?: false | true,
19
20
  * confirmButton?: {text: React.ReactNode, props?: ButtonProps}
20
21
  * cancelButton?: {text: React.ReactNode, props?: ButtonProps}
@@ -35,6 +36,7 @@ export default function Confirm({
35
36
  onCancel,
36
37
  showCloseButton,
37
38
  showCancelButton,
39
+ showConfirmButton,
38
40
  fullScreen,
39
41
  confirmButton,
40
42
  cancelButton,
@@ -81,29 +83,33 @@ export default function Confirm({
81
83
  },
82
84
  }}
83
85
  actions={
84
- <>
85
- {showCancelButton && (
86
- <Button
87
- onClick={(e) => {
88
- e.stopPropagation();
89
- onCancel(e, 'closeButton');
90
- }}
91
- color="primary"
92
- {...cancelButton.props}>
93
- {cancelButton.text}
94
- </Button>
95
- )}
96
- <Button
97
- onClick={(e) => {
98
- e.stopPropagation();
99
- onConfirm(e);
100
- }}
101
- color="primary"
102
- autoFocus
103
- {...confirmButton.props}>
104
- {confirmButton.text}
105
- </Button>
106
- </>
86
+ showCancelButton || showConfirmButton ? (
87
+ <>
88
+ {showCancelButton && (
89
+ <Button
90
+ onClick={(e) => {
91
+ e.stopPropagation();
92
+ onCancel(e, 'closeButton');
93
+ }}
94
+ color="primary"
95
+ {...cancelButton.props}>
96
+ {cancelButton.text}
97
+ </Button>
98
+ )}
99
+ {showConfirmButton && (
100
+ <Button
101
+ onClick={(e) => {
102
+ e.stopPropagation();
103
+ onConfirm(e);
104
+ }}
105
+ color="primary"
106
+ autoFocus
107
+ {...confirmButton.props}>
108
+ {confirmButton.text}
109
+ </Button>
110
+ )}
111
+ </>
112
+ ) : null
107
113
  }>
108
114
  {children}
109
115
  </Dialog>
@@ -117,6 +123,7 @@ Confirm.propTypes = {
117
123
  onCancel: PropTypes.func.isRequired,
118
124
  children: PropTypes.node,
119
125
  showCancelButton: PropTypes.bool,
126
+ showConfirmButton: PropTypes.bool,
120
127
  showCloseButton: PropTypes.bool,
121
128
  fullScreen: PropTypes.bool,
122
129
  // 可以传入 {text: ..., props: ...}
@@ -133,6 +140,7 @@ Confirm.propTypes = {
133
140
 
134
141
  Confirm.defaultProps = {
135
142
  showCancelButton: true,
143
+ showConfirmButton: true,
136
144
  showCloseButton: true,
137
145
  fullScreen: false,
138
146
  confirmButton: {