Skip to content
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

Issue #347 : Add remove button to default file input previews #526

Merged
merged 7 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,9 @@ A component passed using `previewComponent` will receive the following props:
- `multiple` **[Boolean][151]** A flag indicating whether or not to accept multiple files (optional, default `false`)
- `accept` **[String][149]?** Value that defines the file types the file input should accept (e.g., ".doc,.docx"). More info: [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept][166]
- `capture` **(`"user"` \| `"environment"`)?** Value that specifies which camera to use, if the accept attribute indicates the input type of image or video. This is not available for all devices (e.g., desktops). More info: [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#capture][167]
- `onRemove` **[Function][150]** A callback fired when the file is removed (only available when `multiple` is set to `true`) (optional, default `noop`)
- `onRemove` **[Function][150]** A callback fired when a file is removed (optional, default `noop`)
- `previewComponent` **[Function][150]** A custom component that is used to display a preview of each attached file (optional, default `RenderPreview`)
- `removeComponent` **[Function][150]** A custom component that receives `value` and `onRemove` props (only available when `multiple` is set to `true`) (optional, default `RemoveButton`)
- `removeComponent` **[Function][150]** A custom component that receives `value` and `onRemove` props (optional, default `RemoveButton`)
- `thumbnail` **[String][149]?** A placeholder image to display before the file is loaded
- `hidePreview` **[Boolean][151]** A flag indicating whether or not to hide the file preview (optional, default `false`)
- `selectText` **[String][149]?** An override for customizing the text that is displayed on the input's label. Defaults to 'Select File' or 'Select File(s)' depending on the `multiple` prop value
Expand Down
35 changes: 29 additions & 6 deletions migration-guides/v6.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ This version contains the following breaking changes:
5. The `hideLabel` prop on `<RangeInput />` has been renamed to `hideRangeValue`
6. `<CloudinaryFileInput />` and `<FileInput />` components now store an array of objects representing the file data as opposed to a string
7. `<CloudinaryFileInput />` and `<FileInput />` components no longer accept an `onLoad` prop
8. The `previewComponent` for a file input no longer receives a `value` prop and `file` is a file object (with the url)
9. The tag on `<Spinner />` now uses the class `spinner` in place of an id and supports additional classes
10. `<TabBar />` now expects both `options` and `value` as required props.
8. `<CloudinaryFileInput />` and `<FileInput />` components now default to allowing the user to remove a selected file
9. The `previewComponent` for a file input no longer receives a `value` prop and `file` is a file object (with the url)
10. The tag on `<Spinner />` now uses the class `spinner` in place of an id and supports additional classes
11. `<TabBar />` now expects both `options` and `value` as required props.

The required changes for each item are detailed below.

Expand Down Expand Up @@ -167,8 +168,30 @@ import { Field } from 'redux-form'
}}
/>
```
## 8. `<CloudinaryFileInput />` and `<FileInput />` components now default to allowing the user to remove a selected file

## 8. The `previewComponent` for a file input no longer receives a `value` prop and `file` is a file object (with the url)
You may need to add styling to account for the new button that is available next to file previews. If you want to keep your application as-is (i.e., not showing a remove button), then you can specify a custom `removeComponent` that returns `null`.

```jsx
// Before
<Field
name="profilePhoto"
component={FileInput}
/>

// After
function EmptyRemoveComponent() {
return null
}

<Field
name="profilePhoto"
component={FileInput}
removeComponent={EmptyRemoveComponent}
/>
```

## 9. The `previewComponent` for a file input no longer receives a `value` prop and `file` is a file object (with the url)

If you're passing in a custom `previewComponent`, you must modify your logic to only access the `value` object.

Expand Down Expand Up @@ -196,7 +219,7 @@ const PreviewComponent = ({ file }) => {
<FileInput previewComponent={PreviewComponent} />
```

#### 9. The tag on `<Spinner />` now uses the `spinner` class in place of an id
## 10. The tag on `<Spinner />` now uses the `spinner` class in place of an id

Replace any styling rules that target `#spinner` with `.spinner`.

Expand All @@ -215,7 +238,7 @@ Replace any styling rules that target `#spinner` with `.spinner`.
}
}
```
#### 10. `<TabBar />` now expects both `options` and `value` as required props.
## 11. `<TabBar />` now expects both `options` and `value` as required props.

Make sure that any instances of `<TabBar />` in your application are already sending these two props.

Expand Down
6 changes: 3 additions & 3 deletions src/forms/inputs/file-input/file-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ import classnames from 'classnames'
* @param {Boolean} [multiple=false] - A flag indicating whether or not to accept multiple files
* @param {String} [accept] - Value that defines the file types the file input should accept (e.g., ".doc,.docx"). More info: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept
* @param {("user"|"environment")} [capture] - Value that specifies which camera to use, if the accept attribute indicates the input type of image or video. This is not available for all devices (e.g., desktops). More info: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#capture
* @param {Function} [onRemove=noop] - A callback fired when the file is removed (only available when `multiple` is set to `true`)
* @param {Function} [onRemove=noop] - A callback fired when a file is removed
* @param {Function} [previewComponent=RenderPreview] - A custom component that is used to display a preview of each attached file
* @param {Function} [removeComponent=RemoveButton] - A custom component that receives `value` and `onRemove` props (only available when `multiple` is set to `true`)
* @param {Function} [removeComponent=RemoveButton] - A custom component that receives `value` and `onRemove` props
* @param {String} [thumbnail] - A placeholder image to display before the file is loaded
* @param {Boolean} [hidePreview=false] - A flag indicating whether or not to hide the file preview
* @param {String} [selectText] - An override for customizing the text that is displayed on the input's label. Defaults to 'Select File' or 'Select File(s)' depending on the `multiple` prop value
Expand Down Expand Up @@ -160,7 +160,7 @@ function FileInput(props) {
{files.map((file, idx) => (
<div key={file?.name || idx} className="fileupload-preview-container">
<RenderPreview file={file} thumbnail={thumbnail} {...rest} />
{multiple && file && <RemoveComponent file={file} onRemove={() => removeFile(idx)} />}
{file && <RemoveComponent file={file} onRemove={() => removeFile(idx)} />}
</div>
))}
</React.Fragment>
Expand Down
12 changes: 12 additions & 0 deletions test/forms/inputs/file-input.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ describe('FileInput', () => {
expect(wrapper.find('button.remove-file').exists()).toBe(true)
})

test('shows a clear input button component when multiple prop is false and a file is selected', () => {
const props = { input: { name, value: [{ name: 'fileName', type: 'image/png' }], onChange: defaultOnChange }, meta: {}, multiple: false }
const wrapper = mount(<FileInput { ...props }/>)
expect(wrapper.find('button.remove-file').exists()).toBe(true)
})

test('does not show a clear input button component when multiple prop is false and a file is not selected', () => {
const props = { input: { name, value: [], onChange: defaultOnChange }, meta: {}, multiple: false }
const wrapper = mount(<FileInput { ...props }/>)
expect(wrapper.find('button.remove-file').exists()).toBe(false)
})

test('adds custom aria-label to default remove button', () => {
const file = { name: 'fileName.png', type: 'image/png' }
const props = { input: { name, value: [file], onChange: defaultOnChange }, meta: {}, multiple: true }
Expand Down