@arcblock/ux 2.13.14 → 2.13.16

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.
@@ -16,6 +16,6 @@ export default function ThemeModeToggle() {
16
16
  }
17
17
  return /*#__PURE__*/_jsx(IconButton, {
18
18
  onClick: toggleMode,
19
- children: mode === 'light' ? /*#__PURE__*/_jsx(LightModeOutlinedIcon, {}) : /*#__PURE__*/_jsx(Brightness2OutlinedIcon, {})
19
+ children: mode === 'light' ? /*#__PURE__*/_jsx(Brightness2OutlinedIcon, {}) : /*#__PURE__*/_jsx(LightModeOutlinedIcon, {})
20
20
  });
21
21
  }
@@ -329,9 +329,6 @@ const Container = styled('div')`
329
329
  display: flex;
330
330
  align-items: center;
331
331
  height: 56px;
332
- background-color: ${({
333
- theme
334
- }) => theme.palette.background.default};
335
332
  .custom-toobar-title {
336
333
  position: relative;
337
334
  flex: 1;
@@ -40,6 +40,9 @@ export type DataTableProps = {
40
40
  emptyNode?: import("react").ReactNode;
41
41
  durable?: string;
42
42
  durableKeys?: "page" | "rowsPerPage" | "searchText" | "sortOrder";
43
+ bgColor?: string;
44
+ hoverColor?: string;
45
+ stripColor?: string;
43
46
  } & ModifiedMUIDataTableProps;
44
47
  import { TableFilterList } from 'mui-datatables';
45
48
  import { TableFooter } from 'mui-datatables';
@@ -58,7 +58,10 @@ import { styled } from '../Theme';
58
58
  * components?: ModifiedMUIDataTableProps['components'],
59
59
  * emptyNode?: import('react').ReactNode,
60
60
  * durable?: string,
61
- * durableKeys?: 'page' | 'rowsPerPage' | 'searchText' | 'sortOrder'
61
+ * durableKeys?: 'page' | 'rowsPerPage' | 'searchText' | 'sortOrder',
62
+ * bgColor?: string,
63
+ * hoverColor?: string,
64
+ * stripColor?: string
62
65
  * } & ModifiedMUIDataTableProps} DataTableProps
63
66
  */
64
67
 
@@ -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);
@@ -419,6 +425,9 @@ function ReDataTable({
419
425
  };
420
426
  return /*#__PURE__*/_jsx(TableContainer, {
421
427
  verticalKeyWidth: verticalKeyWidth,
428
+ bgColor: bgColor,
429
+ hoverColor: hoverColor,
430
+ stripColor: stripColor,
422
431
  className: clsx({
423
432
  'datatable-stripped': stripped,
424
433
  'datatable-hide-header': hideTableHeader
@@ -448,7 +457,10 @@ ReDataTable.propTypes = {
448
457
  components: PropTypes.object,
449
458
  emptyNode: PropTypes.node,
450
459
  durable: PropTypes.string,
451
- durableKeys: PropTypes.array
460
+ durableKeys: PropTypes.array,
461
+ bgColor: PropTypes.string,
462
+ hoverColor: PropTypes.string,
463
+ stripColor: PropTypes.string
452
464
  };
453
465
  ReDataTable.defaultProps = {
454
466
  options: {},
@@ -465,7 +477,10 @@ ReDataTable.defaultProps = {
465
477
  components: {},
466
478
  emptyNode: '',
467
479
  durable: '',
468
- durableKeys: ['page', 'rowsPerPage', 'searchText', 'sortOrder']
480
+ durableKeys: ['page', 'rowsPerPage', 'searchText', 'sortOrder'],
481
+ bgColor: 'transparent',
482
+ hoverColor: '',
483
+ stripColor: ''
469
484
  };
470
485
  const alignCss = css`
