@applica-software-guru/react-admin 1.3.151 → 1.3.153

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 (46) hide show
  1. package/dist/components/Layout/Header/Buttons/HeaderButton.d.ts +6 -0
  2. package/dist/components/Layout/Header/Buttons/HeaderButton.d.ts.map +1 -0
  3. package/dist/components/Layout/Header/Buttons/HeaderIconButton.d.ts +6 -0
  4. package/dist/components/Layout/Header/Buttons/HeaderIconButton.d.ts.map +1 -0
  5. package/dist/components/Layout/Header/Buttons/HeaderToggleButton.d.ts +6 -0
  6. package/dist/components/Layout/Header/Buttons/HeaderToggleButton.d.ts.map +1 -0
  7. package/dist/components/Layout/Header/Buttons/index.d.ts +4 -0
  8. package/dist/components/Layout/Header/Buttons/index.d.ts.map +1 -0
  9. package/dist/components/Layout/Header/DrawerToggle.d.ts.map +1 -1
  10. package/dist/components/Layout/Header/Notification/Notification.d.ts.map +1 -1
  11. package/dist/components/Layout/Header/Profile/Profile.d.ts +1 -1
  12. package/dist/components/Layout/Header/Profile/Profile.d.ts.map +1 -1
  13. package/dist/components/Layout/Header/ResponsiveSection.d.ts.map +1 -1
  14. package/dist/components/Layout/Header/index.d.ts +1 -0
  15. package/dist/components/Layout/Header/index.d.ts.map +1 -1
  16. package/dist/hooks/index.d.ts +13 -12
  17. package/dist/hooks/index.d.ts.map +1 -1
  18. package/dist/hooks/mui.d.ts +4 -1
  19. package/dist/hooks/mui.d.ts.map +1 -1
  20. package/dist/hooks/useLocalizedValue.d.ts +9 -0
  21. package/dist/hooks/useLocalizedValue.d.ts.map +1 -0
  22. package/dist/hooks/usePopoverState.d.ts +10 -0
  23. package/dist/hooks/usePopoverState.d.ts.map +1 -0
  24. package/dist/react-admin.cjs.js +57 -57
  25. package/dist/react-admin.cjs.js.map +1 -1
  26. package/dist/react-admin.es.js +7315 -7304
  27. package/dist/react-admin.es.js.map +1 -1
  28. package/dist/react-admin.umd.js +58 -58
  29. package/dist/react-admin.umd.js.map +1 -1
  30. package/dist/utils/localizedValue.d.ts +12 -5
  31. package/dist/utils/localizedValue.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/components/Layout/Header/Buttons/HeaderButton.tsx +13 -0
  34. package/src/components/Layout/Header/Buttons/HeaderIconButton.tsx +22 -0
  35. package/src/components/Layout/Header/Buttons/HeaderToggleButton.tsx +23 -0
  36. package/src/components/Layout/Header/Buttons/index.ts +3 -0
  37. package/src/components/Layout/Header/DrawerToggle.tsx +9 -18
  38. package/src/components/Layout/Header/Notification/Notification.tsx +31 -53
  39. package/src/components/Layout/Header/Profile/{Profile.jsx → Profile.tsx} +34 -92
  40. package/src/components/Layout/Header/ResponsiveSection.tsx +17 -34
  41. package/src/components/Layout/Header/index.ts +1 -0
  42. package/src/hooks/index.jsx +13 -22
  43. package/src/hooks/mui.ts +16 -6
  44. package/src/hooks/useLocalizedValue.tsx +34 -0
  45. package/src/hooks/usePopoverState.tsx +28 -0
  46. package/src/utils/localizedValue.ts +37 -2
@@ -1,11 +1,18 @@
1
+ type ILocale = {
2
+ name: string;
3
+ locale: string;
4
+ };
1
5
  type ILocalizedValue<T> = {
2
6
  [key: string]: T;
3
7
  };
