+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/DatagridInput.spec.tsx b/packages/ra-ui-materialui/src/input/DatagridInput.spec.tsx
new file mode 100644
index 00000000000..39a1cdc0174
--- /dev/null
+++ b/packages/ra-ui-materialui/src/input/DatagridInput.spec.tsx
@@ -0,0 +1,11 @@
+import * as React from 'react';
+import { render, screen } from '@testing-library/react';
+
+import { Themed } from './DatagridInput.stories';
+
+describe('', () => {
+ it('should be customized by a theme', async () => {
+ render();
+ await screen.findByTestId('themed');
+ });
+});
diff --git a/packages/ra-ui-materialui/src/input/DatagridInput.stories.tsx b/packages/ra-ui-materialui/src/input/DatagridInput.stories.tsx
index 659734e4c5f..888b76127b3 100644
--- a/packages/ra-ui-materialui/src/input/DatagridInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/DatagridInput.stories.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { Admin } from 'react-admin';
import { Resource, TestMemoryRouter } from 'ra-core';
+import { createTheme } from '@mui/material/styles';
import { Edit } from '../detail';
import { SimpleForm } from '../form';
@@ -157,3 +158,30 @@ export const InsideReferenceInput = () => (
);
+
+export const Themed = () => (
+
+
+
+
+
+);
diff --git a/packages/ra-ui-materialui/src/input/DatagridInput.tsx b/packages/ra-ui-materialui/src/input/DatagridInput.tsx
index 078e3c73c10..b649fce16f1 100644
--- a/packages/ra-ui-materialui/src/input/DatagridInput.tsx
+++ b/packages/ra-ui-materialui/src/input/DatagridInput.tsx
@@ -8,13 +8,24 @@ import {
useChoicesContext,
useInput,
} from 'ra-core';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
+
import { CommonInputProps } from './CommonInputProps';
import { InputHelperText } from './InputHelperText';
import { SupportCreateSuggestionOptions } from './useSupportCreateSuggestion';
-import { Datagrid, DatagridProps } from '../list/datagrid';
-import { FilterButton, FilterForm } from '../list/filter';
-import { FilterContext } from '../list/FilterContext';
+import {
+ Datagrid,
+ DatagridProps,
+ FilterButton,
+ FilterForm,
+ FilterContext,
+} from '../list';
import { Pagination as DefaultPagination } from '../list/pagination';
+import { sanitizeInputRestProps } from './sanitizeInputRestProps';
const defaultPagination = ;
@@ -49,7 +60,12 @@ const defaultPagination = ;
*
* );
*/
-export const DatagridInput = (props: DatagridInputProps) => {
+export const DatagridInput = (inProps: DatagridInputProps) => {
+ const props = useThemeProps({
+ props: inProps,
+ name: PREFIX,
+ });
+
const {
choices,
className,
@@ -121,7 +137,7 @@ export const DatagridInput = (props: DatagridInputProps) => {
]
);
return (
-
+
{/* @ts-ignore FIXME cannot find another way to fix this error: "Types of property 'isPending' are incompatible: Type 'boolean' is not assignable to type 'false'." */}
{filters ? (
@@ -145,7 +161,7 @@ export const DatagridInput = (props: DatagridInputProps) => {
) : null}
{!fieldState.error && !fetchError && (
<>
-
+
{pagination !== false && pagination}
>
)}
@@ -153,7 +169,7 @@ export const DatagridInput = (props: DatagridInputProps) => {
error={fieldState.error?.message || fetchError?.message}
/>
-
+
);
};
@@ -169,3 +185,29 @@ export type DatagridInputProps = Omit<
filters?: ReactElement | ReactElement[];
pagination?: ReactElement | false;
};
+
+const PREFIX = 'RaDatagridInput';
+
+const Root = styled('div', {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/DateInput.spec.tsx b/packages/ra-ui-materialui/src/input/DateInput.spec.tsx
index bb71d119ba3..ea3ff106224 100644
--- a/packages/ra-ui-materialui/src/input/DateInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/DateInput.spec.tsx
@@ -14,6 +14,7 @@ import {
ExternalChanges,
ExternalChangesWithParse,
Parse,
+ Themed,
} from './DateInput.stories';
describe('', () => {
@@ -319,4 +320,9 @@ describe('', () => {
await screen.findByText('Required');
});
});
+
+ it('should be customized by a theme', async () => {
+ render();
+ await screen.findByTestId('themed');
+ });
});
diff --git a/packages/ra-ui-materialui/src/input/DateInput.stories.tsx b/packages/ra-ui-materialui/src/input/DateInput.stories.tsx
index 86640668a6c..1b94491ff44 100644
--- a/packages/ra-ui-materialui/src/input/DateInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/DateInput.stories.tsx
@@ -3,7 +3,8 @@ import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
import { minValue, useRecordContext } from 'ra-core';
import { useFormContext, useWatch } from 'react-hook-form';
-import { Box, Button, Typography } from '@mui/material';
+import { Box, Button, createTheme, Typography } from '@mui/material';
+import { ThemeOptions } from '@mui/material/styles';
import get from 'lodash/get';
import { AdminContext } from '../AdminContext';
@@ -141,16 +142,52 @@ export const ExternalChangesWithParse = ({
);
+export const Themed = ({
+ dateInputProps,
+ simpleFormProps,
+}: {
+ dateInputProps?: Partial;
+ simpleFormProps?: Partial;
+}) => (
+
+
+
+);
+
const i18nProvider = polyglotI18nProvider(() => englishMessages);
const Wrapper = ({
children,
simpleFormProps,
+ theme = undefined,
}: {
children: React.ReactNode;
simpleFormProps?: Partial;
+ theme?: ThemeOptions;
}) => (
-
+
{children}
diff --git a/packages/ra-ui-materialui/src/input/DateInput.tsx b/packages/ra-ui-materialui/src/input/DateInput.tsx
index cd3e824632b..faac05a5e84 100644
--- a/packages/ra-ui-materialui/src/input/DateInput.tsx
+++ b/packages/ra-ui-materialui/src/input/DateInput.tsx
@@ -2,6 +2,11 @@ import * as React from 'react';
import clsx from 'clsx';
import TextField, { TextFieldProps } from '@mui/material/TextField';
import { useInput, FieldTitle, useEvent } from 'ra-core';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
import { CommonInputProps } from './CommonInputProps';
import { sanitizeInputRestProps } from './sanitizeInputRestProps';
@@ -46,23 +51,28 @@ import { useForkRef } from '@mui/material';
* to convert the form value (which is always a date string) back to a Date object.
* new Date(val)} />
*/
-export const DateInput = ({
- className,
- defaultValue,
- format = defaultFormat,
- label,
- source,
- resource,
- helperText,
- margin,
- onChange,
- onFocus,
- validate,
- variant,
- disabled,
- readOnly,
- ...rest
-}: DateInputProps) => {
+export const DateInput = (props: DateInputProps) => {
+ const {
+ className,
+ defaultValue,
+ format = defaultFormat,
+ label,
+ source,
+ resource,
+ helperText,
+ margin,
+ onChange,
+ onFocus,
+ validate,
+ variant,
+ disabled,
+ readOnly,
+ ...rest
+ } = useThemeProps({
+ props: props,
+ name: PREFIX,
+ });
+
const { field, fieldState, id, isRequired } = useInput({
defaultValue,
resource,
@@ -179,7 +189,7 @@ export const DateInput = ({
const inputRef = useForkRef(ref, localInputRef);
return (
- {
// other values (e.g., localized date strings, timestamps) need to be converted to Dates first
return convertDateToString(new Date(value));
};
+
+const PREFIX = 'RaDateInput';
+
+const StyledTextField = styled(TextField, {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/DateTimeInput.spec.tsx b/packages/ra-ui-materialui/src/input/DateTimeInput.spec.tsx
index f2d3640aa6c..e52eed31257 100644
--- a/packages/ra-ui-materialui/src/input/DateTimeInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/DateTimeInput.spec.tsx
@@ -14,6 +14,7 @@ import { SaveButton } from '../button';
import {
ExternalChanges,
ExternalChangesWithParse,
+ Themed,
} from './DateTimeInput.stories';
describe('', () => {
@@ -328,4 +329,9 @@ describe('', () => {
});
});
});
+
+ it('should be customized by a theme', async () => {
+ render();
+ await screen.findByTestId('themed');
+ });
});
diff --git a/packages/ra-ui-materialui/src/input/DateTimeInput.stories.tsx b/packages/ra-ui-materialui/src/input/DateTimeInput.stories.tsx
index 2e660fc328a..16441805db7 100644
--- a/packages/ra-ui-materialui/src/input/DateTimeInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/DateTimeInput.stories.tsx
@@ -3,7 +3,8 @@ import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
import { useRecordContext } from 'ra-core';
import { useFormContext, useWatch } from 'react-hook-form';
-import { Box, Button, Typography } from '@mui/material';
+import { Box, Button, createTheme, Typography } from '@mui/material';
+import { ThemeOptions } from '@mui/material/styles';
import get from 'lodash/get';
import { AdminContext } from '../AdminContext';
@@ -96,16 +97,45 @@ export const AsDateObject = () => (
);
+export const Themed = () => (
+
+
+
+);
+
const i18nProvider = polyglotI18nProvider(() => englishMessages);
const Wrapper = ({
children,
simpleFormProps,
+ theme,
}: {
children: React.ReactNode;
simpleFormProps?: Omit;
+ theme: ThemeOptions;
}) => (
-
+
{children}
diff --git a/packages/ra-ui-materialui/src/input/DateTimeInput.tsx b/packages/ra-ui-materialui/src/input/DateTimeInput.tsx
index de9d072409e..051fad68d52 100644
--- a/packages/ra-ui-materialui/src/input/DateTimeInput.tsx
+++ b/packages/ra-ui-materialui/src/input/DateTimeInput.tsx
@@ -2,6 +2,11 @@ import * as React from 'react';
import clsx from 'clsx';
import TextField, { TextFieldProps } from '@mui/material/TextField';
import { useInput, FieldTitle } from 'ra-core';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
import { CommonInputProps } from './CommonInputProps';
import { sanitizeInputRestProps } from './sanitizeInputRestProps';
@@ -11,24 +16,29 @@ import { useForkRef } from '@mui/material';
/**
* Input component for entering a date and a time with timezone, using the browser locale
*/
-export const DateTimeInput = ({
- className,
- defaultValue,
- format = formatDateTime,
- label,
- helperText,
- margin,
- onBlur,
- onChange,
- onFocus,
- source,
- resource,
- validate,
- variant,
- disabled,
- readOnly,
- ...rest
-}: DateTimeInputProps) => {
+export const DateTimeInput = (props: DateTimeInputProps) => {
+ const {
+ className,
+ defaultValue,
+ format = formatDateTime,
+ label,
+ helperText,
+ margin,
+ onBlur,
+ onChange,
+ onFocus,
+ source,
+ resource,
+ validate,
+ variant,
+ disabled,
+ readOnly,
+ ...rest
+ } = useThemeProps({
+ props: props,
+ name: PREFIX,
+ });
+
const { field, fieldState, id, isRequired } = useInput({
defaultValue,
onBlur,
@@ -138,7 +148,7 @@ export const DateTimeInput = ({
const inputRef = useForkRef(ref, localInputRef);
return (
- {
return convertDateToString(new Date(value));
};
+
+const PREFIX = 'RaDateTimeInput';
+
+const StyledTextField = styled(TextField, {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/NumberInput.spec.tsx b/packages/ra-ui-materialui/src/input/NumberInput.spec.tsx
index ea2c78a336c..eb85b3f3994 100644
--- a/packages/ra-ui-materialui/src/input/NumberInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/NumberInput.spec.tsx
@@ -9,6 +9,7 @@ import { AdminContext } from '../AdminContext';
import { SaveButton } from '../button';
import { SimpleForm, Toolbar } from '../form';
import { required, ResourceContextProvider } from 'ra-core';
+import { Themed } from './NumberInput.stories';
describe('', () => {
const defaultProps = {
@@ -672,4 +673,9 @@ describe('', () => {
});
});
});
+
+ it('should be customized by a theme', async () => {
+ render();
+ await screen.findByTestId('themed');
+ });
});
diff --git a/packages/ra-ui-materialui/src/input/NumberInput.stories.tsx b/packages/ra-ui-materialui/src/input/NumberInput.stories.tsx
index e62f4a8736e..0ea04faa15d 100644
--- a/packages/ra-ui-materialui/src/input/NumberInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/NumberInput.stories.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { required } from 'ra-core';
import { useFormState, useFormContext } from 'react-hook-form';
+import { createTheme } from '@mui/material/styles';
import { NumberInput } from './NumberInput';
import { AdminContext } from '../AdminContext';
@@ -11,8 +12,8 @@ import { TextInput } from './TextInput';
export default { title: 'ra-ui-materialui/input/NumberInput' };
-const Wrapper = ({ children }) => (
-
+const Wrapper = ({ children, theme = undefined }) => (
+
(
);
+
+export const Themed = () => (
+
+
+
+
+);
diff --git a/packages/ra-ui-materialui/src/input/NumberInput.tsx b/packages/ra-ui-materialui/src/input/NumberInput.tsx
index 949dc799b8b..78952c2a96f 100644
--- a/packages/ra-ui-materialui/src/input/NumberInput.tsx
+++ b/packages/ra-ui-materialui/src/input/NumberInput.tsx
@@ -2,6 +2,11 @@ import * as React from 'react';
import clsx from 'clsx';
import TextField, { TextFieldProps } from '@mui/material/TextField';
import { useInput, FieldTitle } from 'ra-core';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
import { CommonInputProps } from './CommonInputProps';
import { InputHelperText } from './InputHelperText';
@@ -18,29 +23,34 @@ import { sanitizeInputRestProps } from './sanitizeInputRestProps';
*
*
*/
-export const NumberInput = ({
- className,
- defaultValue = null,
- format = convertNumberToString,
- helperText,
- label,
- margin,
- onChange,
- onBlur,
- onFocus,
- parse,
- resource,
- source,
- step = 'any',
- min,
- max,
- validate,
- variant,
- inputProps: overrideInputProps,
- disabled,
- readOnly,
- ...rest
-}: NumberInputProps) => {
+export const NumberInput = (props: NumberInputProps) => {
+ const {
+ className,
+ defaultValue = null,
+ format = convertNumberToString,
+ helperText,
+ label,
+ margin,
+ onChange,
+ onBlur,
+ onFocus,
+ parse,
+ resource,
+ source,
+ step = 'any',
+ min,
+ max,
+ validate,
+ variant,
+ inputProps: overrideInputProps,
+ disabled,
+ readOnly,
+ ...rest
+ } = useThemeProps({
+ props: props,
+ name: PREFIX,
+ });
+
const {
field,
fieldState: { error, invalid },
@@ -124,7 +134,7 @@ export const NumberInput = ({
const { ref, ...fieldWithoutRef } = field;
return (
- {
const convertNumberToString = value =>
value == null || isNaN(value) ? '' : value.toString();
+
+const PREFIX = 'RaNumberInput';
+
+const StyledTextField = styled(TextField, {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/PasswordInput.spec.tsx b/packages/ra-ui-materialui/src/input/PasswordInput.spec.tsx
new file mode 100644
index 00000000000..658772da728
--- /dev/null
+++ b/packages/ra-ui-materialui/src/input/PasswordInput.spec.tsx
@@ -0,0 +1,11 @@
+import * as React from 'react';
+import { render, screen } from '@testing-library/react';
+
+import { Themed } from './PasswordInput.stories';
+
+describe('', () => {
+ it('should be customized by a theme', async () => {
+ render();
+ await screen.findByTestId('themed');
+ });
+});
diff --git a/packages/ra-ui-materialui/src/input/PasswordInput.stories.tsx b/packages/ra-ui-materialui/src/input/PasswordInput.stories.tsx
index ef998eb1557..dc3c6e711c8 100644
--- a/packages/ra-ui-materialui/src/input/PasswordInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/PasswordInput.stories.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
+import { createTheme } from '@mui/material/styles';
import { AdminContext } from '../AdminContext';
import { Create } from '../detail';
@@ -35,10 +36,33 @@ export const ReadOnly = () => (
);
+export const Themed = () => (
+
+
+
+);
+
const i18nProvider = polyglotI18nProvider(() => englishMessages);
-const Wrapper = ({ children }) => (
-
+const Wrapper = ({ children, theme = undefined }) => (
+
{children}
diff --git a/packages/ra-ui-materialui/src/input/PasswordInput.tsx b/packages/ra-ui-materialui/src/input/PasswordInput.tsx
index 4caa084bb84..7535cec8fd5 100644
--- a/packages/ra-ui-materialui/src/input/PasswordInput.tsx
+++ b/packages/ra-ui-materialui/src/input/PasswordInput.tsx
@@ -4,11 +4,19 @@ import { useTranslate } from 'ra-core';
import { InputAdornment, IconButton } from '@mui/material';
import Visibility from '@mui/icons-material/Visibility';
import VisibilityOff from '@mui/icons-material/VisibilityOff';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
import { TextInput, TextInputProps } from './TextInput';
export const PasswordInput = (props: PasswordInputProps) => {
- const { initiallyVisible = false, ...rest } = props;
+ const { initiallyVisible = false, ...rest } = useThemeProps({
+ props: props,
+ name: PREFIX,
+ });
const [visible, setVisible] = useState(initiallyVisible);
const translate = useTranslate();
@@ -17,7 +25,7 @@ export const PasswordInput = (props: PasswordInputProps) => {
};
return (
- {
export interface PasswordInputProps extends TextInputProps {
initiallyVisible?: boolean;
}
+
+const PREFIX = 'RaPasswordInput';
+
+const StyledTextInput = styled(TextInput, {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx
index 1e6b3d0d1b7..408651685a0 100644
--- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.spec.tsx
@@ -13,6 +13,7 @@ import { SimpleForm } from '../form';
import { RadioButtonGroupInput } from './RadioButtonGroupInput';
import {
InsideReferenceArrayInput,
+ Themed,
TranslateChoice,
} from './RadioButtonGroupInput.stories';
@@ -310,6 +311,12 @@ describe('', () => {
expect(screen.queryByText('Mastercard')).not.toBeNull();
});
+ it('should be customized by a theme', async () => {
+ render();
+ const inputs = await screen.findAllByTestId('themed');
+ expect(inputs).toHaveLength(3);
+ });
+
describe('translateChoice', () => {
it('should translate the choices by default', async () => {
render();
diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx
index cce3f60a48a..09c483ce6fe 100644
--- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInput.stories.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
+import { createTheme } from '@mui/material/styles';
import { AdminContext } from '../AdminContext';
import { Create, Edit } from '../detail';
@@ -178,8 +179,12 @@ export const Id = () => (
);
const i18nProvider = polyglotI18nProvider(() => englishMessages);
-const Wrapper = ({ children }) => (
-
+const Wrapper = ({ children, theme = undefined }) => (
+
{children}
@@ -272,3 +277,24 @@ export const TranslateChoice = () => {
);
};
+
+export const Themed = () => (
+
+
+
+);
diff --git a/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx b/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx
index 72761931f77..50d304740d9 100644
--- a/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx
+++ b/packages/ra-ui-materialui/src/input/RadioButtonGroupInputItem.tsx
@@ -1,15 +1,30 @@
import * as React from 'react';
import FormControlLabel from '@mui/material/FormControlLabel';
import Radio from '@mui/material/Radio';
-import { useChoices } from 'ra-core';
-
-export const RadioButtonGroupInputItem = ({
- choice,
- optionText,
- optionValue,
- source,
- translateChoice,
-}) => {
+import { type ChoicesProps, useChoices } from 'ra-core';
+import { FormControlLabelProps } from '@mui/material';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
+import { sanitizeInputRestProps } from './sanitizeInputRestProps';
+
+export const RadioButtonGroupInputItem = (
+ props: RadioButtonGroupInputItemProps
+) => {
+ const {
+ choice,
+ optionText,
+ optionValue,
+ source,
+ translateChoice,
+ ...rest
+ } = useThemeProps({
+ props: props,
+ name: PREFIX,
+ });
+
const { getChoiceText, getChoiceValue } = useChoices({
optionText,
optionValue,
@@ -21,13 +36,47 @@ export const RadioButtonGroupInputItem = ({
const nodeId = `${source}_${value}`;
return (
- }
+ {...sanitizeInputRestProps(rest)}
/>
);
};
export default RadioButtonGroupInputItem;
+
+export interface RadioButtonGroupInputItemProps
+ extends Omit,
+ Pick {
+ choice: any;
+ source: any;
+}
+
+const PREFIX = 'RaRadioButtonGroupInputItem';
+
+const StyledFormControlLabel = styled(FormControlLabel, {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/TextInput.spec.tsx b/packages/ra-ui-materialui/src/input/TextInput.spec.tsx
index 08820056915..b63c605b716 100644
--- a/packages/ra-ui-materialui/src/input/TextInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/TextInput.spec.tsx
@@ -5,7 +5,7 @@ import { required, ResourceContextProvider, testDataProvider } from 'ra-core';
import { AdminContext } from '../AdminContext';
import { SimpleForm } from '../form';
import { TextInput } from './TextInput';
-import { ValueNull, Parse } from './TextInput.stories';
+import { ValueNull, Parse, Themed } from './TextInput.stories';
describe('', () => {
const defaultProps = {
@@ -245,4 +245,9 @@ describe('', () => {
expect(container.querySelector(`label`)).toBeNull();
});
});
+
+ it('should be customized by a theme', async () => {
+ render();
+ await screen.findByTestId('themed');
+ });
});
diff --git a/packages/ra-ui-materialui/src/input/TextInput.stories.tsx b/packages/ra-ui-materialui/src/input/TextInput.stories.tsx
index 1753abc722d..e5e99448eb0 100644
--- a/packages/ra-ui-materialui/src/input/TextInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/TextInput.stories.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { required, Resource } from 'ra-core';
import { useFormState, useFormContext } from 'react-hook-form';
+import { createTheme } from '@mui/material/styles';
import { TextInput } from './TextInput';
import { AdminContext } from '../AdminContext';
@@ -13,8 +14,8 @@ import { MemoryRouter } from 'react-router';
export default { title: 'ra-ui-materialui/input/TextInput' };
-const Wrapper = ({ children }) => (
-
+const Wrapper = ({ children, theme = undefined }) => (
+
(
);
+
+export const Themed = () => (
+
+
+
+
+);
diff --git a/packages/ra-ui-materialui/src/input/TextInput.tsx b/packages/ra-ui-materialui/src/input/TextInput.tsx
index ccbd0e9fb8b..e3a2b4ce2e5 100644
--- a/packages/ra-ui-materialui/src/input/TextInput.tsx
+++ b/packages/ra-ui-materialui/src/input/TextInput.tsx
@@ -1,6 +1,11 @@
import * as React from 'react';
import clsx from 'clsx';
import { useInput, FieldTitle } from 'ra-core';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
import { CommonInputProps } from './CommonInputProps';
import {
@@ -37,7 +42,11 @@ export const TextInput = (props: TextInputProps) => {
source,
validate,
...rest
- } = props;
+ } = useThemeProps({
+ props: props,
+ name: PREFIX,
+ });
+
const {
field,
fieldState: { error, invalid },
@@ -59,7 +68,7 @@ export const TextInput = (props: TextInputProps) => {
const renderHelperText = helperText !== false || invalid;
return (
- {
export type TextInputProps = CommonInputProps &
Omit;
+
+const PREFIX = 'RaTextInput';
+
+const StyledResettableTextField = styled(ResettableTextField, {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/TimeInput.spec.tsx b/packages/ra-ui-materialui/src/input/TimeInput.spec.tsx
index 2df9478ee92..9568f163380 100644
--- a/packages/ra-ui-materialui/src/input/TimeInput.spec.tsx
+++ b/packages/ra-ui-materialui/src/input/TimeInput.spec.tsx
@@ -10,6 +10,7 @@ import { SimpleForm, Toolbar } from '../form';
import { TimeInput } from './TimeInput';
import { ArrayInput, SimpleFormIterator } from './ArrayInput';
import { SaveButton } from '../button';
+import { Themed } from './TimeInput.stories';
describe('', () => {
const defaultProps = {
@@ -274,4 +275,9 @@ describe('', () => {
});
});
});
+
+ it('should be customized by a theme', async () => {
+ render();
+ await screen.findByTestId('themed');
+ });
});
diff --git a/packages/ra-ui-materialui/src/input/TimeInput.stories.tsx b/packages/ra-ui-materialui/src/input/TimeInput.stories.tsx
index 6a73afc9614..45c56b46f2e 100644
--- a/packages/ra-ui-materialui/src/input/TimeInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/TimeInput.stories.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
+import { createTheme } from '@mui/material/styles';
import { AdminContext } from '../AdminContext';
import { Create } from '../detail';
@@ -41,10 +42,37 @@ export const OutlinedNoLabel = () => (
);
+export const Themed = () => (
+
+
+
+);
+
const i18nProvider = polyglotI18nProvider(() => englishMessages);
-const Wrapper = ({ children }) => (
-
+const Wrapper = ({ children, theme = undefined }) => (
+
{children}
diff --git a/packages/ra-ui-materialui/src/input/TimeInput.tsx b/packages/ra-ui-materialui/src/input/TimeInput.tsx
index cf69444e004..846ea5ff7da 100644
--- a/packages/ra-ui-materialui/src/input/TimeInput.tsx
+++ b/packages/ra-ui-materialui/src/input/TimeInput.tsx
@@ -2,6 +2,11 @@ import * as React from 'react';
import clsx from 'clsx';
import TextField, { TextFieldProps } from '@mui/material/TextField';
import { useInput, FieldTitle } from 'ra-core';
+import {
+ ComponentsOverrides,
+ styled,
+ useThemeProps,
+} from '@mui/material/styles';
import { CommonInputProps } from './CommonInputProps';
import { sanitizeInputRestProps } from './sanitizeInputRestProps';
@@ -43,24 +48,29 @@ const parseTime = (value: string) => {
*
* );
*/
-export const TimeInput = ({
- className,
- defaultValue,
- format = formatTime,
- label,
- helperText,
- margin,
- onBlur,
- onChange,
- source,
- resource,
- disabled,
- readOnly,
- parse = parseTime,
- validate,
- variant,
- ...rest
-}: TimeInputProps) => {
+export const TimeInput = (props: TimeInputProps) => {
+ const {
+ className,
+ defaultValue,
+ format = formatTime,
+ label,
+ helperText,
+ margin,
+ onBlur,
+ onChange,
+ source,
+ resource,
+ disabled,
+ readOnly,
+ parse = parseTime,
+ validate,
+ variant,
+ ...rest
+ } = useThemeProps({
+ props: props,
+ name: PREFIX,
+ });
+
const { field, fieldState, id, isRequired } = useInput({
defaultValue,
format,
@@ -80,7 +90,7 @@ export const TimeInput = ({
const renderHelperText = helperText !== false || invalid;
return (
- {
return convertDateToString(new Date(value));
};
+
+const PREFIX = 'RaTimeInput';
+
+const StyledTextField = styled(TextField, {
+ name: PREFIX,
+ overridesResolver: (props, styles) => styles.root,
+})({});
+
+declare module '@mui/material/styles' {
+ interface ComponentNameToClassKey {
+ [PREFIX]: 'root';
+ }
+
+ interface ComponentsPropsList {
+ [PREFIX]: Partial;
+ }
+
+ interface Components {
+ [PREFIX]?: {
+ defaultProps?: ComponentsPropsList[typeof PREFIX];
+ styleOverrides?: ComponentsOverrides<
+ Omit
+ >[typeof PREFIX];
+ };
+ }
+}
diff --git a/packages/ra-ui-materialui/src/input/sanitizeInputRestProps.ts b/packages/ra-ui-materialui/src/input/sanitizeInputRestProps.ts
index 14561eb19b4..4d843ed54ea 100644
--- a/packages/ra-ui-materialui/src/input/sanitizeInputRestProps.ts
+++ b/packages/ra-ui-materialui/src/input/sanitizeInputRestProps.ts
@@ -41,5 +41,6 @@ export const sanitizeInputRestProps = ({
validate,
validateFields,
value,
+ fullWidth,
...rest
}: any) => rest;
diff --git a/packages/ra-ui-materialui/src/list/List.stories.tsx b/packages/ra-ui-materialui/src/list/List.stories.tsx
index 4bf5ba41d29..90189f61f78 100644
--- a/packages/ra-ui-materialui/src/list/List.stories.tsx
+++ b/packages/ra-ui-materialui/src/list/List.stories.tsx
@@ -30,7 +30,7 @@ import { ShowGuesser } from '../detail';
import TopToolbar from '../layout/TopToolbar';
import { BulkActionsToolbar } from './BulkActionsToolbar';
import { deepmerge } from '@mui/utils';
-import { defaultLightTheme, RaThemeOptions } from '../theme';
+import { defaultLightTheme } from '../theme';
export default { title: 'ra-ui-materialui/list/List' };