471
486
  .MuiTableCell-head {
@@ -502,15 +517,17 @@ const alignCss = css`
502
517
  }
503
518
  `;
504
519
  const TableContainer = styled('div', {
505
- shouldForwardProp: prop => prop !== 'verticalKeyWidth'
520
+ shouldForwardProp: prop => !['verticalKeyWidth', 'bgColor', 'hoverColor', 'stripColor'].includes(prop)
506
521
  })(({
507
522
  theme,
508
- verticalKeyWidth
523
+ verticalKeyWidth,
524
+ bgColor,
525
+ hoverColor,
526
+ stripColor
509
527
  }) => {
510
528
  const primaryTextColor = theme.palette.text.primary;
511
- const defaultBgColor = theme.palette.background.default;
512
- const hoverBgColor = theme.palette.action.hover;
513
- const oddRowBgColor = theme.palette.grey[50];
529
+ const defaultHoverColor = theme.palette.action.hover;
530
+ const defaultStripColor = theme.palette.grey[50];
514
531
  const verticalKeyWidthStyle = verticalKeyWidth ? `
515
532
  ${theme.breakpoints.down('md')} {
516
533
  [class*='MUIDataTable-responsiveBase'] {
@@ -552,7 +569,7 @@ const TableContainer = styled('div', {
552
569
  height: 100%;
553
570
  box-shadow: none;
554
571
  background: none;
555
- background-color: ${defaultBgColor};
572
+ background-color: ${bgColor};
556
573
  }
557
574
  ${theme.breakpoints.down('md')} {
558
575
  td.MuiTableCell-body {
@@ -593,7 +610,7 @@ const TableContainer = styled('div', {
593
610
 
594
611
  .MuiTableCell-head {
595
612
  color: ${primaryTextColor};
596
- background-color: ${defaultBgColor};
613
+ background-color: ${bgColor};
597
614
  }
598
615
 
599
616
  .MuiTableCell-root {
@@ -601,26 +618,26 @@ const TableContainer = styled('div', {
601
618
  }
602
619
 
603
620
  .MuiTableRow-root {
604
- background-color: ${defaultBgColor};
605
- &:nth-of-type(even) {
606
- background-color: ${defaultBgColor};
607
- }
621
+ background-color: ${bgColor};
608
622
  &:hover {
609
- background-color: ${hoverBgColor};
623
+ background-color: ${hoverColor || defaultHoverColor};
610
624
  }
611
625
  &.MuiTableRow-footer {
612
- background-color: ${defaultBgColor};
626
+ background-color: ${bgColor};
613
627
  }
614
628
  }
615
629
 
616
630
  &.datatable-stripped {
617
631
  .MuiTableRow-root:nth-of-type(odd) {
618
- background-color: ${oddRowBgColor};
632
+ background-color: ${stripColor || defaultStripColor};
619
633
  &:hover {
620
- background-color: ${hoverBgColor};
634
+ background-color: ${hoverColor || defaultHoverColor};
635
+ }
636
+ &.MuiTableRow-head {
637
+ background-color: ${bgColor};
621
638
  }
622
639
  &.MuiTableRow-footer {
623
- background-color: ${defaultBgColor};
640
+ background-color: ${bgColor};
624
641
  }
625
642
  }
626
643
  }
@@ -629,7 +646,6 @@ const TableContainer = styled('div', {
629
646
  const FooterContainer = styled('div')`
630
647
  display: flex;
631
648
  align-items: center;
632
- background-color: ${props => props.theme.palette.background.default};
633
649
  .datatable-footer {
634
650
  position: relative;
635
651
  margin-left: auto;
@@ -52,7 +52,7 @@ export default function LoadingMask({
52
52
  right: finialBorderWidth,
53
53
  top: finialBorderWidth,
54
54
  bottom: finialBorderWidth,
55
- backgroundColor: 'white',
55
+ backgroundColor: 'background.default',
56
56
  borderRadius: `${finialRadius - finialBorderWidth}px`
57
57
  },
58
58
  '&::before': {
@@ -12,7 +12,6 @@ export const NavMenuStyled = styled('nav', {
12
12
  minWidth: '50px',
13
13
  // FIXME: @zhanghan 这个只是临时的解决方案,会导致 header align right 不能真正的右对齐,需要修改 header 才能真正解决这个问题
14
14
  flexGrow: 100,
15
- backgroundColor: $bgColor,
16
15
  color: $textColor,
17
16
  fontSize: '16px',
18
17
  '&.navmenu--inline': {
@@ -20,6 +20,7 @@ const SharedBridge = /*#__PURE__*/memo(function SharedBridge({
20
20
  const refId = useId();
21
21
  const dataId = `shared-bridge_${refId}`;
22
22
  const currentState = useReactive({
23
+ hasInited: undefined,
23
24
  open: false,
24
25
  hasStorageAccess: false,
25
26
  get origin() {
@@ -72,10 +73,22 @@ const SharedBridge = /*#__PURE__*/memo(function SharedBridge({
72
73
  value
73
74
  }) => {
74
75
  currentState.hasStorageAccess = value;
76
+ currentState.hasInited = true;
75
77
  });
78
+ setTimeout(() => {
79
+ if (currentState.hasInited === undefined) {
80
+ currentState.hasInited = false;
81
+ }
82
+ }, 1000);
76
83
  onLoad();
77
84
  });
78
- return currentState.hasStorageAccess ? null : /*#__PURE__*/_jsxs(_Fragment, {
85
+ if (currentState.hasInited === false) {
86
+ return null;
87
+ }
88
+ if (currentState.hasStorageAccess) {
89
+ return null;
90
+ }
91
+ return /*#__PURE__*/_jsxs(_Fragment, {
79
92
  children: [/*#__PURE__*/_jsx(DialogComponent, {
80
93
  popup: true,
81
94
  locale: locale,
@@ -101,7 +114,8 @@ const SharedBridge = /*#__PURE__*/memo(function SharedBridge({
101
114
  left: 0,
102
115
  width: '100%',
103
116
  height: '100%',
104
- cursor: 'pointer'
117
+ cursor: 'pointer',
118
+ opacity: 0
105
119
  }, sx)
106
120
  })]
107
121
  });
@@ -0,0 +1,8 @@
1
+ import { type Breakpoint } from '@mui/material';
2
+ import { type ThemeOptions } from '@blocklet/theme';
3
+ export default function useBlockletLogo({ key, meta, theme: themeOverrides, square, }?: {
4
+ key?: number | Breakpoint;
5
+ meta?: any;
6
+ theme?: ThemeOptions;
7
+ square?: boolean;
8
+ }): any;
@@ -0,0 +1,31 @@
1
+ import { useCreation } from 'ahooks';
2
+ import { useTheme } from '../Theme';
3
+ import useMobile from './use-mobile';
4
+ export default function useBlockletLogo({
5
+ key = 'sm',
6
+ meta = {},
7
+ theme: themeOverrides = {},
8
+ square
9
+ } = {}) {
10
+ const isMobileDevice = useMobile({
11
+ key
12
+ });
13
+ const theme = useTheme();
14
+ const mode = useCreation(() => {
15
+ return themeOverrides?.palette?.mode || theme.palette.mode;
16
+ }, [theme, themeOverrides]);
17
+ const finalAppLogo = useCreation(() => {
18
+ const {
19
+ appLogo,
20
+ appLogoDark,
21
+ appLogoRect,
22
+ appLogoRectDark
23
+ } = Object.assign({}, window.blocklet ?? {}, meta);
24
+ const isDark = mode === 'dark';
25
+ const squareLogo = (isDark ? appLogoDark : appLogo) || appLogo;
26
+ // 深色模式尽可能优先使用深色图标
27
+ const rectLogo = (isDark ? appLogoRectDark || appLogoDark : appLogoRect) || appLogoRect;
28
+ return isMobileDevice || square ? squareLogo : rectLogo || squareLogo || '';
29
+ }, [mode, meta, isMobileDevice, square]);
30
+ return finalAppLogo;
31
+ }
@@ -0,0 +1,4 @@
1
+ import { Breakpoint } from '@mui/material';
2
+ export default function useMobile({ key }?: {
3
+ key?: number | Breakpoint;
4
+ }): boolean;
@@ -0,0 +1,7 @@
1
+ import { useTheme, useMediaQuery } from '@mui/material';
2
+ export default function useMobile({
3
+ key = 'sm'
4
+ } = {}) {
5
+ const theme = useTheme();
6
+ return useMediaQuery(theme.breakpoints.down(key));
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.13.14",
3
+ "version": "2.13.16",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -71,14 +71,14 @@
71
71
  "react": ">=18.2.0",
72
72
  "react-router-dom": ">=6.22.3"
73
73
  },
74
- "gitHead": "b9f48199169b641a2d3277806501471a56dd496d",
74
+ "gitHead": "ccf3113f17409f98eb34b43a18f532effef9bd9b",
75
75
  "dependencies": {
76
76
  "@arcblock/did-motif": "^1.1.13",
77
- "@arcblock/icons": "^2.13.14",
78
- "@arcblock/nft-display": "^2.13.14",
79
- "@arcblock/react-hooks": "^2.13.14",
77
+ "@arcblock/icons": "^2.13.16",
78
+ "@arcblock/nft-display": "^2.13.16",
79
+ "@arcblock/react-hooks": "^2.13.16",
80
80
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
81
- "@blocklet/theme": "^2.13.14",
81
+ "@blocklet/theme": "^2.13.16",
82
82
  "@fontsource/roboto": "~5.1.1",
83
83
  "@fontsource/ubuntu-mono": "^5.0.18",
84
84
  "@iconify-icons/logos": "^1.2.36",
@@ -16,7 +16,7 @@ export default function ThemeModeToggle() {
16
16
 
17
17
  return (
18
18
  <IconButton onClick={toggleMode}>
19
- {mode === 'light' ? <LightModeOutlinedIcon /> : <Brightness2OutlinedIcon />}
19
+ {mode === 'light' ? <Brightness2OutlinedIcon /> : <LightModeOutlinedIcon />}
20
20
  </IconButton>
21
21
  );
22
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;
@@ -62,7 +62,7 @@ export default function LoadingMask({
62
62
  right: finialBorderWidth,
63
63
  top: finialBorderWidth,
64
64
  bottom: finialBorderWidth,
65
- backgroundColor: 'white',
65
+ backgroundColor: 'background.default',
66
66
  borderRadius: `${finialRadius - finialBorderWidth}px`,
67
67
  },
68
68
  '&::before': {
@@ -14,7 +14,6 @@ export const NavMenuStyled = styled('nav', {
14
14
  minWidth: '50px',
15
15
  // FIXME: @zhanghan 这个只是临时的解决方案,会导致 header align right 不能真正的右对齐,需要修改 header 才能真正解决这个问题
16
16
  flexGrow: 100,
17
- backgroundColor: $bgColor,
18
17
  color: $textColor,
19
18
  fontSize: '16px',
20
19
  '&.navmenu--inline': {
@@ -29,7 +29,14 @@ const SharedBridge = memo(function SharedBridge({
29
29
  const _iframeRef = useRef<HTMLIFrameElement>(null);
30
30
  const refId = useId();
31
31
  const dataId = `shared-bridge_${refId}`;
32
- const currentState = useReactive({
32
+ const currentState = useReactive<{
33
+ hasInited?: boolean;
34
+ open: boolean;
35
+ hasStorageAccess: boolean;
36
+ origin: string;
37
+ host: string;
38
+ }>({
39
+ hasInited: undefined,
33
40
  open: false,
34
41
  hasStorageAccess: false,
35
42
  get origin() {
@@ -80,11 +87,25 @@ const SharedBridge = memo(function SharedBridge({
80
87
  const handleLoad = useMemoizedFn(() => {
81
88
  callIframe(targetIframeRef.current as HTMLIFrameElement, 'hasStorageAccess').then(({ value }) => {
82
89
  currentState.hasStorageAccess = value;
90
+ currentState.hasInited = true;
83
91
  });
92
+ setTimeout(() => {
93
+ if (currentState.hasInited === undefined) {
94
+ currentState.hasInited = false;
95
+ }
96
+ }, 1000);
84
97
  onLoad();
85
98
  });
86
99
 
87
- return currentState.hasStorageAccess ? null : (
100
+ if (currentState.hasInited === false) {
101
+ return null;
102
+ }
103
+
104
+ if (currentState.hasStorageAccess) {
105
+ return null;
106
+ }
107
+
108
+ return (
88
109
  <>
89
110
  <DialogComponent
90
111
  popup
@@ -112,6 +133,7 @@ const SharedBridge = memo(function SharedBridge({
112
133
  width: '100%',
113
134
  height: '100%',
114
135
  cursor: 'pointer',
136
+ opacity: 0,
115
137
  },
116
138
  sx
117
139
  )}
@@ -0,0 +1,32 @@
1
+ import { type Breakpoint } from '@mui/material';
2
+ import { type ThemeOptions } from '@blocklet/theme';
3
+ import { useCreation } from 'ahooks';
4
+ import { useTheme } from '../Theme';
5
+ import useMobile from './use-mobile';
6
+
7
+ export default function useBlockletLogo({
8
+ key = 'sm',
9
+ meta = {},
10
+ theme: themeOverrides = {},
11
+ square,
12
+ }: { key?: number | Breakpoint; meta?: any; theme?: ThemeOptions; square?: boolean } = {}) {
13
+ const isMobileDevice = useMobile({ key });
14
+ const theme = useTheme();
15
+
16
+ const mode = useCreation(() => {
17
+ return themeOverrides?.palette?.mode || theme.palette.mode;
18
+ }, [theme, themeOverrides]);
19
+
20
+ const finalAppLogo = useCreation(() => {
21
+ const { appLogo, appLogoDark, appLogoRect, appLogoRectDark } = Object.assign({}, window.blocklet ?? {}, meta);
22
+ const isDark = mode === 'dark';
23
+
24
+ const squareLogo = (isDark ? appLogoDark : appLogo) || appLogo;
25
+ // 深色模式尽可能优先使用深色图标
26
+ const rectLogo = (isDark ? appLogoRectDark || appLogoDark : appLogoRect) || appLogoRect;
27
+
28
+ return isMobileDevice || square ? squareLogo : rectLogo || squareLogo || '';
29
+ }, [mode, meta, isMobileDevice, square]);
30
+
31
+ return finalAppLogo;
32
+ }
@@ -0,0 +1,6 @@
1
+ import { Breakpoint, useTheme, useMediaQuery } from '@mui/material';
2
+
3
+ export default function useMobile({ key = 'sm' }: { key?: number | Breakpoint } = {}) {
4
+ const theme = useTheme();
5
+ return useMediaQuery(theme.breakpoints.down(key));
6
+ }