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

feat(conform-dom,conform-react): multiple file support #72

Merged
merged 1 commit into from
Jan 4, 2023

Conversation

edmundhung
Copy link
Owner

@edmundhung edmundhung commented Jan 3, 2023

My original idea was to use [] to denote the type of the data and hopefully enable a better type hint on the parsed value, but then comes to realize the current types for submission.value is very much a lie as there is no way to guess its structure, best as Record<string, unknown>.

  • The final solution simply removes the error thrown when there are more than one entry with the same name and convert the value to an array instead. This means the result data type will be an array ONLY when there are 2+ entries. It is the duty of the user to coerce the value to an array if appropriate.
  • The FormData API will generate an entry with empty file (name = '', size = 0, type = 'application/octet-stream') even no file is selected. However, there is currently a bug on @remix-run/web-fetch which parses the body incorrectly and returns an empty string instead on the server. Since this is a polyfill, only remix app running on node is affected and some extra logic to preprocess it is needed.
  • When validating a list of files, only validation messages on the array level are accepted. Error on the item will not be captured and reported. e.g. files instead of files[0],

Zod example:

function isEmptyFile(file: unknown): boolean {
    return (
        // FIXME: The empty file is presented as empty string on server side
        // This is caused by @remix-run/web-fetch considered empty filename as non-file entry
        file === '' ||
        (file instanceof File &&
            file.name === '' &&
            file.size === 0 &&
            file.type === 'application/octet-stream')
    );
}

const schema = z.object({
    file: z.preprocess(
        (file) => (isEmptyFile(file) ? undefined : file),
        z.instanceof(File, { message: 'File is required' }),
    ),
    files: z
        .preprocess(
            (files) =>
                isEmptyFile(files) ? [] : Array.isArray(files) ? files : [files],
            z.instanceof(File).array().min(1, 'At least 1 file is required'),
        )
        .refine(
            (files) => files.reduce((size, file) => size + file.size, 0) < 5 * 1024,
            'Total file size must be less than 5kb',
        ),
});

@codesandbox
Copy link

codesandbox bot commented Jan 3, 2023

CodeSandbox logoCodeSandbox logo  Open in CodeSandbox Web Editor | VS Code | VS Code Insiders

@edmundhung
Copy link
Owner Author

cc: @brandonpittman

@brandonpittman
Copy link
Contributor

This seems good to me. I think you have to put it on the user to validate repeated names.

@edmundhung edmundhung mentioned this pull request Jan 4, 2023
17 tasks
@edmundhung edmundhung merged commit 9b37fe9 into dev Jan 4, 2023
@edmundhung edmundhung deleted the file-upload branch January 4, 2023 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants