@applica-software-guru/react-admin 1.5.237 → 1.5.240

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.
package/package.json CHANGED
@@ -115,5 +115,5 @@
115
115
  "type": "module",
116
116
  "types": "dist/index.d.ts",
117
117
  "typings": "dist/index.d.ts",
118
- "version": "1.5.237"
118
+ "version": "1.5.240"
119
119
  }
@@ -21,6 +21,11 @@ const StyledMenuPopover = styled(MenuPopover, {
21
21
  margin: 0,
22
22
  '& .MuiButton-startIcon': {
23
23
  marginRight: theme.spacing(0)
24
+ },
25
+ [theme.breakpoints.down('sm')]: {
26
+ '&>.MuiSvgIcon-root, & svg': {
27
+ marginRight: theme.spacing(0)
28
+ }
24
29
  }
25
30
  }
26
31
  }));
@@ -0,0 +1,84 @@
1
+ import { Button as MuiButton } from '@mui/material';
2
+ import { styled } from '@mui/material/styles';
3
+ import { LocationDescriptor, Button as RaButton, ButtonProps as RaButtonProps, useTranslate } from 'react-admin';
4
+
5
+ type ButtonProps = RaButtonProps & {
6
+ /**
7
+ * Disable icon only in small screens.
8
+ */
9
+ disableIconOnly?: boolean;
10
+ };
11
+
12
+ const PREFIX = 'RaButton';
13
+ function getLinkParams(locationDescriptor?: LocationDescriptor | string) {
14
+ // eslint-disable-next-line eqeqeq
15
+ if (locationDescriptor == undefined) {
16
+ return undefined;
17
+ }
18
+
19
+ if (typeof locationDescriptor === 'string') {
20
+ return { to: locationDescriptor };
21
+ }
22
+
23
+ const { redirect, replace, state, ...to } = locationDescriptor;
24
+ return {
25
+ to,
26
+ redirect,
27
+ replace,
28
+ state
29
+ };
30
+ }
31
+ const StyledButton = styled(MuiButton, {
32
+ name: PREFIX,
33
+ overridesResolver: (_props, styles) => styles.root
34
+ })({
35
+ '&.MuiButton-sizeSmall': {
36
+ // fix for icon misalignment on small buttons, see https://github.com/mui/material-ui/pull/30240
37
+ lineHeight: 1.5
38
+ }
39
+ });
40
+
41
+ /**
42
+ * A button that can be displayed as a floating button on small screens.
43
+ * @param props The component props.
44
+ * @returns The component.
45
+ */
46
+ function Button(props: ButtonProps): JSX.Element {
47
+ const {
48
+ disableIconOnly = false,
49
+ label,
50
+ children,
51
+ className,
52
+ color,
53
+ size,
54
+ disabled,
55
+ alignIcon,
56
+ to: locationDescriptor,
57
+ ...rest
58
+ } = props;
59
+ const translate = useTranslate();
60
+ const linkParams = getLinkParams(locationDescriptor);
61
+
62
+ if (disableIconOnly) {
63
+ const translatedLabel = label ? translate(label, { _: label }) : undefined;
64
+ return (
65
+ <StyledButton
66
+ className={className}
67
+ color={color}
68
+ size={size}
69
+ aria-label={translatedLabel}
70
+ disabled={disabled}
71
+ startIcon={alignIcon === 'left' && children ? children : undefined}
72
+ endIcon={alignIcon === 'right' && children ? children : undefined}
73
+ {...linkParams}
74
+ {...rest}
75
+ >
76
+ {translatedLabel}
77
+ </StyledButton>
78
+ );
79
+ }
80
+ return <RaButton {...props} />;
81
+ }
82
+
83
+ export { Button };
84
+ export type { ButtonProps };
@@ -1,7 +1,9 @@
1
+ import { Button as RaButton } from './Button';
1
2
  import { Toolbar } from '@/components/ra-forms';
2
- import { Breakpoint, Dialog } from '@mui/material';
3
- import { CreateBase, UseCreateMutateParams, useResourceContext } from 'ra-core';
4
- import { Button, CreateButton, CreateButtonProps, CreateProps, SaveButton } from 'ra-ui-materialui';
3
+ import { PlusCircleOutlined } from '@ant-design/icons';
4
+ import { Breakpoint, Button, Dialog } from '@mui/material';
5
+ import { CreateBase, UseCreateMutateParams, useResourceContext, useTranslate } from 'ra-core';
6
+ import { ButtonProps, CreateButton, CreateButtonProps, CreateProps, SaveButton } from 'ra-ui-materialui';
5
7
  import React, { Children, PropsWithChildren, useCallback, useState } from 'react';
6
8
  import { FieldValues, useFormContext } from 'react-hook-form';
7
9
  import { useQueryClient } from 'react-query';
@@ -27,11 +29,14 @@ function setListQueryData(res: any, data: any) {
27
29
  return res && res.data ? { ...res, data: updateColl(res.data, data), total: res.total + 1 } : res;
28
30
  }
29
31
 
30
- type ResponsiveButtonProps = CreateButtonProps & {
31
- label?: string;
32
- onClick?: () => void;
33
- };
32
+ type ResponsiveButtonProps = CreateButtonProps &
33
+ ButtonProps & {
34
+ label?: string;
35
+ onClick?: () => void;
36
+ disableFloatingButton?: boolean;
37
+ };
34
38
  function ResponsiveButton(props: ResponsiveButtonProps): JSX.Element {
39
+ const { disableFloatingButton, startIcon = <PlusCircleOutlined />, ...rest } = props;
35
40
  const handleClick = useCallback(
36
41
  (event: any) => {
37
42
  (event as Event).preventDefault();
@@ -40,7 +45,15 @@ function ResponsiveButton(props: ResponsiveButtonProps): JSX.Element {
40
45
  },
41
46
  [props]
42
47
  );
43
- return <CreateButton {...props} onClick={handleClick} />;
48
+ return disableFloatingButton ? (
49
+ <RaButton {...rest} onClick={handleClick}>
50
+ {startIcon as any}
51
+ </RaButton>
52
+ ) : (
53
+ <CreateButton {...props} onClick={handleClick}>
54
+ {startIcon as any}
55
+ </CreateButton>
56
+ );
44
57
  }
45
58
  type CloseDialogFunction = () => void;
46
59
  type SubmitFunction = (values: FieldValues, closeDialog: CloseDialogFunction) => void;
@@ -51,6 +64,7 @@ type SubmitButtonProps = {
51
64
  function SubmitButton(props: SubmitButtonProps) {
52
65
  const { onSubmit, closeDialog } = props;
53
66
  const { handleSubmit } = useFormContext();
67
+ const translate = useTranslate();
54
68
  const handleClick = useCallback(
55
69
  (event: any) => {
56
70
  (event as Event).preventDefault();
@@ -59,7 +73,11 @@ function SubmitButton(props: SubmitButtonProps) {
59
73
  },
60
74
  [handleSubmit, onSubmit, closeDialog]
61
75
  );
62
- return <Button onClick={handleClick} label="ra.action.save" color="primary" variant="contained" size="medium" />;
76
+ return (
77
+ <Button onClick={handleClick} color="primary" variant="contained" size="medium">
78
+ {translate('ra.action.save')}
79
+ </Button>
80
+ );
63
81
  }
64
82
  type CreateInDialogButtonProps = PropsWithChildren &
65
83
  CreateProps &
@@ -67,6 +85,12 @@ type CreateInDialogButtonProps = PropsWithChildren &
67
85
  maxWidth: Breakpoint;
68
86
  fullWidth?: boolean;
69
87
  fullScreen?: boolean;
88
+ /**
89
+ * Indicates whether the floating button should be disabled.
90
+ * Default is false, this mean that the floating button will be displayed on small screens.
91
+ * **If you have multiple buttons on the same page, they will be displayed over each other! **
92
+ */
93
+ disableFloatingButton?: boolean;
70
94
  scroll: 'paper' | 'body' | undefined;
71
95
  /**
72
96
  * Custom handler for the submit event, in this case you are responsible for closing the dialog.
@@ -89,6 +113,7 @@ function CreateInDialogButton(props: CreateInDialogButtonProps) {
89
113
  const { children, maxWidth = 'md', fullWidth = true, fullScreen, onSubmit, mutationOptions, scroll, ...rest } = props;
90
114
  const queryClient = useQueryClient();
91
115
  const resource = useResourceContext();
116
+ const translate = useTranslate();
92
117
  const Child = Children.only(children);
93
118
  const [open, setOpen] = useState(false);
94
119
  const handleOpen = useCallback(() => setOpen(true), []);
@@ -116,7 +141,7 @@ function CreateInDialogButton(props: CreateInDialogButtonProps) {
116
141
 
117
142
  return (
118
143
  <>
119
- <ResponsiveButton {...rest} onClick={handleOpen} />
144
+ <ResponsiveButton {...(rest as any)} onClick={handleOpen} />
120
145
  <CreateBase
121
146
  {...props}
122
147
  mutationOptions={{
@@ -131,6 +156,11 @@ function CreateInDialogButton(props: CreateInDialogButtonProps) {
131
156
  maxWidth={maxWidth}
132
157
  fullWidth={fullWidth}
133
158
  fullScreen={fullScreen}
159
+ sx={{
160
+ '& .MuiToolbar-root': {
161
+ position: 'relative !important'
162
+ }
163
+ }}
134
164
  >
135
165
  {React.isValidElement(Child)
136
166
  ? React.cloneElement(Child, {
@@ -138,7 +168,9 @@ function CreateInDialogButton(props: CreateInDialogButtonProps) {
138
168
  modal: true,
139
169
  toolbar: (
140
170
  <Toolbar>
141
- <Button variant="text" size="medium" label="ra.action.cancel" onClick={handleClose} />
171
+ <Button variant="text" size="medium" onClick={handleClose}>
172
+ {translate('ra.action.cancel')}
173
+ </Button>
142
174
  {onSubmit ? (
143
175
  <SubmitButton onSubmit={onSubmit!} closeDialog={handleClose} />
144
176
  ) : (
@@ -1,8 +1,10 @@
1
+ import { Button } from './Button';
1
2
  import { Toolbar } from '@/components/ra-forms';
2
3
  import { Breakpoint, Dialog } from '@mui/material';
3
4
  import { EditBase, UseUpdateMutateParams, useRecordContext } from 'ra-core';
4
- import { Button, EditButton, EditProps, SaveButton } from 'ra-ui-materialui';
5
+ import { EditButton, EditProps, SaveButton } from 'ra-ui-materialui';
5
6
  import React, { Children, PropsWithChildren, useCallback, useState } from 'react';
7
+ import { FieldValues, useFormContext } from 'react-hook-form';
6
8
 
7
9
  type ResponsiveButtonProps = {
8
10
  label?: string;
@@ -21,6 +23,34 @@ function ResponsiveButton(props: ResponsiveButtonProps): JSX.Element {
21
23
  return <EditButton {...props} onClick={handleClick} />;
22
24
  }
23
25
 
26
+ type CloseDialogFunction = () => void;
27
+ type SubmitFunction = (values: FieldValues, closeDialog: CloseDialogFunction) => void;
28
+ type SubmitButtonProps = {
29
+ onSubmit: SubmitFunction;
30
+ closeDialog: CloseDialogFunction;
31
+ };
32
+ function SubmitButton(props: SubmitButtonProps) {
33
+ const { onSubmit, closeDialog } = props;
34
+ const { handleSubmit } = useFormContext();
35
+ const handleClick = useCallback(
36
+ (event: any) => {
37
+ (event as Event).preventDefault();
38
+ (event as Event).stopPropagation();
39
+ handleSubmit((fieldValues) => onSubmit(fieldValues, closeDialog))();
40
+ },
41
+ [handleSubmit, onSubmit, closeDialog]
42
+ );
43
+ return (
44
+ <Button
45
+ disableIconOnly
46
+ onClick={handleClick}
47
+ color="primary"
48
+ variant="contained"
49
+ size="medium"
50
+ label="ra.action.save"
51
+ />
52
+ );
53
+ }
24
54
  type EditInDialogButtonProps = PropsWithChildren &
25
55
  EditProps &
26
56
  ResponsiveButtonProps & {
@@ -28,9 +58,25 @@ type EditInDialogButtonProps = PropsWithChildren &
28
58
  fullWidth?: boolean;
29
59
  fullScreen?: boolean;
30
60
  scroll: 'paper' | 'body' | undefined;
61
+ /**
62
+ * Custom handler for the submit event, in this case you are responsible for closing the dialog.
63
+ * @example
64
+ *
65
+ * const handleSubmit = (values, closeDialog) => {
66
+ * console.log(values); // { title: 'Hello World' }
67
+ * closeDialog();
68
+ * }
69
+ * <CreateInDialogButton onSubmit={handleSubmit}>
70
+ * <SimpleForm>
71
+ * <TextInput source="title" />
72
+ * </SimpleForm>
73
+ * </CreateInDialogButton>
74
+ *
75
+ */
76
+ onSubmit?: SubmitFunction;
31
77
  };
32
78
  function EditInDialogButton(props: EditInDialogButtonProps): JSX.Element {
33
- const { children, maxWidth = 'md', fullWidth = true, fullScreen, mutationOptions, scroll, ...rest } = props;
79
+ const { children, maxWidth = 'md', fullWidth = true, fullScreen, mutationOptions, onSubmit, scroll, ...rest } = props;
34
80
  const [open, setOpen] = useState(false);
35
81
  const Child = Children.only(children);
36
82
  const handleOpen = useCallback(() => setOpen(true), []);
@@ -63,6 +109,11 @@ function EditInDialogButton(props: EditInDialogButtonProps): JSX.Element {
63
109
  maxWidth={maxWidth}
64
110
  fullScreen={fullScreen}
65
111
  keepMounted={false}
112
+ sx={{
113
+ '& .MuiToolbar-root': {
114
+ position: 'relative !important'
115
+ }
116
+ }}
66
117
  >
67
118
  {React.isValidElement(Child)
68
119
  ? React.cloneElement(Child, {
@@ -70,8 +121,18 @@ function EditInDialogButton(props: EditInDialogButtonProps): JSX.Element {
70
121
  modal: true,
71
122
  toolbar: (
72
123
  <Toolbar>
73
- <Button variant="text" size="medium" label="ra.action.cancel" onClick={handleClose} />
74
- <SaveButton type="button" />
124
+ <Button
125
+ disableIconOnly
126
+ variant="text"
127
+ size="medium"
128
+ onClick={handleClose}
129
+ label="ra.action.cancel"
130
+ />
131
+ {onSubmit ? (
132
+ <SubmitButton onSubmit={onSubmit!} closeDialog={handleClose} />
133
+ ) : (
134
+ <SaveButton type="button" />
135
+ )}
75
136
  </Toolbar>
76
137
  )
77
138
  })
@@ -1,3 +1,4 @@
1
+ export * from './Button';
1
2
  export * from './CreateInDialogButton';
2
3
  export * from './EditInDialogButton';
3
4
  export * from './ImpersonateUserButton';
@@ -6,6 +6,7 @@ const StyledToolbar = styled(RaToolbar, { slot: 'Root' })(({ theme }: { theme: a
6
6
  ...theme.mixins.toolbar,
7
7
  backgroundColor: theme.palette.background.paper,
8
8
  justifyContent: 'flex-end',
9
+ position: 'initial !important',
9
10
 
10
11
  '& .RaToolbar-defaultToolbar': {
11
12
  justifyContent: 'right',
@@ -20,8 +21,7 @@ const StyledToolbar = styled(RaToolbar, { slot: 'Root' })(({ theme }: { theme: a
20
21
  }));
21
22
 
22
23
  function Toolbar(props: ToolbarProps): JSX.Element {
23
- // @ts-ignore
24
- return <StyledToolbar {...props} />;
24
+ return <StyledToolbar {...(props as any)} />;
25
25
  }
26
26
 
27
27
  export { Toolbar };
package/src/index.ts CHANGED
@@ -13,7 +13,6 @@ export {
13
13
  ArrayInputContext,
14
14
  BooleanField,
15
15
  BulkDeleteWithConfirmButton,
16
- Button,
17
16
  ChipField,
18
17
  Confirm,
19
18
  CreateButton,
@@ -16,7 +16,7 @@ import {
16
16
 
17
17
  function CategoryAddButton() {
18
18
  return (
19
- <CreateInDialogButton maxWidth="sm" redirect="list" size="small" variant="text">
19
+ <CreateInDialogButton maxWidth="sm" redirect="list" size="medium" variant="text">
20
20
  <CategoryForm />
21
21
  </CreateInDialogButton>
22
22
  );
@@ -27,7 +27,7 @@ function CategorySubmitButton() {
27
27
  console.log(values);
28
28
  }
29
29
  return (
30
- <CreateInDialogButton onSubmit={handleSubmit} redirect="list" label="Submit">
30
+ <CreateInDialogButton onSubmit={handleSubmit} redirect="list" label="Submit" size="medium">
31
31
  <SimpleForm>
32
32
  <TextInput source="description" validate={required()} fullWidth />
33
33
  </SimpleForm>
@@ -55,6 +55,9 @@ function CategoryList() {
55
55
  <EditInDialogButton>
56
56
  <CategoryForm />
57
57
  </EditInDialogButton>
58
+ <EditInDialogButton label="Edit with Submit" onSubmit={console.log}>
59
+ <CategoryForm />
60
+ </EditInDialogButton>
58
61
  </Datagrid>
59
62
  </List>
60
63
  );
@@ -41,15 +41,15 @@ function RolesInput({ record, source, roles, ...props }) {
41
41
  );
42
42
  }
43
43
 
44
- function ImageField({ record }) {
44
+ function ImageField(record) {
45
45
  return <CoverField source="image" record={record} width={50} height={50} circle />;
46
46
  }
47
47
 
48
- function NameField({ record }) {
48
+ function NameField(record) {
49
49
  return record.name;
50
50
  }
51
51
 
52
- function SecondaryField({ record }) {
52
+ function SecondaryField(record) {
53
53
  return record.email;
54
54
  }
55
55