@applica-software-guru/react-admin 1.5.295 → 1.5.297

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 (34) hide show
  1. package/dist/components/Layout/ThemeProvider.d.ts +1 -1
  2. package/dist/components/Layout/ThemeProvider.d.ts.map +1 -1
  3. package/dist/components/Layout/ThemeToggler.d.ts.map +1 -1
  4. package/dist/components/ra-lists/List.d.ts.map +1 -1
  5. package/dist/components/ra-lists/ListView.d.ts.map +1 -1
  6. package/dist/components/ra-lists/SimpleList.d.ts +2 -2
  7. package/dist/hooks/index.d.ts +1 -0
  8. package/dist/hooks/index.d.ts.map +1 -1
  9. package/dist/hooks/useSystemTheme.d.ts +9 -0
  10. package/dist/hooks/useSystemTheme.d.ts.map +1 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/react-admin.cjs.js +52 -52
  14. package/dist/react-admin.cjs.js.gz +0 -0
  15. package/dist/react-admin.cjs.js.map +1 -1
  16. package/dist/react-admin.es.js +9469 -9354
  17. package/dist/react-admin.es.js.gz +0 -0
  18. package/dist/react-admin.es.js.map +1 -1
  19. package/dist/react-admin.umd.js +55 -55
  20. package/dist/react-admin.umd.js.gz +0 -0
  21. package/dist/react-admin.umd.js.map +1 -1
  22. package/dist/themes/index.d.ts.map +1 -1
  23. package/dist/themes/palette.d.ts +2 -1
  24. package/dist/themes/palette.d.ts.map +1 -1
  25. package/package.json +1 -1
  26. package/src/components/Layout/ThemeProvider.tsx +1 -1
  27. package/src/components/Layout/ThemeToggler.tsx +98 -8
  28. package/src/components/ra-lists/List.tsx +5 -3
  29. package/src/components/ra-lists/ListView.tsx +72 -8
  30. package/src/hooks/index.ts +1 -0
  31. package/src/hooks/useSystemTheme.ts +40 -0
  32. package/src/index.ts +4 -0
  33. package/src/themes/index.tsx +6 -1
  34. package/src/themes/palette.ts +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAUxC,OAAO,EAAE,iBAAiB,EAAW,MAAM,OAAO,CAAC;AAEnD,KAAK,uBAAuB,GAAG,iBAAiB,CAAC;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE9E,iBAAS,0BAA0B,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,uBAAuB,2CAiExF;AAED,OAAO,EAAE,0BAA0B,EAAE,SAAS,IAAI,aAAa,EAAE,SAAS,IAAI,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAUxC,OAAO,EAAE,iBAAiB,EAAW,MAAM,OAAO,CAAC;AAEnD,KAAK,uBAAuB,GAAG,iBAAiB,CAAC;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE9E,iBAAS,0BAA0B,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,uBAAuB,2CAqExF;AAED,OAAO,EAAE,0BAA0B,EAAE,SAAS,IAAI,aAAa,EAAE,SAAS,IAAI,cAAc,EAAE,CAAC"}
@@ -1,3 +1,4 @@
1
- declare function Palette(mode: 'light' | 'dark', presetColor: string): any;
1
+ import { ThemeMode } from '../components';
2
+ declare function Palette(mode: ThemeMode, presetColor: string): any;
2
3
  export { Palette };
3
4
  //# sourceMappingURL=palette.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../../src/themes/palette.ts"],"names":[],"mappings":"AAIA,iBAAS,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,GAAG,CA8DjE;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../../src/themes/palette.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKzC,iBAAS,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,GAAG,CA8D1D;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/package.json CHANGED
@@ -106,5 +106,5 @@
106
106
  "type": "module",
107
107
  "types": "dist/index.d.ts",
108
108
  "typings": "dist/index.d.ts",
109
- "version": "1.5.295"
109
+ "version": "1.5.297"
110
110
  }
@@ -1,7 +1,7 @@
1
1
  import { useLocalStorage } from '@/hooks';
2
2
  import { PropsWithChildren, createContext, useContext } from 'react';
3
3
 
