Skip to content

Commit 0df1871

Browse files
Merge pull request #8337 from primefaces/v11-fileupload
Add New FileUpload
2 parents e0e1a56 + b100284 commit 0df1871

33 files changed

Lines changed: 1951 additions & 0 deletions
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export async function POST() {
2+
return new Response(JSON.stringify({ success: true }), {
3+
status: 200,
4+
headers: { 'Content-Type': 'application/json' }
5+
});
6+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { FileUploadInstance } from '@primereact/types/shared/fileupload';
2+
import { ToastRegionInstance, ToastType } from '@primereact/types/shared/toast';
3+
import { Button } from 'primereact/button';
4+
import { FileUpload } from 'primereact/fileupload';
5+
import { Message } from 'primereact/message';
6+
import { ProgressBar } from 'primereact/progressbar';
7+
import { Toast, toast } from 'primereact/toast';
8+
9+
export default function AdvancedDemo() {
10+
const onUpload = () => {
11+
toast({
12+
title: 'Success',
13+
description: 'File Uploaded',
14+
group: 'advanced-demo'
15+
});
16+
};
17+
18+
return (
19+
<div className="card">
20+
<FileUpload name="demo[]" url="/api/upload" multiple accept="image/*" maxFileSize={1000000} className="border border-surface-200 dark:border-surface-700 rounded-md" onUpload={onUpload}>
21+
{(instance: FileUploadInstance) => {
22+
return (
23+
<>
24+
<div className="flex items-center p-5 gap-2">
25+
<Button onClick={instance.choose}>
26+
<i className="pi pi-plus" />
27+
Choose
28+
</Button>
29+
<Button severity="secondary" disabled={!instance.hasFiles} onClick={instance.upload}>
30+
<i className="pi pi-upload" />
31+
Upload
32+
</Button>
33+
<Button severity="secondary" disabled={!instance.hasFiles} onClick={instance.clear}>
34+
<i className="pi pi-times" />
35+
Cancel
36+
</Button>
37+
</div>
38+
39+
<FileUpload.Content>
40+
{((instance.state.messages && instance.state.messages.length > 0) || instance.hasFiles) && (
41+
<div className="flex flex-col gap-4">
42+
{instance.state.messages &&
43+
instance.state.messages.length > 0 &&
44+
instance.state.messages.map((msg, i) => (
45+
<Message key={i} severity="error" className="mb-2">
46+
<Message.Content>
47+
<Message.Text>{msg}</Message.Text>
48+
</Message.Content>
49+
</Message>
50+
))}
51+
52+
{instance.hasFiles && (
53+
<ProgressBar value={instance.state.progress}>
54+
<ProgressBar.Track style={{ height: '0.25rem' }}>
55+
<ProgressBar.Indicator>
56+
<ProgressBar.Label />
57+
</ProgressBar.Indicator>
58+
</ProgressBar.Track>
59+
</ProgressBar>
60+
)}
61+
</div>
62+
)}
63+
64+
<FileUpload.List />
65+
66+
{!instance.hasFiles && !instance.hasUploadedFiles && <div>Drag and drop files to here to upload.</div>}
67+
</FileUpload.Content>
68+
</>
69+
);
70+
}}
71+
</FileUpload>
72+
73+
<Toast position="top-right" group="advanced-demo">
74+
<Toast.Portal>
75+
<Toast.Region>
76+
{({ toast }: ToastRegionInstance) =>
77+
toast?.toasts.map((toast: ToastType) => (
78+
<Toast.Item key={toast.id} data={toast}>
79+
<div className="flex items-start gap-2">
80+
<div className="flex-1">
81+
<Toast.Title className="mb-1 -mt-0.5" />
82+
<Toast.Description />
83+
</div>
84+
</div>
85+
<Toast.Close as={Button} iconOnly severity={'secondary'} variant="text" size="small" className={'absolute top-2 right-2'}>
86+
<i className="pi pi-times"></i>
87+
</Toast.Close>
88+
</Toast.Item>
89+
))
90+
}
91+
</Toast.Region>
92+
</Toast.Portal>
93+
</Toast>
94+
</div>
95+
);
96+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { FileUploadInstance } from '@primereact/types/shared/fileupload';
2+
import { ToastRegionInstance, ToastType } from '@primereact/types/shared/toast';
3+
import { Button } from 'primereact/button';
4+
import { FileUpload } from 'primereact/fileupload';
5+
import { Message } from 'primereact/message';
6+
import { Toast, toast } from 'primereact/toast';
7+
8+
export default function AutoDemo() {
9+
const onUpload = () => {
10+
toast({
11+
title: 'Success',
12+
description: 'File Uploaded',
13+
group: 'auto-demo'
14+
});
15+
};
16+
17+
return (
18+
<div className="card flex justify-center">
19+
<FileUpload name="demo[]" url="/api/upload" auto accept="image/*" maxFileSize={1000000} onUpload={onUpload}>
20+
{(instance: FileUploadInstance) => {
21+
return (
22+
<>
23+
{instance.state.messages &&
24+
instance.state.messages.length > 0 &&
25+
instance.state.messages.map((msg, i) => (
26+
<Message key={i} severity="error" className="mb-2">
27+
<Message.Content>
28+
<Message.Text>{msg}</Message.Text>
29+
</Message.Content>
30+
</Message>
31+
))}
32+
33+
<div className="flex flex-wrap items-center gap-3">
34+
<Button onClick={instance.choose}>
35+
<i className="pi pi-plus" />
36+
Browse
37+
</Button>
38+
</div>
39+
</>
40+
);
41+
}}
42+
</FileUpload>
43+
44+
<Toast position="top-right" group="auto-demo">
45+
<Toast.Portal>
46+
<Toast.Region>
47+
{({ toast }: ToastRegionInstance) =>
48+
toast?.toasts.map((toast: ToastType) => (
49+
<Toast.Item key={toast.id} data={toast}>
50+
<div className="flex items-start gap-2">
51+
<div className="flex-1">
52+
<Toast.Title className="mb-1 -mt-0.5" />
53+
<Toast.Description />
54+
</div>
55+
</div>
56+
<Toast.Close as={Button} iconOnly severity={'secondary'} variant="text" size="small" className={'absolute top-2 right-2'}>
57+
<i className="pi pi-times"></i>
58+
</Toast.Close>
59+
</Toast.Item>
60+
))
61+
}
62+
</Toast.Region>
63+
</Toast.Portal>
64+
</Toast>
65+
</div>
66+
);
67+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { FileUploadInstance } from '@primereact/types/shared/fileupload';
2+
import { ToastRegionInstance, ToastType } from '@primereact/types/shared/toast';
3+
import { Button } from 'primereact/button';
4+
import { FileUpload } from 'primereact/fileupload';
5+
import { Message } from 'primereact/message';
6+
import { Toast, toast } from 'primereact/toast';
7+
8+
const onUpload = () => {
9+
toast({
10+
title: 'Success',
11+
description: 'File Uploaded',
12+
group: 'basic-demo'
13+
});
14+
};
15+
16+
export default function BasicDemo() {
17+
return (
18+
<div className="card">
19+
<FileUpload name="demo[]" url="/api/upload" accept="image/*" multiple maxFileSize={1000000} onUpload={onUpload}>
20+
{(instance: FileUploadInstance) => {
21+
return (
22+
<>
23+
{instance.state.messages &&
24+
instance.state.messages.length > 0 &&
25+
instance.state.messages.map((msg, i) => (
26+
<Message key={i} severity="error" className="mb-2">
27+
<Message.Content>
28+
<Message.Text>{msg}</Message.Text>
29+
</Message.Content>
30+
</Message>
31+
))}
32+
33+
<div className="flex justify-between">
34+
<div className="flex flex-wrap items-center gap-3">
35+
<Button onClick={instance.choose}>
36+
<i className="pi pi-plus" />
37+
Choose
38+
</Button>
39+
<span>{instance.hasFiles ? instance.state.files.map((file) => file.name).join(', ') : 'No file chosen'}</span>
40+
</div>
41+
<Button severity="secondary" onClick={instance.upload}>
42+
Upload
43+
</Button>
44+
</div>
45+
</>
46+
);
47+
}}
48+
</FileUpload>
49+
50+
<Toast position="top-right" group="basic-demo">
51+
<Toast.Portal>
52+
<Toast.Region>
53+
{({ toast }: ToastRegionInstance) =>
54+
toast?.toasts.map((toast: ToastType) => (
55+
<Toast.Item key={toast.id} data={toast}>
56+
<div className="flex items-start gap-2">
57+
<div className="flex-1">
58+
<Toast.Title className="mb-1 -mt-0.5" />
59+
<Toast.Description />
60+
</div>
61+
</div>
62+
<Toast.Close as={Button} iconOnly severity={'secondary'} variant="text" size="small" className={'absolute top-2 right-2'}>
63+
<i className="pi pi-times"></i>
64+
</Toast.Close>
65+
</Toast.Item>
66+
))
67+
}
68+
</Toast.Region>
69+
</Toast.Portal>
70+
</Toast>
71+
</div>
72+
);
73+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { FileUploadHandlerEvent, FileUploadInstance } from '@primereact/types/shared/fileupload';
2+
import { Button } from 'primereact/button';
3+
import { FileUpload } from 'primereact/fileupload';
4+
import * as React from 'react';
5+
6+
export default function CustomUploadDemo() {
7+
const [src, setSrc] = React.useState<string | null>(null);
8+
9+
const onFileSelect = (event: FileUploadHandlerEvent) => {
10+
const file = event.files[0];
11+
const reader = new FileReader();
12+
13+
reader.onload = async (e) => {
14+
if (e.target?.result && typeof e.target.result === 'string') {
15+
setSrc(e.target.result);
16+
}
17+
};
18+
19+
reader.readAsDataURL(file);
20+
};
21+
22+
return (
23+
<div className="card flex flex-col items-center gap-6">
24+
<FileUpload url="/api/upload" auto customUpload uploadHandler={onFileSelect}>
25+
{(instance: FileUploadInstance) => {
26+
return (
27+
<div className="flex flex-wrap items-center gap-3">
28+
<Button onClick={instance.choose} severity="secondary" variant="outlined">
29+
<i className="pi pi-plus" />
30+
Browse
31+
</Button>
32+
</div>
33+
);
34+
}}
35+
</FileUpload>
36+
{src && <img src={src} alt="Image" className="shadow-md rounded-xl w-full sm:w-64" style={{ filter: 'grayscale(100%)' }} />}
37+
</div>
38+
);
39+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { FileUploadInstance } from '@primereact/types/shared/fileupload';
2+
import { Button } from 'primereact/button';
3+
import { FileUpload } from 'primereact/fileupload';
4+
import { Message } from 'primereact/message';
5+
6+
export default function FileUploadPTDemo() {
7+
return (
8+
<FileUpload name="demo[]" url="/api/upload" multiple accept="image/*" maxFileSize={1000000} className="border border-surface-200 dark:border-surface-700 rounded-md">
9+
{(instance: FileUploadInstance) => {
10+
return (
11+
<>
12+
<div className="flex items-center p-5 gap-2">
13+
<Button onClick={instance.choose}>
14+
<i className="pi pi-plus" />
15+
Choose
16+
</Button>
17+
<Button severity="secondary" disabled={!instance.hasFiles} onClick={instance.upload}>
18+
<i className="pi pi-upload" />
19+
Upload
20+
</Button>
21+
<Button severity="secondary" disabled={!instance.hasFiles} onClick={instance.clear}>
22+
<i className="pi pi-times" />
23+
Cancel
24+
</Button>
25+
</div>
26+
27+
<FileUpload.Content>
28+
{((instance.state.messages && instance.state.messages.length > 0) || instance.hasFiles) && (
29+
<div className="flex flex-col gap-4">
30+
{instance.state.messages &&
31+
instance.state.messages.length > 0 &&
32+
instance.state.messages.map((msg, i) => (
33+
<Message key={i} severity="error" className="mb-2">
34+
<Message.Content>
35+
<Message.Text>{msg}</Message.Text>
36+
</Message.Content>
37+
</Message>
38+
))}
39+
</div>
40+
)}
41+
42+
<FileUpload.List />
43+
44+
{!instance.hasFiles && !instance.hasUploadedFiles && <div>Drag and drop files to here to upload.</div>}
45+
</FileUpload.Content>
46+
</>
47+
);
48+
}}
49+
</FileUpload>
50+
);
51+
}

0 commit comments

Comments
 (0)