Skip to content

Commit 04a646c

Browse files
authored
Merge pull request #263 from MetroStar/file-input-clearing
Add Custom File Input Hook
2 parents f9ebb40 + 6370a4e commit 04a646c

File tree

6 files changed

+120
-6
lines changed

6 files changed

+120
-6
lines changed

package-lock.json

+1-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/comet-uswds/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@metrostar/comet-uswds",
3-
"version": "3.2.0",
3+
"version": "3.3.0",
44
"description": "React with TypeScript Component Library based on USWDS 3.0.",
55
"license": "Apache-2.0",
66
"main": "./dist/cjs/index.js",

packages/comet-uswds/src/components/file-input/file-input.stories.tsx

+58-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import React from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import { Meta, StoryFn } from '@storybook/react';
33
import { FileInput, FileInputProps } from './file-input';
4+
import { useFileInput } from '../../hooks';
5+
import Button from '../button';
46

57
const meta: Meta<typeof FileInput> = {
68
title: 'USWDS/Forms/File Input',
@@ -38,3 +40,58 @@ Multiple.args = {
3840
helperText: 'Input accepts multiple files',
3941
disabled: false,
4042
};
43+
44+
const CustomTemplate: StoryFn<typeof FileInput> = (args: FileInputProps) => {
45+
const { clear } = useFileInput();
46+
const [file, setFile] = useState<File | null>(null);
47+
48+
useEffect(() => {
49+
// eslint-disable-next-line no-console
50+
console.log(file);
51+
}, [file]);
52+
return (
53+
<>
54+
<div className="padding-bottom-1">
55+
<FileInput
56+
onChange={(event) => {
57+
const target = event.target as HTMLInputElement;
58+
const files = target?.files;
59+
if (files) {
60+
setFile(files[0]);
61+
}
62+
}}
63+
{...args}
64+
/>
65+
</div>
66+
<div>
67+
<Button
68+
id="clear-btn"
69+
onClick={() => {
70+
clear(args.id);
71+
setFile(null);
72+
}}
73+
>
74+
Clear
75+
</Button>
76+
</div>
77+
</>
78+
);
79+
};
80+
81+
export const CustomClear = CustomTemplate.bind({});
82+
CustomClear.args = {
83+
id: 'file-input-1',
84+
name: 'file-input-1',
85+
multiple: false,
86+
required: false,
87+
label: 'Select a file',
88+
helperText: 'Input accepts a single file',
89+
disabled: false,
90+
};
91+
CustomClear.parameters = {
92+
docs: {
93+
source: {
94+
type: 'code',
95+
},
96+
},
97+
};
+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
export { default as useFileInput } from './use-file-input';
12
export { default as useHeader } from './use-header';
23
export { default as useModal } from './use-modal';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { act, renderHook } from '@testing-library/react';
2+
import useFileInput from './use-file-input';
3+
4+
describe('useFileInput', () => {
5+
test('should call clear successfully', async () => {
6+
const { result } = renderHook(() => useFileInput());
7+
8+
await act(async () => {
9+
result.current.clear('file-input');
10+
});
11+
expect(result.current.clear).toBeTruthy();
12+
});
13+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const useFileInput = () => {
2+
const clear = (elemId: string): void => {
3+
const elem = document.getElementById(elemId) as HTMLInputElement;
4+
if (elem === null) {
5+
return;
6+
}
7+
8+
// Get the Parent element based on USWDS file input HTML structure
9+
const parent = elem.parentElement as HTMLFormElement;
10+
if (parent === null) {
11+
return;
12+
}
13+
14+
// Get Preview Elements and remove them
15+
const previewElement = parent.querySelectorAll(
16+
'.usa-file-input__preview',
17+
) as NodeListOf<HTMLElement>;
18+
previewElement.forEach((element) => element.remove());
19+
20+
// Get Preview Heading Elements and remove them
21+
const previewHeadingElement = parent.querySelectorAll(
22+
'.usa-file-input__preview-heading',
23+
) as NodeListOf<HTMLElement>;
24+
previewHeadingElement.forEach((element) => element.remove());
25+
26+
// Get the sr-only Element and reset
27+
const srOnlyElement = parent.querySelector('.usa-sr-only') as HTMLElement;
28+
if (srOnlyElement) {
29+
srOnlyElement.innerHTML = 'No file selected.';
30+
}
31+
32+
// Get the instructions and reset
33+
const instructions = parent.querySelector('.usa-file-input__instructions') as HTMLElement;
34+
if (instructions) {
35+
instructions.removeAttribute('hidden');
36+
}
37+
38+
// Reset input element values
39+
elem.setAttribute('aria-label', '');
40+
elem.value = '';
41+
};
42+
43+
return { clear };
44+
};
45+
46+
export default useFileInput;

0 commit comments

Comments
 (0)