4
- type ThemeMode = 'light' | 'dark';
4
+ type ThemeMode = 'light' | 'dark' | 'auto';
5
5
  type ThemeOrientation = 'vertical' | 'horizontal';
6
6
 
7
7
  type ThemeDirection = 'ltr' | 'rtl';
@@ -1,17 +1,107 @@
1
1
  import { HeaderToggleButton } from './Header';
2
- import { useThemeConfig } from '@/components/Layout/ThemeProvider';
2
+ import { ThemeMode, useThemeConfig } from '@/components/Layout/ThemeProvider';
3
+ import { usePopoverState } from '@/hooks';
3
4
  import { MoonOutlined, SunOutlined } from '@ant-design/icons';
5
+ import { Popper } from '@mui/base';
6
+ import { ClickAwayListener, List, ListItemButton, Paper, Typography, useTheme } from '@mui/material';
7
+ import { Transitions } from '@/components/@extended';
8
+ import { MainCard } from '@/components/MainCard';
9
+ import { Brightness6 } from '@mui/icons-material';
10
+ import { useCallback } from 'react';
11
+ import { useTranslate } from 'ra-core';
12
+
13
+ type ThemeModePopoverProps = {
14
+ open: boolean;
15
+ anchorEl: HTMLElement | null;
16
+ handleClose: () => void;
17
+ theme: any;
18
+ mode: ThemeMode;
19
+ toggleThemeMode: (theme: ThemeMode) => void;
20
+ };
21
+
22
+ function ThemeModePopover({ open, anchorEl, handleClose, theme, mode, toggleThemeMode }: ThemeModePopoverProps) {
23
+ const translate = useTranslate();
24
+ return (
25
+ <Popper placement="bottom-end" open={open} anchorEl={anchorEl} role={undefined} transition disablePortal>
26
+ {({ TransitionProps }) => (
27
+ <Transitions type="grow" position="top-right" in={open} {...TransitionProps}>
28
+ <Paper
29
+ sx={{
30
+ boxShadow: theme.customShadows.z1,
31
+ minWidth: 200,
32
+ [theme.breakpoints.down('md')]: { maxWidth: 250 },
33
+ marginTop: 1
34
+ }}
35
+ >
36
+ <ClickAwayListener onClickAway={handleClose}>
37
+ <MainCard elevation={0} border={false} content={false}>
38
+ <List>
39
+ <ListItemButton selected={mode === 'light'} onClick={() => toggleThemeMode('light')}>
40
+ <SunOutlined />
41
+ <Typography variant="subtitle1" ml={1}>
42
+ {translate('ra.preferences.theme.light')}
43
+ </Typography>
44
+ </ListItemButton>
45
+
46
+ <ListItemButton selected={mode === 'dark'} onClick={() => toggleThemeMode('dark')}>
47
+ <MoonOutlined />
48
+ <Typography variant="subtitle1" ml={1}>
49
+ {translate('ra.preferences.theme.dark')}
50
+ </Typography>
51
+ </ListItemButton>
52
+
53
+ <ListItemButton selected={mode === 'auto'} onClick={() => toggleThemeMode('auto')}>
54
+ <Brightness6 />
55
+ <Typography variant="subtitle1" ml={1} textTransform={'none'}>
56
+ {translate('ra.preferences.theme.auto')}
57
+ </Typography>
58
+ </ListItemButton>
59
+ </List>
60
+ </MainCard>
61
+ </ClickAwayListener>
62
+ </Paper>
63
+ </Transitions>
64
+ )}
65
+ </Popper>
66
+ );
67
+ }
4
68
 
5
69
  function ThemeToggler(): JSX.Element {
70
+ const theme = useTheme();
6
71
  const { mode, setMode } = useThemeConfig();
72
+ const { open, anchorEl, handleToggle, handleClose } = usePopoverState();
73
+
74
+ const toggleThemeMode = useCallback(
75
+ (theme: ThemeMode) => {
76
+ setMode(theme);
77
+ },
78
+ [setMode]
79
+ );
80
+
81
+ const ThemeIcon = useCallback(() => {
82
+ switch (mode) {
83
+ case 'light':
84
+ return <SunOutlined />;
85
+ case 'dark':
86
+ return <MoonOutlined />;
87
+ default:
88
+ return <Brightness6 />;
89
+ }
90
+ }, [mode]);
91
+
7
92
  return (
8
- <HeaderToggleButton
9
- value="theme-mode"
10
- aria-label="toggle mode"
11
- onChange={() => setMode(mode === 'dark' ? 'light' : 'dark')}
12
- selected={false}
13
- >
14
- {mode === 'dark' ? <SunOutlined /> : <MoonOutlined />}
93
+ <HeaderToggleButton value="theme-mode" aria-label="toggle mode" onClick={handleToggle} selected={false}>
94
+ <ThemeIcon />
95
+ {open ? (
96
+ <ThemeModePopover
97
+ open={open}
98
+ anchorEl={anchorEl}
99
+ handleClose={handleClose}
100
+ theme={theme}
101
+ mode={mode}
102
+ toggleThemeMode={toggleThemeMode}
103
+ />
104
+ ) : null}
15
105
  </HeaderToggleButton>
16
106
  );
17
107
  }
@@ -2,7 +2,7 @@ import { MainCard } from '@/components/MainCard';
2
2
  import { ListView } from '@/components/ra-lists/ListView';
3
3
  import { styled } from '@mui/system';
4
4
  import { ListBase, RaRecord } from 'ra-core';
5
- import { ReactElement } from 'react';
5
+ import React, { ReactElement } from 'react';
6
6
  import { ListProps } from 'react-admin';
7
7
  import { Pagination } from '@/components/Pagination/Pagination';
8
8
 
@@ -193,10 +193,12 @@ const StyledList = styled(RaList, { slot: 'root' })(({ theme }) => ({
193
193
  }));
194
194
 
195
195
  function List(props: ListProps): ReactElement {
196
+ const Wrapper = props.aside ? React.Fragment : MainCard;
197
+
196
198
  return (
197
- <MainCard content={false}>
199
+ <Wrapper {...(!props.aside && { content: false })}>
198
200
  <StyledList {...props} pagination={<Pagination />} />
199
- </MainCard>
201
+ </Wrapper>
200
202
  );
201
203
  }
202
204
 
@@ -1,14 +1,20 @@
1
1
  /* eslint-disable filenames/match-regex */
2
2
  import { Error } from '@/components/Layout/Error';
3
- import { Card } from '@mui/material';
4
- import { styled } from '@mui/material/styles';
3
+ import { Card, CardContent } from '@mui/material';
4
+ import { styled, useTheme } from '@mui/material/styles';
5
5
  import { SxProps } from '@mui/system';
6
6
  import clsx from 'clsx';
7
7
  import { RaRecord, useListContext } from 'ra-core';
8
8
  import { ElementType, ReactElement, ReactNode, cloneElement } from 'react';
9
9
  import * as React from 'react';
10
- import { ListActions as DefaultActions, Pagination as DefaultPagination, Empty, ListToolbar, Title } from 'react-admin';
11
-
10
+ import {
11
+ ListActions as DefaultActions,
12
+ Pagination as DefaultPagination,
13
+ Empty,
14
+ ListToolbar,
15
+ SavedQueriesListClasses,
16
+ Title
17
+ } from 'react-admin';
12
18
  const defaultActions = <DefaultActions />;
13
19
  const defaultPagination = <DefaultPagination />;
14
20
  const defaultEmpty = <Empty />;
@@ -31,6 +37,8 @@ function ListView<RecordType extends RaRecord = any>(props: ListViewProps): Reac
31
37
  ...rest
32
38
  } = props;
33
39
  const { defaultTitle, data, error, isLoading, filterValues, resource } = useListContext<RecordType>(props);
40
+ const theme = useTheme() as any;
41
+ const isAsideValidElement = React.isValidElement(aside);
34
42
 
