@applica-software-guru/react-admin 1.3.144 → 1.3.146

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 (31) hide show
  1. package/dist/components/ra-lists/BulkActionsToolbar.d.ts +26 -0
  2. package/dist/components/ra-lists/BulkActionsToolbar.d.ts.map +1 -0
  3. package/dist/components/ra-lists/BulkFloatingActionsToolbar.d.ts +13 -0
  4. package/dist/components/ra-lists/BulkFloatingActionsToolbar.d.ts.map +1 -0
  5. package/dist/components/ra-lists/Datagrid/Datagrid.d.ts +114 -0
  6. package/dist/components/ra-lists/Datagrid/Datagrid.d.ts.map +1 -0
  7. package/dist/components/ra-lists/Datagrid/DatagridContext.d.ts +9 -0
  8. package/dist/components/ra-lists/Datagrid/DatagridContext.d.ts.map +1 -0
  9. package/dist/components/ra-lists/Datagrid/DatagridContextProvider.d.ts +8 -0
  10. package/dist/components/ra-lists/Datagrid/DatagridContextProvider.d.ts.map +1 -0
  11. package/dist/components/ra-lists/Datagrid/index.d.ts +15 -0
  12. package/dist/components/ra-lists/Datagrid/index.d.ts.map +1 -0
  13. package/dist/components/ra-lists/index.d.ts +6 -5
  14. package/dist/components/ra-lists/index.d.ts.map +1 -1
  15. package/dist/react-admin.cjs.js +59 -59
  16. package/dist/react-admin.cjs.js.map +1 -1
  17. package/dist/react-admin.es.js +10034 -9399
  18. package/dist/react-admin.es.js.map +1 -1
  19. package/dist/react-admin.umd.js +59 -59
  20. package/dist/react-admin.umd.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/components/ra-lists/BulkActionsToolbar.tsx +141 -0
  23. package/src/components/ra-lists/BulkFloatingActionsToolbar.tsx +100 -0
  24. package/src/components/ra-lists/Datagrid/Datagrid.tsx +345 -0
  25. package/src/components/ra-lists/Datagrid/DatagridContext.ts +13 -0
  26. package/src/components/ra-lists/Datagrid/DatagridContextProvider.tsx +8 -0
  27. package/src/components/ra-lists/{Datagrid.tsx → Datagrid/index.tsx} +6 -9
  28. package/src/components/ra-lists/index.ts +6 -5
  29. package/src/playground/components/ra-forms/TestModelForm.jsx +18 -0
  30. package/dist/components/ra-lists/Datagrid.d.ts +0 -638
  31. package/dist/components/ra-lists/Datagrid.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applica-software-guru/react-admin",
3
- "version": "1.3.144",
3
+ "version": "1.3.146",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,141 @@
1
+ import * as React from 'react';
2
+ import { Children, ReactNode, cloneElement, isValidElement, useCallback } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { styled, lighten } from '@mui/material/styles';
5
+ import clsx from 'clsx';
6
+ import Toolbar from '@mui/material/Toolbar';
7
+ import Typography from '@mui/material/Typography';
8
+
9
+ import IconButton from '@mui/material/IconButton';
10
+ import CloseIcon from '@mui/icons-material/Close';
11
+ import { useTranslate, sanitizeListRestProps, useListContext, Identifier } from 'ra-core';
12
+ import { TopToolbar } from 'react-admin';
13
+
14
+ const BulkActionsToolbar = (props: BulkActionsToolbarProps) => {
15
+ const { label = 'ra.action.bulk_actions', children, className, ...rest } = props;
16
+ const { filterValues, resource, selectedIds = [], onUnselectItems } = useListContext(props);
17
+
18
+ const translate = useTranslate();
19
+
20
+ const handleUnselectAllClick = useCallback(() => {
21
+ onUnselectItems();
22
+ }, [onUnselectItems]);
23
+
24
+ return (
25
+ <Root className={className}>
26
+ <Toolbar
27
+ data-test="bulk-actions-toolbar"
28
+ className={clsx(BulkActionsToolbarClasses.toolbar, {
29
+ [BulkActionsToolbarClasses.collapsed]: selectedIds.length === 0
30
+ })}
31
+ {...sanitizeListRestProps(rest)}
32
+ >
33
+ <div className={BulkActionsToolbarClasses.title}>
34
+ <IconButton
35
+ className={BulkActionsToolbarClasses.icon}
36
+ aria-label={translate('ra.action.unselect')}
37
+ title={translate('ra.action.unselect')}
38
+ onClick={handleUnselectAllClick}
39
+ size="small"
40
+ >
41
+ <CloseIcon fontSize="small" />
42
+ </IconButton>
43
+ <Typography color="inherit" variant="subtitle1">
44
+ {translate(label, {
45
+ _: label,
46
+ // eslint-disable-next-line camelcase
47
+ smart_count: selectedIds.length
48
+ })}
49
+ </Typography>
50
+ </div>
51
+ <TopToolbar className={BulkActionsToolbarClasses.topToolbar}>
52
+ {Children.map(children, (child) =>
53
+ isValidElement<any>(child)
54
+ ? cloneElement(child, {
55
+ filterValues,
56
+ resource,
57
+ selectedIds
58
+ })
59
+ : null
60
+ )}
61
+ </TopToolbar>
62
+ </Toolbar>
63
+ </Root>
64
+ );
65
+ };
66
+
67
+ BulkActionsToolbar.propTypes = {
68
+ children: PropTypes.node,
69
+ label: PropTypes.string
70
+ };
71
+
72
+ export interface BulkActionsToolbarProps {
73
+ children?: ReactNode;
74
+ label?: string;
75
+ selectedIds?: Identifier[];
76
+ className?: string;
77
+ }
78
+
79
+ const PREFIX = 'RaBulkActionsToolbar';
80
+
81
+ export const BulkActionsToolbarClasses = {
82
+ toolbar: `${PREFIX}-toolbar`,
83
+ topToolbar: `${PREFIX}-topToolbar`,
84
+ buttons: `${PREFIX}-buttons`,
85
+ collapsed: `${PREFIX}-collapsed`,
86
+ title: `${PREFIX}-title`,
87
+ icon: `${PREFIX}-icon`
88
+ };
89
+
90
+ const Root = styled('div', {
91
+ name: PREFIX,
92
+ overridesResolver: (props, styles) => styles.root
93
+ })(({ theme }) => ({
94
+ position: 'relative',
95
+ [`& .${BulkActionsToolbarClasses.toolbar}`]: {
96
+ position: 'absolute',
97
+ left: 0,
98
+ right: 0,
99
+ zIndex: 3,
100
+ color: theme.palette.mode === 'light' ? theme.palette.primary.main : theme.palette.text.primary,
101
+ justifyContent: 'space-between',
102
+ backgroundColor: theme.palette.mode === 'light' ? lighten(theme.palette.primary.light, 0.8) : theme.palette.primary.dark,
103
+ minHeight: theme.spacing(6),
104
+ height: theme.spacing(6),
105
+ transform: `translateY(-${theme.spacing(6)})`,
106
+ transition: `${theme.transitions.create('height')}, ${theme.transitions.create('min-height')}, ${theme.transitions.create(
107
+ 'transform'
108
+ )}`,
109
+ borderTopLeftRadius: theme.shape.borderRadius,
110
+ borderTopRightRadius: theme.shape.borderRadius
111
+ },
112
+
113
+ [`& .${BulkActionsToolbarClasses.topToolbar}`]: {
114
+ paddingBottom: theme.spacing(1),
115
+ minHeight: 'auto',
116
+ [theme.breakpoints.down('sm')]: {
117
+ backgroundColor: 'transparent'
118
+ }
119
+ },
120
+
121
+ [`& .${BulkActionsToolbarClasses.buttons}`]: {},
122
+
123
+ [`& .${BulkActionsToolbarClasses.collapsed}`]: {
124
+ minHeight: 0,
125
+ height: 0,
126
+ transform: `translateY(0)`,
127
+ overflowY: 'hidden'
128
+ },
129
+
130
+ [`& .${BulkActionsToolbarClasses.title}`]: {
131
+ display: 'flex',
132
+ flex: '0 0 auto'
133
+ },
134
+
135
+ [`& .${BulkActionsToolbarClasses.icon}`]: {
136
+ marginLeft: '-0.5em',
137
+ marginRight: '0.5em'
138
+ }
139
+ }));
140
+
141
+ export default BulkActionsToolbar;
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useListContext, Button } from 'react-admin';
4
+ import { Box, Fab, Fade, List, ListItem, Popover, Theme, useMediaQuery } from '@mui/material';
5
+ import CloseIcon from '@mui/icons-material/Close';
6
+ const noSpaceOutside = {
7
+ p: 0,
8
+ m: 0
9
+ };
10
+ const moreSpaceInside = {
11
+ p: 2,
12
+ m: 0,
13
+ borderRadius: 0,
14
+ width: '100%'
15
+ };
16
+
17
+ const BulkFloatingActionsToolbar = (props: BulkFloatingActionsToolbarProps) => {
18
+ const { children } = props;
19
+ const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
20
+
21
+ const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
22
+ setAnchorEl(event.currentTarget);
23
+ };
24
+
25
+ const handleClose = () => {
26
+ setAnchorEl(null);
27
+ };
28
+ const isSmall = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'));
29
+ const open = Boolean(anchorEl);
30
+ const id = open ? 'simple-popover' : undefined;
31
+ const { filterValues, resource, selectedIds = [], onUnselectItems } = useListContext(props);
32
+
33
+ const handleUnselectAllClick = React.useCallback(() => {
34
+ onUnselectItems();
35
+ setAnchorEl(null);
36
+ }, [onUnselectItems, setAnchorEl]);
37
+
38
+ return (
39
+ <Fade in={selectedIds !== undefined && selectedIds.length > 0}>
40
+ <Box
41
+ sx={{
42
+ position: 'fixed',
43
+ bottom: '16px',
44
+ right: '16px'
45
+ }}
46
+ >
47
+ <Fab color="primary" aria-label="manage" onClick={handleClick}>
48
+ {selectedIds?.length}
49
+ </Fab>
50
+ <Popover
51
+ id={id}
52
+ open={open}
53
+ anchorEl={anchorEl}
54
+ onClose={handleClose}
55
+ anchorOrigin={{
56
+ vertical: 'top',
57
+ horizontal: isSmall ? 'center' : 'right'
58
+ }}
59
+ transformOrigin={{
60
+ vertical: 'bottom',
61
+ horizontal: isSmall ? 'center' : 'right'
62
+ }}
63
+ disableScrollLock
64
+ elevation={10}
65
+ >
66
+ <List sx={noSpaceOutside}>
67
+ <ListItem sx={noSpaceOutside}>
68
+ <Button onClick={handleUnselectAllClick} sx={moreSpaceInside} label="ra.action.unselect" startIcon={<CloseIcon />}>
69
+ <CloseIcon />
70
+ </Button>
71
+ </ListItem>
72
+ {React.Children.map(children, (child) => (
73
+ <ListItem sx={noSpaceOutside}>
74
+ {React.isValidElement<any>(child)
75
+ ? React.cloneElement(child, {
76
+ filterValues,
77
+ resource,
78
+ selectedIds,
79
+ sx: moreSpaceInside,
80
+ ...(child.props?.popover ? { closePopover: handleClose } : {})
81
+ })
82
+ : null}
83
+ </ListItem>
84
+ ))}
85
+ </List>
86
+ </Popover>
87
+ </Box>
88
+ </Fade>
89
+ );
90
+ };
91
+
92
+ BulkFloatingActionsToolbar.propTypes = {
93
+ children: PropTypes.node
94
+ };
95
+
96
+ export interface BulkFloatingActionsToolbarProps {
97
+ children?: React.ReactNode | React.ReactNode[];
98
+ }
99
+
100
+ export default BulkFloatingActionsToolbar;
@@ -0,0 +1,345 @@
1
+ import {
2
+ DatagridProps as RaDatagridProps,
3
+ DatagridHeader,
4
+ DatagridLoading,
5
+ DatagridBody,
6
+ PureDatagridBody,
7
+ BulkDeleteButton,
8
+ ListNoResults,
9
+ DatagridClasses,
10
+ DatagridRoot
11
+ } from 'react-admin';
12
+
13
+ import * as React from 'react';
14
+ import { cloneElement, createElement, isValidElement, useCallback, useRef, useEffect, FC, useMemo } from 'react';
15
+ import PropTypes from 'prop-types';
16
+ import { sanitizeListRestProps, useListContext, Identifier } from 'ra-core';
17
+ import { Table } from '@mui/material';
18
+ import clsx from 'clsx';
19
+ import union from 'lodash/union';
20
+ import difference from 'lodash/difference';
21
+ import DatagridContextProvider from './DatagridContextProvider';
22
+ import BulkActionsToolbar from '../BulkActionsToolbar';
23
+
24
+ const defaultBulkActionButtons = <BulkDeleteButton />;
25
+
26
+ export type DatagridProps = RaDatagridProps & {
27
+ /**
28
+ * An alternative to bulkActionButtons, to be used when the actions are too complex to be expressed.
29
+ * In this case you are free to fully control the rendering of the bulk actions toolbar.
30
+ * @see BulkActionsToolbar
31
+ * @example <caption>Using the BulkActionsToolbar component</caption>
32
+ * import { BulkActionsToolbar } from '@applica-software-guru/react-admin';
33
+ * import { BulkDeleteButton } from 'react-admin';
34
+ *
35
+ * const PostBulkActionButtons = props => (
36
+ * <BulkActionsToolbar {...props}>
37
+ * <BulkDeleteButton />
38
+ * // add your custom actions here
39
+ * </BulkActionsToolbar>
40
+ * );
41
+ *
42
+ * @example <caption>Using BulkFloatingActionsToolbar component</caption>
43
+ * import { BulkActionsToolbar } from '@applica-software-guru/react-admin';
44
+ * import { BulkDeleteButton } from 'react-admin';
45
+ *
46
+ * const PostBulkActionButtons = props => (
47
+ * <BulkActionsToolbar {...props}>
48
+ * <BulkDeleteButton />
49
+ * // add your custom actions here
50
+ * </BulkActionsToolbar>
51
+ * );
52
+ *
53
+ */
54
+ bulkActionsToolbar: React.ReactNode | React.FC | boolean;
55
+ };
56
+
57
+ /**
58
+ * The Datagrid component renders a list of records as a table.
59
+ * It is usually used as a child of the <List> and <ReferenceManyField> components.
60
+ *
61
+ * Props:
62
+ * - body
63
+ * - bulkActionButtons
64
+ * - children
65
+ * - empty
66
+ * - expand
67
+ * - header
68
+ * - hover
69
+ * - isRowExpandable
70
+ * - isRowSelectable
71
+ * - optimized
72
+ * - rowClick
73
+ * - rowSx
74
+ * - size
75
+ * - sx
76
+ *
77
+ * @example // Display all posts as a datagrid
78
+ * const postRowSx = (record, index) => ({
79
+ * backgroundColor: record.nb_views >= 500 ? '#efe' : 'white',
80
+ * });
81
+ * export const PostList = () => (
82
+ * <List>
83
+ * <Datagrid rowSx={postRowSx}>
84
+ * <TextField source="id" />
85
+ * <TextField source="title" />
86
+ * <TextField source="body" />
87
+ * <EditButton />
88
+ * </Datagrid>
89
+ * </List>
90
+ * );
91
+ *
92
+ * @example // Display all the comments of the current post as a datagrid
93
+ * <ReferenceManyField reference="comments" target="post_id">
94
+ * <Datagrid>
95
+ * <TextField source="id" />
96
+ * <TextField source="body" />
97
+ * <DateField source="created_at" />
98
+ * <EditButton />
99
+ * </Datagrid>
100
+ * </ReferenceManyField>
101
+ *
102
+ * @example // Usage outside of a <List> or a <ReferenceManyField>.
103
+ *
104
+ * const sort = { field: 'published_at', order: 'DESC' };
105
+ *
106
+ * export const MyCustomList = (props) => {
107
+ * const { data, total, isLoading } = useGetList(
108
+ * 'posts',
109
+ * { pagination: { page: 1, perPage: 10 }, sort: sort }
110
+ * );
111
+ *
112
+ * return (
113
+ * <Datagrid
114
+ * data={data}
115
+ * total={total}
116
+ * isLoading={isLoading}
117
+ * sort={sort}
118
+ * selectedIds={[]}
119
+ * setSort={() => {
120
+ * console.log('set sort');
121
+ * }}
122
+ * onSelect={() => {
123
+ * console.log('on select');
124
+ * }}
125
+ * onToggleItem={() => {
126
+ * console.log('on toggle item');
127
+ * }}
128
+ * >
129
+ * <TextField source="id" />
130
+ * <TextField source="title" />
131
+ * </Datagrid>
132
+ * );
133
+ * }
134
+ */
135
+ export const Datagrid: FC<DatagridProps> = React.forwardRef((props, ref) => {
136
+ const {
137
+ optimized = false,
138
+ body = optimized ? PureDatagridBody : DatagridBody,
139
+ header = DatagridHeader,
140
+ children,
141
+ className,
142
+ empty = DefaultEmpty,
143
+ expand,
144
+ bulkActionsToolbar = false,
145
+ bulkActionButtons = defaultBulkActionButtons,
146
+ hover,
147
+ isRowSelectable,
148
+ isRowExpandable,
149
+ resource,
150
+ rowClick,
151
+ rowSx,
152
+ rowStyle,
153
+ size = 'small',
154
+ sx,
155
+ expandSingle = false,
156
+ ...rest
157
+ } = props;
158
+
159
+ const { sort, data, isLoading, onSelect, onToggleItem, selectedIds, setSort, total } = useListContext(props);
160
+
161
+ const hasBulkActions = !!bulkActionButtons !== false;
162
+
163
+ const contextValue = useMemo(() => ({ isRowExpandable, expandSingle }), [isRowExpandable, expandSingle]);
164
+
165
+ const lastSelected = useRef(null);
166
+
167
+ useEffect(() => {
168
+ if (!selectedIds || selectedIds.length === 0) {
169
+ lastSelected.current = null;
170
+ }
171
+ }, [JSON.stringify(selectedIds)]); // eslint-disable-line react-hooks/exhaustive-deps
172
+
173
+ // we manage row selection at the datagrid level to allow shift+click to select an array of rows
174
+ const handleToggleItem = useCallback(
175
+ // @ts-ignore
176
+ (id, event) => {
177
+ const ids = data.map((record) => record.id);
178
+ const lastSelectedIndex = ids.indexOf(lastSelected.current);
179
+ lastSelected.current = event.target.checked ? id : null;
180
+
181
+ if (event.shiftKey && lastSelectedIndex !== -1) {
182
+ const index = ids.indexOf(id);
183
+ const idsBetweenSelections = ids.slice(Math.min(lastSelectedIndex, index), Math.max(lastSelectedIndex, index) + 1);
184
+
185
+ const newSelectedIds = event.target.checked
186
+ ? union(selectedIds, idsBetweenSelections)
187
+ : difference(selectedIds, idsBetweenSelections);
188
+
189
+ onSelect(
190
+ isRowSelectable
191
+ ? newSelectedIds.filter((id: Identifier) => isRowSelectable(data.find((record) => record.id === id)))
192
+ : newSelectedIds
193
+ );
194
+ } else {
195
+ onToggleItem(id);
196
+ }
197
+ },
198
+ [data, isRowSelectable, onSelect, onToggleItem, selectedIds]
199
+ );
200
+
201
+ if (isLoading === true) {
202
+ return (
203
+ <DatagridLoading
204
+ className={className}
205
+ expand={expand}
206
+ hasBulkActions={hasBulkActions}
207
+ nbChildren={React.Children.count(children)}
208
+ size={size}
209
+ />
210
+ );
211
+ }
212
+
213
+ /**
214
+ * Once loaded, the data for the list may be empty. Instead of
215
+ * displaying the table header with zero data rows,
216
+ * the Datagrid displays the empty component.
217
+ */
218
+ if (data == null || data.length === 0 || total === 0) {
219
+ if (empty) {
220
+ return empty;
221
+ }
222
+
223
+ return null;
224
+ }
225
+
226
+ /**
227
+ * After the initial load, if the data for the list isn't empty,
228
+ * and even if the data is refreshing (e.g. after a filter change),
229
+ * the datagrid displays the current data.
230
+ */
231
+ return (
232
+ <DatagridContextProvider value={contextValue}>
233
+ <DatagridRoot sx={sx} className={clsx(DatagridClasses.root, className)}>
234
+ {bulkActionsToolbar != null && isValidElement(bulkActionsToolbar) ? (
235
+ cloneElement<any>(bulkActionsToolbar, {
236
+ selectedIds,
237
+ total
238
+ })
239
+ ) : bulkActionButtons !== false ? (
240
+ <BulkActionsToolbar>{isValidElement(bulkActionButtons) ? bulkActionButtons : defaultBulkActionButtons}</BulkActionsToolbar>
241
+ ) : null}
242
+ <div className={DatagridClasses.tableWrapper}>
243
+ <Table ref={ref} className={DatagridClasses.table} size={size} {...sanitizeRestProps(rest)}>
244
+ {createOrCloneElement(
245
+ header,
246
+ {
247
+ children,
248
+ sort,
249
+ data,
250
+ hasExpand: !!expand,
251
+ hasBulkActions,
252
+ isRowSelectable,
253
+ onSelect,
254
+ resource,
255
+ selectedIds,
256
+ setSort
257
+ },
258
+ children
259
+ )}
260
+ {createOrCloneElement(
261
+ body,
262
+ {
263
+ expand,
264
+ rowClick,
265
+ data,
266
+ hasBulkActions,
267
+ hover,
268
+ onToggleItem: handleToggleItem,
269
+ resource,
270
+ rowSx,
271
+ rowStyle,
272
+ selectedIds,
273
+ isRowSelectable
274
+ },
275
+ children
276
+ )}
277
+ </Table>
278
+ </div>
279
+ </DatagridRoot>
280
+ </DatagridContextProvider>
281
+ );
282
+ });
283
+
284
+ // @ts-ignore
285
+ const createOrCloneElement = (element, props, children) =>
286
+ isValidElement(element) ? cloneElement(element, props, children) : createElement(element, props, children);
287
+
288
+ Datagrid.propTypes = {
289
+ // @ts-ignore
290
+ body: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
291
+ // @ts-ignore-line
292
+ bulkActionButtons: PropTypes.oneOfType([PropTypes.bool, PropTypes.element]),
293
+ children: PropTypes.node.isRequired,
294
+ className: PropTypes.string,
295
+ // @ts-ignore
296
+ sort: PropTypes.exact({
297
+ field: PropTypes.string,
298
+ order: PropTypes.oneOf(['ASC', 'DESC'] as const)
299
+ }),
300
+ data: PropTypes.arrayOf(PropTypes.any),
301
+ empty: PropTypes.element,
302
+ // @ts-ignore
303
+ expand: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
304
+ // @ts-ignore
305
+ header: PropTypes.oneOfType([PropTypes.element, PropTypes.elementType]),
306
+ hover: PropTypes.bool,
307
+ isLoading: PropTypes.bool,
308
+ onSelect: PropTypes.func,
309
+ onToggleItem: PropTypes.func,
310
+ resource: PropTypes.string,
311
+ // @ts-ignore
312
+ rowClick: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.bool]),
313
+ rowSx: PropTypes.func,
314
+ rowStyle: PropTypes.func,
315
+ selectedIds: PropTypes.arrayOf(PropTypes.any),
316
+ setSort: PropTypes.func,
317
+ total: PropTypes.number,
318
+ isRowSelectable: PropTypes.func,
319
+ isRowExpandable: PropTypes.func,
320
+ expandSingle: PropTypes.bool
321
+ };
322
+
323
+ const injectedProps = [
324
+ 'isRequired',
325
+ 'setFilter',
326
+ 'setPagination',
327
+ 'limitChoicesToValue',
328
+ 'translateChoice',
329
+ // Datagrid may be used as an alternative to SelectInput
330
+ 'field',
331
+ 'fieldState',
332
+ 'formState'
333
+ ];
334
+
335
+ // @ts-ignore
336
+ const sanitizeRestProps = (props) =>
337
+ Object.keys(sanitizeListRestProps(props))
338
+ .filter((propName) => !injectedProps.includes(propName))
339
+ .reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});
340
+
341
+ Datagrid.displayName = 'Datagrid';
342
+
343
+ const DefaultEmpty = <ListNoResults />;
344
+
345
+ export default Datagrid;
@@ -0,0 +1,13 @@
1
+ import { createContext } from 'react';
2
+ import { RaRecord } from 'ra-core';
3
+
4
+ const DatagridContext = createContext<DatagridContextValue>({});
5
+
6
+ DatagridContext.displayName = 'DatagridContext';
7
+
8
+ export type DatagridContextValue = {
9
+ isRowExpandable?: (record: RaRecord) => boolean;
10
+ expandSingle?: boolean;
11
+ };
12
+
13
+ export default DatagridContext;
@@ -0,0 +1,8 @@
1
+ import React, { ReactElement, ReactNode } from 'react';
2
+ import DatagridContext, { DatagridContextValue } from './DatagridContext';
3
+
4
+ const DatagridContextProvider = ({ children, value }: { children: ReactNode; value: DatagridContextValue }): ReactElement => (
5
+ <DatagridContext.Provider value={value}>{children}</DatagridContext.Provider>
6
+ );
7
+
8
+ export default DatagridContextProvider;
@@ -1,8 +1,9 @@
1
- import { DatagridProps, Datagrid as RaDatagrid } from 'react-admin';
1
+ import { Datagrid as RaDatagrid } from './Datagrid';
2
+ import { DatagridProps } from 'react-admin';
2
3
 
3
4
  import { styled } from '@mui/material/styles';
4
5
 
5
- const ApplicaStyledDatagrid = styled(RaDatagrid, {
6
+ const StyledDatagrid = styled(RaDatagrid, {
6
7
  name: 'ApplicaDatagrid',
7
8
  slot: 'root'
8
9
  })(() => ({
@@ -40,13 +41,9 @@ const ApplicaStyledDatagrid = styled(RaDatagrid, {
40
41
  * @param {DatagridProps} props
41
42
  * @returns {JSX.Element}
42
43
  */
43
- const Datagrid = (props: DatagridProps): JSX.Element => <ApplicaStyledDatagrid {...props} />;
44
-
45
- Datagrid.propTypes = {
46
- ...RaDatagrid.propTypes
47
- };
48
- Datagrid.defaultProps = {
49
- ...RaDatagrid.defaultProps
44
+ const Datagrid = (props: DatagridProps): JSX.Element => {
45
+ // @ts-ignore
46
+ return <StyledDatagrid {...props} />;
50
47
  };
51
48
 
52
49
  export default Datagrid;
@@ -1,5 +1,6 @@
1
- import Datagrid from './Datagrid';
2
- import Empty from './Empty';
3
- import List from './List';
4
- import NotificationList from './NotificationList';
5
- export { Datagrid, Empty, NotificationList, List };
1
+ export { default as Datagrid } from './Datagrid';
2
+ export { default as Empty } from './Empty';
3
+ export { default as NotificationList } from './NotificationList';
4
+ export { default as List } from './List';
5
+ export { default as BulkActionsToolbar } from './BulkActionsToolbar';
6
+ export { default as BulkFloatingActionsToolbar } from './BulkFloatingActionsToolbar';
@@ -0,0 +1,18 @@
1
+ import { LongForm, MainCard, TextInput } from '@applica-software-guru/react-admin';
2
+ import { Grid } from '@mui/material';
3
+
4
+ const TestModelForm = () => (
5
+ <LongForm>
6
+ <LongForm.Tab id="root" label="Root">
7
+ <MainCard title="Info">
8
+ <Grid container spacing={2}>
9
+ <Grid item xs={12}>
10
+ <TextInput source="name" fullWidth />
11
+ </Grid>
12
+ </Grid>
13
+ </MainCard>
14
+ </LongForm.Tab>
15
+ </LongForm>
16
+ );
17
+
18
+ export default TestModelForm;