4
- declare function localizedValueHasAllLocales<T>(value?: ILocalizedValue<T>, locales?: Array<{
5
- name: string;
6
- locale: string;
7
- }>, options?: {
8
+ declare function localizedValueHasAllLocales<T>(value?: ILocalizedValue<T>, locales?: Array<ILocale>, options?: {
8
9
  isEmpty?: (v: T) => boolean;
9
10
  }): boolean;
10
- export { localizedValueHasAllLocales };
11
+ type IGetLocalizedValueOptions = {
12
+ fallback?: boolean;
13
+ fallbackLocales?: Array<string>;
14
+ };
15
+ declare function getLocalizedValue<T>(value: ILocalizedValue<T>, locale: string, options?: IGetLocalizedValueOptions): T | undefined;
16
+ export type { ILocalizedValue, IGetLocalizedValueOptions };
17
+ export { localizedValueHasAllLocales, getLocalizedValue };
11
18
  //# sourceMappingURL=localizedValue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"localizedValue.d.ts","sourceRoot":"","sources":["../../../src/utils/localizedValue.ts"],"names":[],"mappings":"AACA,KAAK,eAAe,CAAC,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAAC;AAE/C,iBAAS,2BAA2B,CAAC,CAAC,EACpC,KAAK,GAAE,eAAe,CAAC,CAAC,CAAM,EAC9B,OAAO,GAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAM,EACrD,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;CAAO,GAC5C,OAAO,CAIT;AAED,OAAO,EAAE,2BAA2B,EAAE,CAAC"}
1
+ {"version":3,"file":"localizedValue.d.ts","sourceRoot":"","sources":["../../../src/utils/localizedValue.ts"],"names":[],"mappings":"AACA,KAAK,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,KAAK,eAAe,CAAC,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAAC;AAE/C,iBAAS,2BAA2B,CAAC,CAAC,EACpC,KAAK,GAAE,eAAe,CAAC,CAAC,CAAM,EAC9B,OAAO,GAAE,KAAK,CAAC,OAAO,CAAM,EAC5B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;CAAO,GAC5C,OAAO,CAIT;AAED,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACjC,CAAC;AACF,iBAAS,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,yBAAyB,GAAG,CAAC,GAAG,SAAS,CAwB3H;AAED,YAAY,EAAE,eAAe,EAAE,yBAAyB,EAAE,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applica-software-guru/react-admin",
3
- "version": "1.3.151",
3
+ "version": "1.3.153",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,13 @@
1
+ import { Button, ButtonProps } from '@mui/material';
2
+ import { useSx } from '../../../../hooks';
3
+ import { ForwardedRef, forwardRef } from 'react';
4
+
5
+ type IHeaderButtonProps = Omit<ButtonProps, 'color' | 'variant' | 'size'>;
6
+
7
+ const HeaderButton = forwardRef(function HeaderButton(props: IHeaderButtonProps, ref: ForwardedRef<HTMLButtonElement> | null) {
8
+ const sx = useSx(props, { color: 'text.primary' }, { defaults: true });
9
+
10
+ return <Button ref={ref} {...props} color="secondary" variant="text" sx={sx} />;
11
+ });
12
+
13
+ export { HeaderButton };
@@ -0,0 +1,22 @@
1
+ import { ButtonProps, IconButtonProps } from '@mui/material';
2
+ import { IconButton } from '../../../@extended';
3
+ import { useSx } from '../../../../hooks';
4
+ import { ForwardedRef, forwardRef } from 'react';
5
+
6
+ type IHeaderIconButtonProps = Omit<IconButtonProps & ButtonProps, 'color' | 'variant' | 'size'>;
7
+
8
+ const HeaderIconButton = forwardRef(function HeaderIconButton(props: IHeaderIconButtonProps, ref: ForwardedRef<HTMLButtonElement> | null) {
9
+ const sx = useSx(
10
+ props,
11
+ {
12
+ color: 'text.primary'
13
+ },
14
+ { defaults: true }
15
+ );
16
+ return (
17
+ // @ts-ignore
18
+ <IconButton ref={ref} {...props} color="secondary" variant="text" sx={sx} />
19
+ );
20
+ });
21
+
22
+ export { HeaderIconButton };
@@ -0,0 +1,23 @@
1
+ import { ToggleButton, ToggleButtonProps } from '@mui/material';
2
+ import { ForwardedRef, forwardRef } from 'react';
3
+ import { useSx } from '../../../../hooks';
4
+
5
+ type IHeaderToggleButtonProps = Omit<ToggleButtonProps, 'color' | 'size'>;
6
+
7
+ const HeaderToggleButton = forwardRef(function HeaderToggleButton(props: IHeaderToggleButtonProps, ref: ForwardedRef<HTMLButtonElement>) {
8
+ const sx = useSx(
9
+ props,
10
+ {
11
+ color: 'text.primary',
12
+ borderStyle: 'none',
13
+ padding: 1,
14
+ fontSize: '1.5rem',
15
+ width: 36,
16
+ height: 36
17
+ },
18
+ { defaults: true }
19
+ );
20
+ return <ToggleButton ref={ref} {...props} color="secondary" sx={sx} />;
21
+ });
22
+
23
+ export { HeaderToggleButton };
@@ -0,0 +1,3 @@
1
+ export * from './HeaderButton';
2
+ export * from './HeaderIconButton';
3
+ export * from './HeaderToggleButton';
@@ -1,27 +1,18 @@
1
1
  import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
2
- import { IconButton } from '../../@extended';
3
- import { useLayoutDrawerState, useLayoutThemeState } from '../Provider';
2
+ import { useLayoutDrawerState } from '../Provider';
3
+ import { HeaderToggleButton } from './Buttons';
4
+
5
+ const buttonSx = {
6
+ ml: { xs: 0, lg: -2 }
7
+ };
4
8
 
5
9
  function DrawerToggle() {
6
- const { iconColor, iconColorOpen } = useLayoutThemeState(),
7
- { open, handleDrawerToggle } = useLayoutDrawerState();
10
+ const { open, handleDrawerToggle } = useLayoutDrawerState();
8
11
 
9
12
  return (
10
- //@ts-ignore
11
- <IconButton
12
- aria-label="open drawer"
13
- onClick={handleDrawerToggle}
14
- edge="start"
15
- color="secondary"
16
- variant="light"
17
- sx={{
18
- color: 'text.primary',
19
- bgcolor: open ? iconColorOpen : iconColor,
20
- ml: { xs: 0, lg: -2 }
21
- }}
22
- >
13
+ <HeaderToggleButton value="drawer" aria-label="open drawer" sx={buttonSx} onChange={handleDrawerToggle} selected={open}>
23
14
  {!open ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
24
- </IconButton>
15
+ </HeaderToggleButton>
25
16
  );
26
17
  }
27
18
 
@@ -1,74 +1,62 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
1
+ import { BellOutlined, CheckCircleOutlined } from '@ant-design/icons';
2
+ import { useLayoutMediaState, useLayoutNotificationsState } from '../../Provider';
3
+ import { HeaderToggleButton } from '../Buttons';
4
+ import { useGetList, useTranslate } from 'ra-core';
5
+ import { HeaderNotificationItem, INotification } from './NotificationItem';
6
+ import { useEffect, useState } from 'react';
2
7
  import {
3
8
  Badge,
4
- Box,
5
9
  ClickAwayListener,
6
- Divider,
7
- List,
8
- ListItemButton,
9
- ListItemText,
10
10
  Paper,
11
11
  Popper,
12
+ useTheme,
12
13
  Tooltip,
13
- Typography,
14
- useTheme
14
+ List,
15
+ Divider,
16
+ ListItemButton,
17
+ ListItemText,
18
+ Typography
15
19
  } from '@mui/material';
16
- import { useLayoutMediaState, useLayoutNotificationsState, useLayoutThemeState } from '../../Provider';
20
+ import { usePopoverState } from '../../../../hooks';
17
21
  import { IconButton, Transitions } from '../../../@extended';
18
- import { BellOutlined, CheckCircleOutlined } from '@ant-design/icons';
19
- import { useGetList, useTranslate } from 'ra-core';
20
22
  import MainCard from '../../../MainCard';
21
- import { HeaderNotificationItem, INotification } from './NotificationItem';
22
23
  import { Link } from 'react-router-dom';
23
24
 
24
- const avatarSX = {
25
+ const avatarSx = {
25
26
  width: 36,
26
27
  height: 36,
27
28
  fontSize: '1rem'
28
29
  };
29
30
 
30
- const actionSX = {
31
+ const actionSx = {
31
32
  mt: '6px',
32
33
  ml: 1,
33
34
  top: 'auto',
34
35
  right: 'auto',
35
36
  alignSelf: 'flex-start',
36
-
37
37
  transform: 'none'
38
38
  };
39
39
 
40
40
  function HeaderNotification() {
41
41
  const { enable } = useLayoutNotificationsState();
42
-
43
42
  return enable ? <HeaderNotificationButton /> : null;
44
43
  }
45
44
 
46
45
  function HeaderNotificationButton() {
47
- const theme = useTheme(),
48
- anchorRef = useRef(),
49
- translate = useTranslate(),
50
- { resource } = useLayoutNotificationsState(),
46
+ const translate = useTranslate(),
47
+ theme = useTheme(),
51
48
  { downMd } = useLayoutMediaState(),
52
- { iconColor, iconColorOpen } = useLayoutThemeState(),
53
- [notificationOpen, setNotificationOpen] = useState(false),
49
+ { resource } = useLayoutNotificationsState(),
54
50
  [notifications, setNotifications] = useState<Array<INotification>>([]),
55
- read = notifications.filter((item) => item.readed === null).length,
56
- handleToggle = useCallback(() => setNotificationOpen(!notificationOpen), [notificationOpen]),
57
- handleClose = useCallback(() => {
58
- //@ts-ignore
59
- if (anchorRef.current && anchorRef.current.contains(event.target)) {
60
- return;
61
- }
62
-
63
- setNotificationOpen(false);
64
- }, [anchorRef.current, setNotificationOpen]),
65
51
  { data, isLoading } = useGetList<INotification>(resource, {
66
52
  pagination: { page: 1, perPage: 25 },
67
53
  sort: { field: 'created', order: 'DESC' },
68
54
  filter: {
69
55
  readed: false
70
56
  }
71
- });
57
+ }),
58
+ read = notifications.filter((item) => item.readed === null).length,
59
+ { open, anchorEl, handleClose, handleToggle } = usePopoverState();
72
60
 
73
61
  useEffect(() => {
74
62
  if (!isLoading && data) {
@@ -77,26 +65,16 @@ function HeaderNotificationButton() {
77
65
  }, [data, isLoading]);
78
66
 
79
67
  return (
80
- <Box sx={{ flexShrink: 0 }}>
81
- {/*@ts-ignore*/}
82
- <IconButton
83
- color="secondary"
84
- variant="light"
85
- sx={{ color: 'text.primary', bgcolor: notificationOpen ? iconColorOpen : iconColor }}
86
- aria-label="open profile"
87
- ref={anchorRef}
88
- aria-controls={notificationOpen ? 'profile-grow' : undefined}
89
- aria-haspopup="true"
90
- onClick={handleToggle}
91
- >
68
+ <>
69
+ <HeaderToggleButton value="notifications" selected={open} onChange={handleToggle}>
92
70
  <Badge badgeContent={read} color="primary">
93
71
  <BellOutlined />
94
72
  </Badge>
95
- </IconButton>
73
+ </HeaderToggleButton>
96
74
  <Popper
97
75
  placement={downMd ? 'bottom' : 'bottom-end'}
98
- open={notificationOpen}
99
- anchorEl={anchorRef.current}
76
+ open={open}
77
+ anchorEl={anchorEl}
100
78
  role={undefined}
101
79
  transition
102
80
  disablePortal
@@ -152,8 +130,8 @@ function HeaderNotificationButton() {
152
130
  '& .MuiListItemButton-root': {
153
131
  py: 0.5,
154
132
  '&.Mui-selected': { bgcolor: 'grey.50', color: 'text.primary' },
155
- '& .MuiAvatar-root': avatarSX,
156
- '& .MuiListItemSecondaryAction-root': { ...actionSX, position: 'relative' }
133
+ '& .MuiAvatar-root': avatarSx,
134
+ '& .MuiListItemSecondaryAction-root': { ...actionSx, position: 'relative' }
157
135
  },
158
136
  maxHeight: 'calc(100vh - 240px)',
159
137
  overflow: 'auto'
@@ -164,12 +142,11 @@ function HeaderNotificationButton() {
164
142
  key={item.id}
165
143
  selected={read > 0}
166
144
  notification={item}
167
- onClick={handleToggle}
145
+ onClick={handleClose}
168
146
  divider={index < notifications.length - 1}
169
147
  />
170
148
  ))}
171
149
  </List>
172
- <Divider />
173
150
  {/*@ts-ignore*/}
174
151
  <ListItemButton
175
152
  sx={{ textAlign: 'center', py: `${12}px !important` }}
@@ -185,13 +162,14 @@ function HeaderNotificationButton() {
185
162
  }
186
163
  />
187
164
  </ListItemButton>
165
+ <Divider />
188
166
  </MainCard>
189
167
  </ClickAwayListener>
190
168
  </Paper>
191
169
  </Transitions>
192
170
  )}
193
171
  </Popper>
194
- </Box>
172
+ </>
195
173
  );
196
174
  }
197
175
 
@@ -1,108 +1,46 @@
1
+ import { CardContent, ClickAwayListener, Grid, List, Paper, Stack, Tooltip, Typography, useTheme } from '@mui/material';
2
+ import { HeaderToggleButton } from '../Buttons';
1
3
  import { Avatar, IconButton, Transitions } from '../../../@extended';
2
- import {
3
- Box,
4
- ButtonBase,
5
- CardContent,
6
- ClickAwayListener,
7
- Grid,
8
- List,
9
- Paper,
10
- Popper,
11
- Stack,
12
- Tooltip,
13
- Typography,
14
- useTheme
15
- } from '@mui/material';
16
- import { ChangePasswordButton, LogoutButton, StopImpersonateButton } from './buttons';
17
- import { useAuthProvider, useDataProvider, useGetIdentity, useLogout } from 'react-admin';
18
- import { useCallback, useEffect, useRef, useState } from 'react';
19
-
20
- import { LogoutOutlined } from '@ant-design/icons';
4
+ import { useAuthProvider, useDataProvider, useGetIdentity, useLogout } from 'ra-core';
5
+ import { useCallback, useEffect, useState } from 'react';
6
+ import { usePopoverState } from '../../../../hooks';
7
+ import { Popper } from '@mui/base';
21
8
  import MainCard from '../../../MainCard';
22
- import PropTypes from 'prop-types';
23
-
24
- function TabPanel({ children, value, index, ...other }) {
25
- return (
26
- <div role="tabpanel" hidden={value !== index} id={`profile-tabpanel-${index}`} aria-labelledby={`profile-tab-${index}`} {...other}>
27
- {value === index && children}
28
- </div>
29
- );
30
- }
31
-
32
- TabPanel.propTypes = {
33
- children: PropTypes.node,
34
- index: PropTypes.any.isRequired,
35
- value: PropTypes.any.isRequired
36
- };
37
-
38
- const Profile = () => {
39
- const theme = useTheme();
40
-
41
- const { identity } = useGetIdentity();
42
- const hasProfilePic = identity !== undefined && identity.image && identity.image !== null && identity.image !== '';
43
- const anchorRef = useRef(null);
44
- const [open, setOpen] = useState(false);
45
- const handleToggle = () => {
46
- setOpen((prevOpen) => !prevOpen);
47
- };
48
-
49
- const handleClose = (event) => {
50
- if (anchorRef.current && anchorRef.current.contains(event.target)) {
51
- return;
52
- }
53
- setOpen(false);
54
- };
9
+ import { LogoutOutlined } from '@ant-design/icons';
10
+ import { ChangePasswordButton, LogoutButton, StopImpersonateButton } from './buttons';
55
11
 
56
- const iconBackColorOpen = theme.palette.mode === 'dark' ? 'grey.200' : 'grey.300';
57
- const logout = useLogout();
12
+ function Profile() {
13
+ const theme = useTheme(),
14
+ dataProvider = useDataProvider(),
15
+ authProvider = useAuthProvider(),
16
+ { identity } = useGetIdentity(),
17
+ hasProfilePic = identity !== undefined && identity.image && identity.image !== null && identity.image !== '',
18
+ [profileImage, setProfileImage] = useState<string | null>(null),
19
+ { open, anchorEl, handleToggle, handleClose } = usePopoverState(),
20
+ logout = useLogout(),
21
+ handleLogout = useCallback(() => {
22
+ logout();
23
+ }, [authProvider, logout]);
58
24
 
59
- const dataProvider = useDataProvider();
60
- const authProvider = useAuthProvider();
61
- const handleLogout = useCallback(() => {
62
- logout();
63
- }, [authProvider, logout]);
64
- const [profileImage, setProfileImage] = useState(null);
65
25
  useEffect(() => {
66
- if (!hasProfilePic) {
67
- return;
26
+ if (hasProfilePic) {
27
+ dataProvider.getFile('/profile/me/image').then((image: string) => setProfileImage(image));
68
28
  }
69
- async function fetchProfileImage() {
70
- var image = await dataProvider.getFile('/profile/me/image');
71
- setProfileImage(image);
72
- }
73
- fetchProfileImage();
74
29
  }, [dataProvider, hasProfilePic]);
75
30
 
76
31
  return (
77
- <Box sx={{ flexShrink: 0 }}>
78
- <ButtonBase
79
- sx={{
80
- p: 0.25,
81
- bgcolor: open ? iconBackColorOpen : 'transparent',
82
- borderRadius: 1,
83
- '&:hover': {
84
- bgcolor: theme.palette.mode === 'dark' ? 'secondary.light' : 'secondary.lighter'
85
- },
86
- '&:focus-visible': {
87
- outline: `2px solid ${theme.palette.secondary.dark}`,
88
- outlineOffset: 2
89
- }
90
- }}
91
- aria-label="open profile"
92
- ref={anchorRef}
93
- aria-controls={open ? 'profile-grow' : undefined}
94
- aria-haspopup="true"
95
- onClick={handleToggle}
96
- >
32
+ <>
33
+ <HeaderToggleButton sx={{ p: 0.25, width: 'auto' }} onClick={handleToggle} value="profile" selected={open}>
97
34
  <Stack direction="row" spacing={2} alignItems="center" sx={{ p: 0.5 }}>
35
+ {/* @ts-ignore */}
98
36
  <Avatar alt={identity?.name?.toUpperCase()} src={profileImage} size="xs" />
99
37
  <Typography variant="subtitle1">{identity?.name}</Typography>
100
38
  </Stack>
101
- </ButtonBase>
39
+ </HeaderToggleButton>
102
40
  <Popper
103
41
  placement="bottom-end"
104
42
  open={open}
105
- anchorEl={anchorRef.current}
43
+ anchorEl={anchorEl}
106
44
  role={undefined}
107
45
  transition
108
46
  disablePortal
@@ -118,9 +56,11 @@ const Profile = () => {
118
56
  }}
119
57
  >
120
58
  {({ TransitionProps }) => (
59
+ /* @ts-ignore */
121
60
  <Transitions type="grow" position="top-right" in={open} {...TransitionProps}>
122
61
  <Paper
123
62
  sx={{
63
+ // @ts-ignore
124
64
  boxShadow: theme.customShadows.z1,
125
65
  width: 290,
126
66
  minWidth: 240,
@@ -136,17 +76,19 @@ const Profile = () => {
136
76
  <Grid container justifyContent="space-between" alignItems="center">
137
77
  <Grid item>
138
78
  <Stack direction="row" spacing={1.25} alignItems="center">
79
+ {/* @ts-ignore */}
139
80
  <Avatar alt="profile user" src={profileImage} sx={{ width: 32, height: 32 }} />
140
81
  <Stack>
141
82
  <Typography variant="h6">{identity?.name}</Typography>
142
83
  <Typography variant="body2" color="textSecondary">
143
- {identity?.roles?.map((r) => r.name.replace('ROLE_', '')).join(',')}
84
+ {identity?.roles?.map((r: { name: string }) => r.name.replace('ROLE_', '')).join(',')}
144
85
  </Typography>
145
86
  </Stack>
146
87
  </Stack>
147
88
  </Grid>
148
89
  <Grid item>
149
90
  <Tooltip title="Logout">
91
+ {/* @ts-ignore */}
150
92
  <IconButton size="large" sx={{ color: 'text.primary' }} onClick={handleLogout}>
151
93
  <LogoutOutlined />
152
94
  </IconButton>
@@ -169,8 +111,8 @@ const Profile = () => {
169
111
  </Transitions>
170
112
  )}
171
113
  </Popper>
172
- </Box>
114
+ </>
173
115
  );
174
- };
116
+ }
175
117
 
176
118
  export default Profile;
@@ -1,53 +1,36 @@
1
- import { AppBar, Box, ClickAwayListener, Paper, Popper, Toolbar } from '@mui/material';
2
- import { IconButton, Transitions } from '../../@extended';
3
- import { useRef, useState, useCallback } from 'react';
1
+ import { AppBar, ClickAwayListener, Paper, Popper, Toolbar } from '@mui/material';
2
+ import { Transitions } from '../../@extended';
4
3
  import { MoreOutlined } from '@ant-design/icons';
5
4
  import { useTheme } from '@mui/material/styles';
6
- import { useLayoutMediaState, useLayoutThemeState } from '../Provider';
5
+ import { useLayoutMediaState } from '../Provider';
6
+ import { HeaderToggleButton } from './Buttons';
7
+ import { usePopoverState } from '../../../hooks';
7
8
 
8
9
  type IResponsiveSectionProps = React.PropsWithChildren;
9
10
 
10
11
  const ResponsiveSection = (props: IResponsiveSectionProps) => {
11
12
  const theme = useTheme(),
12
13
  { downMd } = useLayoutMediaState(),
13
- { iconColor, iconColorOpen } = useLayoutThemeState(),
14
- [open, setOpen] = useState(false),
15
- anchorRef = useRef(null),
16
- handleToggle = useCallback(() => {
17
- setOpen(!open);
18
- }, [open]),
19
- //@ts-ignore
20
- handleClose = useCallback((event) => {
21
- //@ts-ignore
22
- if (anchorRef.current && anchorRef.current.contains(event.target)) {
23
- return;
24
- }
25
- setOpen(false);
26
- }, []);
14
+ { open, anchorEl, handleToggle, handleClose } = usePopoverState();
27
15
 
28
16
  return !downMd ? (
29
17
  <>{props.children}</>
30
18
  ) : (
31
19
  <>
32
- <Box sx={{ flexShrink: 0 }}>
33
- {/*@ts-ignore*/}
34
- <IconButton
35
- sx={{ color: 'text.primary', bgcolor: open ? iconColorOpen : iconColor }}
36
- aria-label="open more menu"
37
- ref={anchorRef}
38
- aria-controls={open ? 'menu-list-grow' : undefined}
39
- aria-haspopup="true"
40
- onClick={handleToggle}
41
- color="secondary"
42
- variant="light"
43
- >
44
- <MoreOutlined />
45
- </IconButton>
46
- </Box>
20
+ {/*@ts-ignore*/}
21
+ <HeaderToggleButton
22
+ aria-label="open more menu"
23
+ aria-controls={open ? 'menu-list-grow' : undefined}
24
+ aria-haspopup="true"
25
+ onClick={handleToggle}
26
+ selected={open}
27
+ >
28
+ <MoreOutlined />
29
+ </HeaderToggleButton>
47
30
  <Popper
48
31
  placement="bottom-end"
49
32
  open={open}
50
- anchorEl={anchorRef.current}
33
+ anchorEl={anchorEl}
51
34
  role={undefined}
52
35
  transition
53
36
  disablePortal
@@ -1,4 +1,5 @@
1
1
  export * from './AppBarStyled';
2
+ export * from './Buttons';
2
3
  export * from './DrawerToggle';
3
4
  export * from './Header';
4
5
  export * from './Notification';
@@ -1,23 +1,14 @@
1
- import useAppConfig from './useAppConfig';
2
- import useBreadcrumbs from './useBreadcrumbs';
3
- import useLocalStorage from './useLocalStorage';
4
- import useMenu from './useMenu';
5
- import useMenuConfig from './useMenuConfig';
6
- import useResourceTitle from './useResourceTitle';
7
- import useThemeConfig from './useThemeConfig';
8
- import useTableFormIterator from './useTableFormIterator';
9
- import useTableFormIteratorItem from './useTableFormIteratorItem';
10
- export {
11
- useAppConfig,
12
- useMenu,
13
- useBreadcrumbs,
14
- useLocalStorage,
15
- useThemeConfig,
16
- useResourceTitle,
17
- useMenuConfig,
18
- useTableFormIterator,
19
- useTableFormIteratorItem
20
- };
21
- export { useSx } from './mui';
22
- export { useRefDimensions } from './useRefDimensions';
1
+ export { default as useAppConfig } from './useAppConfig';
2
+ export { default as useBreadcrumbs } from './useBreadcrumbs';
3
+ export { useLocalizedValue, useGetLocalizedValue } from './useLocalizedValue';
4
+ export { default as useLocalStorage } from './useLocalStorage';
23
5
  export { useMemoizedObject } from './useMemoizedObject';
6
+ export { default as useMenu } from './useMenu';
7
+ export { default as useMenuConfig } from './useMenuConfig';
8
+ export { usePopoverState } from './usePopoverState';
9
+ export { useRefDimensions } from './useRefDimensions';
10
+ export { default as useResourceTitle } from './useResourceTitle';
11
+ export { useSx } from './mui';
12
+ export { default as useTableFormIterator } from './useTableFormIterator';
13
+ export { default as useTableFormIteratorItem } from './useTableFormIteratorItem';
14
+ export { default as useThemeConfig } from './useThemeConfig';
package/src/hooks/mui.ts CHANGED
@@ -2,12 +2,22 @@ import _ from 'lodash';
2
2
  import { SxProps } from '@mui/material';
3
3
  import { ComponentProps, useState, useEffect } from 'react';
4
4
 
5
- function useSx(props: ComponentProps<{ sx?: SxProps } & any>, sx: SxProps): SxProps {
6
- const _sx = _.merge(
7
- _.cloneDeepWith(props?.sx ?? {}, (v) => (_.isFunction(v) ? v : undefined)),
8
- sx
9
- ),
10
- [value, setValue] = useState(_sx);
5
+ type IUseSxOptions = {
6
+ defaults?: boolean;
7
+ };
8
+
9
+ function useSx(props: ComponentProps<{ sx?: SxProps } & any>, sx: SxProps, options?: IUseSxOptions): SxProps {
10
+ const _sx = _.chain(props?.sx ?? {})
11
+ .cloneDeepWith((v) => (_.isFunction(v) ? v : undefined))
12
+ .value();
13
+
14
+ if (options?.defaults) {
15
+ _.defaultsDeep(_sx, sx);
16
+ } else {
17
+ _.merge(_sx, sx);
18
+ }
19
+
20
+ const [value, setValue] = useState(_sx);
11
21
 
12
22
  useEffect(() => {
13
23
  if (!_.isEqual(value, _sx)) {