Skip to content

Commit

Permalink
feat(FileUploader): expose ref to clear files (#18267)
Browse files Browse the repository at this point in the history
  • Loading branch information
tekno0ryder authored Jan 27, 2025
1 parent 8acd725 commit 682c6ab
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 39 deletions.
34 changes: 18 additions & 16 deletions packages/react/src/components/FileUploader/FileUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { useState, ForwardedRef, ReactElement } from 'react';
import React, { useState, ForwardedRef, useImperativeHandle } from 'react';
import Filename from './Filename';
import FileUploaderButton from './FileUploaderButton';
import { ButtonKinds } from '../../prop-types/types';
import { ButtonKinds } from '../Button/Button';
import { keys, matches } from '../../internal/keyboard';
import { usePrefix } from '../../internal/usePrefix';
import { ReactAttr } from '../../types/common';
Expand Down Expand Up @@ -107,8 +107,15 @@ export interface FileUploaderProps extends ReactAttr<HTMLSpanElement> {
size?: 'sm' | 'small' | 'md' | 'field' | 'lg';
}

export interface FileUploaderHandle {
/**
* Clear internal state
*/
clearFiles: () => void;
}

const FileUploader = React.forwardRef(
<ItemType,>(
(
{
accept,
buttonKind,
Expand All @@ -127,15 +134,14 @@ const FileUploader = React.forwardRef(
size,
...other
}: FileUploaderProps,
ref: ForwardedRef<HTMLButtonElement>
ref: ForwardedRef<FileUploaderHandle>
) => {
const fileUploaderInstanceId = useId('file-uploader');
const [state, updateState] = useState({
fileNames: [] as (string | undefined)[],
});
const nodes: HTMLElement[] = [];
const prefix = usePrefix();

const handleChange = (evt) => {
evt.stopPropagation();
const filenames = Array.prototype.map.call(
Expand Down Expand Up @@ -169,10 +175,11 @@ const FileUploader = React.forwardRef(
}
};

const clearFiles = () => {
// A clearFiles function that resets filenames and can be referenced using a ref by the parent.
updateState({ fileNames: [] });
};
useImperativeHandle(ref, () => ({
clearFiles() {
updateState({ fileNames: [] });
},
}));

const uploaderButton = React.createRef<HTMLLabelElement>();
const classes = classNames({
Expand Down Expand Up @@ -255,12 +262,7 @@ const FileUploader = React.forwardRef(
</div>
);
}
) as {
<ItemType>(props: FileUploaderProps): ReactElement;
propTypes?: any;
contextTypes?: any;
defaultProps?: any;
};
);

FileUploader.propTypes = {
/**
Expand Down Expand Up @@ -342,6 +344,6 @@ FileUploader.propTypes = {
* sizes.
*/
size: PropTypes.oneOf(['sm', 'md', 'lg']),
};
} as PropTypes.ValidationMap<FileUploaderProps>;

export default FileUploader;
Original file line number Diff line number Diff line change
Expand Up @@ -50,38 +50,22 @@ describe('FileUploader', () => {

it('should clear all uploaded files when `clearFiles` is called on a ref', () => {
const ref = React.createRef();
const onClick = jest.fn();
let requiredProps1 = {
...requiredProps,
filenameStatus: 'edit',
};
const fileUpload = render(
<FileUploader {...requiredProps1} ref={ref} onClick={onClick} />
);
const { container } = render(<FileUploader {...requiredProps} ref={ref} />);
// eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
const input = fileUpload.container.querySelector('input');
const input = container.querySelector('input');

const filename = 'test.png';
act(() => {
uploadFiles(input, [new File(['test'], filename, { type: 'image/png' })]);
});
expect(getByText(fileUpload.container, filename)).toBeInstanceOf(
HTMLElement
);

const onDelete = jest.fn();
const description = 'test-description';
// eslint-disable-next-line testing-library/render-result-naming-convention

let removeFile = getByLabel(
fileUpload.container,
'test description - test.png'
);
// eslint-disable-next-line testing-library/prefer-screen-queries
expect(getByText(container, filename)).toBeInstanceOf(HTMLElement);
act(() => {
Simulate.click(removeFile);
ref.current.clearFiles();
});

expect(onClick).toHaveBeenCalledTimes(1);
// eslint-disable-next-line testing-library/prefer-screen-queries
expect(getByText(container, filename)).not.toBeInstanceOf(HTMLElement);
});

it('should synchronize the filename status state when its prop changes', () => {
Expand Down

0 comments on commit 682c6ab

Please sign in to comment.