Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,8 @@
"vite": "5.4.2",
"vite-plugin-dts": "^4.0.3",
"vitest": "^2.0.5"
},
"dependencies": {
"react-hook-form": "7.53.0"
}
}
}
86 changes: 86 additions & 0 deletions packages/mui/src/SimpleFileUpload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';
import {
useController,
FieldValues,
UseControllerProps,
FieldPath,
} from 'react-hook-form';
import FormControl, { FormControlProps } from '@mui/material/FormControl';
import InputLabel, { InputLabelProps } from '@mui/material/InputLabel';
import Input, { InputProps } from '@mui/material/Input';
import FormHelperText from '@mui/material/FormHelperText';

export type SimpleFileUploadProps<
TName extends FieldPath<TFieldValues>,
TFieldValues extends FieldValues = FieldValues,
> = UseControllerProps<TFieldValues, TName> &
Omit<InputProps, 'name' | 'type' | 'label' | 'inputProps'> & {
label: string;
accept: string;
disabled?: boolean;
InputLabelProps?: InputLabelProps;
FormControlProps?: FormControlProps;
};

export function SimpleFileUpload<
TName extends FieldPath<TFieldValues>,
TFieldValues extends FieldValues,
>({
control,
name,
rules,
label,
accept,
disabled = false,
InputLabelProps: inputLabelProps,
FormControlProps: formControlProps,
...props
}: SimpleFileUploadProps<TName, TFieldValues>) {
const {
field: { onChange, ref },
fieldState: { error },
} = useController({
name,
control,
rules,
});

const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0] || null;

if (file) {
const fileData = {
size: file.size,
name: file.name,
type: file.type,
};
onChange(fileData);
} else {
onChange(null);
}
};

return (
<FormControl {...formControlProps}>
{label && (
<InputLabel shrink error={!!error} {...inputLabelProps}>
{label}
</InputLabel>
)}
<Input
{...props}
inputRef={ref}
inputProps={{
type: 'file',
accept,
disabled,
onChange: handleFileChange,
}}
error={!!error}
/>
{error && <FormHelperText error>{error.message}</FormHelperText>}
</FormControl>
);
}

SimpleFileUpload.displayName = 'MuiReactHookFormSimpleFileUpload';
75 changes: 75 additions & 0 deletions src/stories/SimpleFileUpload.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Stack from '@mui/material/Stack';
import { StoryFn, Meta } from '@storybook/react';
import { useForm } from 'react-hook-form';

import { SimpleFileUpload } from '../../packages/mui/src/SimpleFileUpload';
import { Form } from './Form';

export default {
title: 'Core/SimpleFileUpload',
component: SimpleFileUpload,
parameters: {
layout: 'fullscreen',
},
argTypes: { onSubmit: { action: 'submit' } },
} as Meta<typeof SimpleFileUpload>;

const Template: StoryFn<typeof SimpleFileUpload> = (args: any) => {
const formProps = useForm<{
file: File | null;
}>({
defaultValues: {
file: null,
},
});

return (
<Form {...formProps} onSubmit={args.onSubmit}>
<Stack>
<SimpleFileUpload
name="file"
label="File Upload"
control={formProps.control}
rules={args.rules}
accept={args.accept}
disabled={args.disabled}
{...args}
/>
</Stack>
</Form>
);
};

export const Default = {
render: Template,
args: {
label: 'Default',
accept: 'image/*',
},
};

export const Required = {
render: Template,
args: {
label: 'Required',
accept: 'image/*',
rules: { required: 'File is required' },
},
};

export const Disabled = {
render: Template,
args: {
label: 'Disabled',
accept: 'image/*',
disabled: true,
},
};

export const AcceptPDF = {
render: Template,
args: {
label: 'Accept PDF',
accept: 'application/pdf',
},
};