mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
Improve FileChooser behavior with file input element (#197)
Before, the `FileChooser` could create a malformed `accept` parameter by repeating extensions if they were specified by several MIME types. This no longer happens and there is a test for it.
This commit is contained in:
parent
4490cc9bc7
commit
0047b9dbb3
|
@ -60,17 +60,24 @@ const InputFileChooser = ({
|
||||||
//
|
//
|
||||||
// which allows pretty generous interpretations.
|
// which allows pretty generous interpretations.
|
||||||
//
|
//
|
||||||
// Update(whscullin) - Adding the MIME type seems to block loading anything
|
// However, it turns out that Safari does not like MIME types when
|
||||||
// from iCloud when using Safari, so reverting to simply using extensions for
|
// reading from iCloud. It may be related to:
|
||||||
// now.
|
//
|
||||||
const newAccept = [];
|
// https://bugs.webkit.org/show_bug.cgi?id=244666
|
||||||
|
//
|
||||||
|
// or it could be related to some permissions issue with iCloud. For
|
||||||
|
// the moment, not adding the MIME type is sufficient.
|
||||||
|
const newAccept: string[] = [];
|
||||||
for (const type of accept) {
|
for (const type of accept) {
|
||||||
for (const [/* typeString */, suffixes] of Object.entries(type.accept)) {
|
for (let [/* typeString */, suffixes] of Object.entries(type.accept)) {
|
||||||
// newAccept.push(typeString);
|
// newAccept.push(typeString);
|
||||||
if (Array.isArray(suffixes)) {
|
if (!Array.isArray(suffixes)) {
|
||||||
newAccept.push(...suffixes);
|
suffixes = [suffixes];
|
||||||
} else {
|
}
|
||||||
newAccept.push(suffixes);
|
for (const suffix of suffixes) {
|
||||||
|
if (!newAccept.includes(suffix)) {
|
||||||
|
newAccept.push(suffix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,6 +164,10 @@ const FilePickerChooser = ({
|
||||||
* Using `window.showOpenFilePicker` has the advantage of allowing read/write
|
* Using `window.showOpenFilePicker` has the advantage of allowing read/write
|
||||||
* access to the file, whereas the regular input element only gives read
|
* access to the file, whereas the regular input element only gives read
|
||||||
* access.
|
* access.
|
||||||
|
*
|
||||||
|
* The FileChooser takes an optional `accept` parameter that specifies which
|
||||||
|
* types of files can be opened. The parameter is a map of MIME type to file
|
||||||
|
* extension. If the MIME type is the empty string, t
|
||||||
*/
|
*/
|
||||||
export const FileChooser = ({
|
export const FileChooser = ({
|
||||||
onChange,
|
onChange,
|
||||||
|
|
|
@ -22,6 +22,17 @@ const FAKE_FILE_HANDLE = {
|
||||||
isDirectory: false,
|
isDirectory: false,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
const TEST_FILE_TYPES = [
|
||||||
|
{
|
||||||
|
description: 'Test description 1',
|
||||||
|
accept: { 'mime1': ['.ext1', '.ext2'] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Test description 2',
|
||||||
|
accept: { 'mime2': ['.ext1', '.ext2'] }
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
const NOP = () => { /* do nothing */ };
|
const NOP = () => { /* do nothing */ };
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
|
@ -44,6 +55,13 @@ describe('FileChooser', () => {
|
||||||
expect(inputElement.type).toBe('file');
|
expect(inputElement.type).toBe('file');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should pass the correct MIME types and file extensions to the picker', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
render(<FileChooser control='input' onChange={onChange} accept={TEST_FILE_TYPES} />);
|
||||||
|
const inputElement = await screen.findByRole('button') as HTMLInputElement;
|
||||||
|
expect(inputElement.accept).toBe('.ext1,.ext2');
|
||||||
|
});
|
||||||
|
|
||||||
it('should fire a callback with empty list when no files are selected', async () => {
|
it('should fire a callback with empty list when no files are selected', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
render(<FileChooser control='input' onChange={onChange} />);
|
render(<FileChooser control='input' onChange={onChange} />);
|
||||||
|
@ -97,6 +115,23 @@ describe('FileChooser', () => {
|
||||||
expect(container).not.toBeNull();
|
expect(container).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should pass the correct MIME types and file extensions to the picker', async () => {
|
||||||
|
mockFilePicker.mockResolvedValueOnce([]);
|
||||||
|
const onChange = jest.fn();
|
||||||
|
render(<FileChooser control='picker' onChange={onChange} accept={TEST_FILE_TYPES} />);
|
||||||
|
|
||||||
|
fireEvent.click(await screen.findByText('Choose File'));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockFilePicker).toBeCalledWith<[OpenFilePickerOptions]>({
|
||||||
|
'excludeAcceptAllOption': true,
|
||||||
|
'multiple': false,
|
||||||
|
'types': TEST_FILE_TYPES
|
||||||
|
});
|
||||||
|
expect(onChange).toBeCalledWith([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should fire a callback with empty list when no files are selected', async () => {
|
it('should fire a callback with empty list when no files are selected', async () => {
|
||||||
mockFilePicker.mockResolvedValueOnce([]);
|
mockFilePicker.mockResolvedValueOnce([]);
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user