Jaaneek / useFilePicker

Simple react hook to open browser file selector.

Home Page:https://use-file-picker.vercel.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

File types empty for kml, kmz, and geojson

elmasrya opened this issue · comments

The file type is an empty string for picking a kmz, kml, or geojson.


Screenshot 2023-08-30 025700


Also there is also no rejection validation for those extensions. Implementing ````accept: ['.kml', '.kmz', '.geojson']```` does not reject files that dont match these extensions.

We are not validating at all when using "accept" we are just passing it to the file picker, we might do it in version 2.0 which will be released soon. If you want this behavior right now just write validator yourself, there are examples in readme, let me know if you have any problems

We will take a look into the empty type

@elmasrya We've investigated the issue of missing type property.
This property represents the MIME type of file. It turns out that the package that we rely on for transforming a file input event to actual file object is only supporting a common set of MIME types, which is described here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
As you can see, geojson, kml and kmz extensions are not present on this list, that's why our package just fallbacks to an empty string.

If you need to get the MIME type of file, just get the name property of a file, and then split it by the last dot, so you'll get the file extension. Then you can use a separate package like mime-types, which was specifically built for inferring the MIME type given the file extension.

When it comes to validation, @Jaaneek has already explained that you need to create a custom validator for that. There's no file type validator built into use file picker, so I wrote the one that you need:

import { Validator } from "use-file-picker/validators";

class FileTypeValidator extends Validator {
  constructor(private readonly acceptedFileExtensions: string[]) {
    super();
  }

  validateBeforeParsing(
    _config: UseFilePickerConfig<any>,
    plainFiles: File[]
  ): Promise<void> {
    const fileExtensionErrors = plainFiles.reduce<
      { name: string; reason: string; causedByFile: File }[]
    >((errors, currentFile) => {
        const fileExtension = currentFile.name.split(".").pop();
        if (!fileExtension) {
          return [
            ...errors,
            {
              name: "FileTypeError",
              reason: "FILE_EXTENSION_NOT_FOUND",
              causedByFile: currentFile,
            },
          ];
        }
        if (!this.acceptedFileExtensions.includes(fileExtension)) {
          return [
            ...errors,
            {
              name: "FileTypeError",
              reason: "FILE_TYPE_NOT_ACCEPTED",
              causedByFile: currentFile,
            },
          ];
        }

        return errors;
      },
      []
    );

    return fileExtensionErrors.length > 0
      ? Promise.reject(fileExtensionErrors)
      : Promise.resolve();
  }

  validateAfterParsing(
    _config: UseFilePickerConfig<any>,
    _file: FileWithPath,
    _reader: FileReader
  ): Promise<void> {
    return Promise.resolve();
  }
}

You can later pass it as an argument to the hook:

const { openFilePicker, errors, plainFiles, filesContent } = useFilePicker({
    validators: [
      new FileTypeValidator(["geojson", "kml", "kmz"]),
    ],
    accept: ["*.geojson","*.kml", "*.kmz"],
    readAs: "Text",
  });

I hope it helps! Your use case is quite common, so I'll make sure that this FileTypeValidator is included in the next release of use file picker.

File type validator was natively shipped with v2.1.1. If you want to use it, just import it from:

import { FileTypeValidator } from 'use-file-picker/validators';

Its API hasn't changed, you can still use it the same way I've already described in this thread above.