35
43
  if (!children || (!data && isLoading && emptyWhileLoading)) {
36
44
  return null;
@@ -38,7 +46,19 @@ function ListView<RecordType extends RaRecord = any>(props: ListViewProps): Reac
38
46
 
39
47
  function renderList() {
40
48
  return (
41
- <div className={ListClasses.main}>
49
+ <div
50
+ className={ListClasses.main}
51
+ style={{
52
+ border: isAsideValidElement ? '1px solid' : 'none',
53
+ borderRadius: isAsideValidElement ? 4 : 0,
54
+ borderColor: isAsideValidElement
55
+ ? theme.palette.mode === 'dark'
56
+ ? theme.palette.divider
57
+ : theme.palette.grey.A800
58
+ : 'transparent',
59
+ backgroundColor: isAsideValidElement ? theme.palette.background.paper : 'transparent'
60
+ }}
61
+ >
42
62
  {filters || actions ? (
43
63
  <ListToolbar className={ListClasses.actions} filters={filters} actions={actions} hasCreate={hasCreate} />
44
64
  ) : null}
@@ -77,17 +97,46 @@ function ListView<RecordType extends RaRecord = any>(props: ListViewProps): Reac
77
97
  <Root className={clsx('list-page', className)} {...rest}>
78
98
  <Title title={title} defaultTitle={defaultTitle} preferenceKey={`${resource}.list.title`} />
79
99
  {shouldRenderEmptyPage ? renderEmpty() : renderList()}
80
- {aside}
100
+ {isAsideValidElement ? <AsideCard aside={aside} /> : null}
81
101
  </Root>
82
102
  );
83
103
  }
84
104
 
105
+ interface AsideCardProps {
106
+ aside: React.ReactElement;
107
+ }
108
+
109
+ function AsideCard({ aside }: AsideCardProps): ReactElement {
110
+ const order = (aside?.props as { order?: number })?.order ?? -1;
111
+ const theme = useTheme() as any;
112
+
113
+ return (
114
+ <Card
115
+ className={ListClasses.asideCard}
116
+ sx={{
117
+ order,
118
+ mr: order === -1 ? 2 : 0,
119
+ ml: order !== -1 ? 2 : 0,
120
+ width: 200,
121
+ border: '1px solid',
122
+ borderRadius: 1,
123
+ borderColor: theme.palette.mode === 'dark' ? theme.palette.divider : theme.palette.grey.A800,
124
+ backgroundColor: theme.palette.background.paper,
125
+ backgroundImage: 'none'
126
+ }}
127
+ >
128
+ <CardContent sx={{ pt: 1 }}>{cloneElement(aside, {})}</CardContent>
129
+ </Card>
130
+ );
131
+ }
132
+
85
133
  const PREFIX = 'RaList';
86
134
  const ListClasses = {
87
135
  main: `${PREFIX}-main`,
88
136
  content: `${PREFIX}-content`,
89
137
  actions: `${PREFIX}-actions`,
90
- noResults: `${PREFIX}-noResults`
138
+ noResults: `${PREFIX}-noResults`,
139
+ asideCard: `${PREFIX}-asideCard`
91
140
  };
92
141
 
93
142
  interface ListViewProps {
@@ -356,7 +405,22 @@ const Root = styled('div', {
356
405
 
357
406
  [`& .${ListClasses.actions}`]: {},
358
407
 
359
- [`& .${ListClasses.noResults}`]: {}
408
+ [`& .${ListClasses.noResults}`]: {},
409
+
410
+ [`& .${ListClasses.asideCard}`]: {
411
+ [theme.breakpoints.down('md')]: {
412
+ display: 'none'
413
+ },
414
+ [`& .${SavedQueriesListClasses.floatingIcon}`]: {
415
+ fontSize: '1.125rem'
416
+ },
417
+ [`& .${SavedQueriesListClasses.floatingTooltip}`]: {
418
+ top: '-1.2em'
419
+ },
420
+ '& form': {
421
+ marginTop: theme.spacing(2)
422
+ }
423
+ }
360
424
  }));
361
425
 
362
426
  export { ListView };
@@ -5,3 +5,4 @@ export * from './useMemoizedObject';
5
5
  export * from './usePopoverState';
6
6
  export * from './useRefDimensions';
7
7
  export * from './useResourceTitle';
8
+ export * from './useSystemTheme';
@@ -0,0 +1,40 @@
1
+ import { ThemeMode, useThemeConfig } from '@/components/Layout/ThemeProvider';
2
+ import { useEffect, useRef, useState } from 'react';
3
+
4
+ /**
5
+ * This hook is a listener for system theme changes (when automatic mode theme is enabled).
6
+ *
7
+ * @returns {ThemeMode} theme
8
+ */
9
+ function useSystemTheme(): ThemeMode {
10
+ const { mode } = useThemeConfig();
11
+ const colorSchemeMatchMedia = window.matchMedia('(prefers-color-scheme: dark)');
12
+ const [theme, setTheme] = useState<ThemeMode>(() => {
13
+ return mode === 'auto' ? (colorSchemeMatchMedia.matches ? 'dark' : 'light') : mode;
14
+ });
15
+ const previousMode = useRef(theme);
16
+
17
+ useEffect(() => {
18
+ function updateTheme() {
19
+ const themeType = colorSchemeMatchMedia.matches ? 'dark' : 'light';
20
+
21
+ if (themeType !== previousMode.current) {
22
+ setTheme(themeType);
23
+ previousMode.current = themeType;
24
+ }
25
+ }
26
+
27
+ updateTheme();
28
+
29
+ const mediaQuery = colorSchemeMatchMedia;
30
+ mediaQuery.addEventListener('change', updateTheme);
31
+
32
+ return () => {
33
+ mediaQuery.removeEventListener('change', updateTheme);
34
+ };
35
+ }, [colorSchemeMatchMedia]);
36
+
37
+ return theme;
38
+ }
39
+
40
+ export { useSystemTheme };
package/src/index.ts CHANGED
@@ -23,6 +23,9 @@ export {
23
23
  EditContextProvider,
24
24
  FieldTitle,
25
25
  FilterButton,
26
+ FilterList,
27
+ FilterListItem,
28
+ FilterLiveSearch,
26
29
  Form,
27
30
  FormDataConsumer,
28
31
  HttpError,
@@ -37,6 +40,7 @@ export {
37
40
  Resource,
38
41
  ResourceContextProvider,
39
42
  SaveButton,
43
+ SavedQueriesList,
40
44
  SimpleFormIteratorContext,
41
45
  SimpleShowLayout,
42
46
  SingleFieldList,
@@ -1,3 +1,4 @@
1
+ import { useSystemTheme } from '@/hooks';
1
2
  import { getColors } from './getColors';
2
3
  import { getShadow } from './getShadow';
3
4
  import { ComponentsOverrides } from './overrides';
@@ -16,8 +17,12 @@ type ThemeCustomizationProps = PropsWithChildren<{ themeOverrides: unknown }>;
16
17
  function ThemeCustomizationProvider({ themeOverrides, children }: ThemeCustomizationProps) {
17
18
  const _themeConfig = useThemeConfig();
18
19
  const { themeDirection, mode, presetColor, fontFamily } = _themeConfig;
20
+ const systemMode = useSystemTheme();
21
+ const paletteMode = useMemo(() => (mode === 'auto' ? systemMode : mode), [mode, systemMode]);
19
22
 
20
- const theme = useMemo(() => Palette(mode, presetColor), [mode, presetColor]);
23
+ const theme = useMemo(() => {
24
+ return Palette(paletteMode, presetColor);
25
+ }, [paletteMode, presetColor]);
21
26
 
22
27
  // eslint-disable-next-line react-hooks/exhaustive-deps
23
28
  const themeTypography = useMemo(() => Typography(fontFamily), [fontFamily]);
@@ -1,8 +1,9 @@
1
+ import { ThemeMode } from '@/components';
1
2
  import { Theme } from './theme';
2
3
  import { presetDarkPalettes, presetPalettes } from '@ant-design/colors';
3
4
  import { alpha, createTheme } from '@mui/material/styles';
4
5
 
5
- function Palette(mode: 'light' | 'dark', presetColor: string): any {
6
+ function Palette(mode: ThemeMode, presetColor: string): any {
6
7
  const colors = mode === 'dark' ? presetDarkPalettes : presetPalettes;
7
8
 
8
9
  let greyPrimary = [