Skip to content

make the remove icon of the file preview configurable and default to RemoveCircle #8756

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 24, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions docs/FileInput.md
Original file line number Diff line number Diff line change
@@ -53,16 +53,17 @@ Files are accepted or rejected based on the `accept`, `multiple`, `minSize` and

## Props

| Prop | Required | Type | Default | Description |
|------------------------|----------|---------------------|------------|---------------------------------------------------------------------|
| `accept` | Optional | `string | string[]` | - | Accepted file type(s). When empty, all file types are accepted. |
| `children` | Optional | `ReactNode` | - | Element used to preview file(s) |
| `minSize` | Optional | `number` | 0 | Minimum file size (in bytes), e.g. 5000 for 5KB |
| Prop | Required | Type | Default | Description |
|------------------------|----------|---------------------|-----------|---------------------------------------------------------------------|
| `accept` | Optional | `string | string[]` | - | Accepted file type(s). When empty, all file types are accepted. |
| `children` | Optional | `ReactNode` | - | Element used to preview file(s) |
| `minSize` | Optional | `number` | 0 | Minimum file size (in bytes), e.g. 5000 for 5KB |
| `maxSize` | Optional | `number` | `Infinity` | Maximum file size (in bytes), e.g. 5000000 for 5MB |
| `multiple` | Optional | `boolean` | `false` | Whether the inputs can accept multiple files. |
| `options` | Optional | `Object` | `{}` | Additional options passed to react-dropzone's `useDropzone()` hook. |
| `placeholder` | Optional | `ReactNode` | - | Invite displayed in the drop zone |
| `validateFile Removal` | Optional | `function` | - | Allows to cancel the removal of files |
| `multiple` | Optional | `boolean` | `false` | Whether the inputs can accept multiple files. |
| `options` | Optional | `Object` | `{}` | Additional options passed to react-dropzone's `useDropzone()` hook. |
| `placeholder` | Optional | `ReactNode` | - | Invite displayed in the drop zone |
| `removeIcon` | Optional | `ReactNode` | [MUI's RemoveCircle icon](https://mui.com/material-ui/material-icons/?query=removeCir&selected=RemoveCircle) | The clickable icon for removing files |
| `validateFile Removal` | Optional | `function` | - | Allows to cancel the removal of files |

`<FileInput>` also accepts the [common input props](./Inputs.md#common-input-props).

@@ -152,6 +153,16 @@ If that's not enough, you can pass a `placeholder` prop to overwrite it. The val
</FileInput>
```

## `removeIcon`

Use the `removeIcon` prop to change the icon displayed as the remove button:

```jsx
<ImageInput source="attachments" removeIcon={CustomSvgIcon}>
<ImageField source="src" title="title" />
</ImageInput>
```

## `sx`: CSS API

The `<FileInput>` component accepts the usual `className` prop. You can also override many styles of the inner components thanks to the `sx` property (as most MUI components, see their [documentation about it](https://mui.com/customization/how-to-customize/#overriding-nested-component-styles)). This property accepts the following subclasses:
13 changes: 12 additions & 1 deletion docs/ImageInput.md
Original file line number Diff line number Diff line change
@@ -53,13 +53,14 @@ Files are accepted or rejected based on the `accept`, `multiple`, `minSize` and

| Prop | Required | Type | Default | Description |
|------------------------|----------|---------------------|------------|---------------------------------------------------------------------|
| `accept` | Optional | `string | string[]` | - | Accepted file type(s). When empty, all file types are accepted. |
| `accept` | Optional | `string | string[]` | - | Accepted file type(s). When empty, all file types are accepted. |
| `children` | Optional | `ReactNode` | - | Element used to preview file(s) |
| `minSize` | Optional | `number` | 0 | Minimum file size (in bytes), e.g. 5000 for 5KB |
| `maxSize` | Optional | `number` | `Infinity` | Maximum file size (in bytes), e.g. 5000000 for 5MB |
| `multiple` | Optional | `boolean` | `false` | Whether the inputs can accept multiple files. |
| `options` | Optional | `Object` | `{}` | Additional options passed to react-dropzone's `useDropzone()` hook. |
| `placeholder` | Optional | `ReactNode` | - | Invite displayed in the drop zone |
| `removeIcon` | Optional | `ReactNode` | [MUI's RemoveCircle icon](https://mui.com/material-ui/material-icons/?query=removeCir&selected=RemoveCircle) | The clickable icon for removing images |
| `validateFile Removal` | Optional | `function` | - | Allows to cancel the removal of files |

`<ImageInput>` also accepts the [common input props](./Inputs.md#common-input-props).
@@ -149,6 +150,16 @@ If that's not enough, you can pass a `placeholder` prop to overwrite it. The val
</ImageInput>
```

## `removeIcon`

Use the `removeIcon` prop to change the icon displayed as the remove button:

```jsx
<ImageInput source="pictures" removeIcon={CustomSvgIcon}>
<ImageField source="src" title="title" />
</ImageInput>
```

## `sx`: CSS API

The `<ImageInput>` component accepts the usual `className` prop. You can also override many styles of the inner components thanks to the `sx` property (as most MUI components, see their [documentation about it](https://mui.com/customization/how-to-customize/#overriding-nested-component-styles)). This property accepts the following subclasses:
10 changes: 10 additions & 0 deletions packages/ra-ui-materialui/src/input/FileInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import { FileInput } from './FileInput';
import { FileField } from '../field';
import { required } from 'ra-core';
import { FormInspector } from './common.stories';
import DeleteIcon from '@mui/icons-material/DeleteOutline';

export default { title: 'ra-ui-materialui/input/FileInput' };

@@ -104,6 +105,15 @@ export const Disabled = () => (
</Wrapper>
);

export const CustomRemoveIcon = () => (
<Wrapper>
<FileInput source="attachments" removeIcon={DeleteIcon}>
<FileField source="src" title="title" />
</FileInput>
<FormInspector name="attachments" />
</Wrapper>
);

const i18nProvider = polyglotI18nProvider(() => englishMessages);

const Wrapper = ({ children }) => (
6 changes: 6 additions & 0 deletions packages/ra-ui-materialui/src/input/FileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, {
Children,
FC,
isValidElement,
ReactElement,
ReactNode,
@@ -22,6 +23,7 @@ import { FileInputPreview } from './FileInputPreview';
import { sanitizeInputRestProps } from './sanitizeInputRestProps';
import { InputHelperText } from './InputHelperText';
import { SxProps } from '@mui/system';
import { SvgIconProps } from '@mui/material';

export const FileInput = (props: FileInputProps) => {
const {
@@ -41,6 +43,7 @@ export const FileInput = (props: FileInputProps) => {
onRemove: onRemoveProp,
parse,
placeholder,
removeIcon,
resource,
source,
validate,
@@ -192,6 +195,7 @@ export const FileInput = (props: FileInputProps) => {
file={file}
onRemove={onRemove(file)}
className={FileInputClasses.removeButton}
removeIcon={removeIcon}
>
<RecordContextProvider value={file}>
{childrenElement}
@@ -223,6 +227,7 @@ FileInput.propTypes = {
multiple: PropTypes.bool,
validateFileRemoval: PropTypes.func,
options: PropTypes.object,
removeIcon: PropTypes.elementType,
resource: PropTypes.string,
source: PropTypes.string,
placeholder: PropTypes.node,
@@ -264,6 +269,7 @@ export type FileInputProps = CommonInputProps & {
options?: DropzoneOptions;
onRemove?: Function;
placeholder?: ReactNode;
removeIcon?: FC<SvgIconProps>;
inputProps?: any;
validateFileRemoval?(file): boolean | Promise<boolean>;
sx?: SxProps;
16 changes: 13 additions & 3 deletions packages/ra-ui-materialui/src/input/FileInputPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import * as React from 'react';
import { FC, ReactNode, useEffect } from 'react';
import { styled } from '@mui/material/styles';
import { useEffect, ReactNode } from 'react';
import PropTypes from 'prop-types';
import RemoveCircle from '@mui/icons-material/RemoveCircle';
import IconButton from '@mui/material/IconButton';
import { useTranslate } from 'ra-core';
import { SvgIconProps } from '@mui/material';

export const FileInputPreview = (props: FileInputPreviewProps) => {
const { children, className, onRemove, file, ...rest } = props;
const {
children,
className,
onRemove,
file,
removeIcon: RemoveIcon = RemoveCircle,
...rest
} = props;

const translate = useTranslate();

@@ -30,7 +38,7 @@ export const FileInputPreview = (props: FileInputPreviewProps) => {
title={translate('ra.action.delete')}
size="small"
>
<RemoveCircle className={FileInputPreviewClasses.removeIcon} />
<RemoveIcon className={FileInputPreviewClasses.removeIcon} />
</IconButton>
{children}
</Root>
@@ -42,6 +50,7 @@ FileInputPreview.propTypes = {
className: PropTypes.string,
file: PropTypes.object,
onRemove: PropTypes.func.isRequired,
removeIcon: PropTypes.element,
};

FileInputPreview.defaultProps = {
@@ -71,4 +80,5 @@ export interface FileInputPreviewProps {
className?: string;
onRemove: () => void;
file: any;
removeIcon?: FC<SvgIconProps>;
}
10 changes: 10 additions & 0 deletions packages/ra-ui-materialui/src/input/ImageInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import { ImageInput } from './ImageInput';
import { ImageField } from '../field';
import { required } from 'ra-core';
import { FormInspector } from './common.stories';
import DeleteIcon from '@mui/icons-material/DeleteOutline';

export default { title: 'ra-ui-materialui/input/ImageInput' };

@@ -83,6 +84,15 @@ export const Required = () => (
</Wrapper>
);

export const CustomRemoveIcon = () => (
<Wrapper>
<ImageInput source="image" removeIcon={DeleteIcon}>
<ImageField source="src" title="title" />
</ImageInput>
<FormInspector name="attachments" />
</Wrapper>
);

const i18nProvider = polyglotI18nProvider(() => englishMessages);

const Wrapper = ({ children }) => (