Skip to content

Commit 475fbd9

Browse files
committed
feat(components): Add FileDropArea
1 parent 34a24df commit 475fbd9

File tree

7 files changed

+152
-2
lines changed

7 files changed

+152
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<script>
2+
import { isAboveMobile } from '../../mdc'
3+
import { createEventDispatcher } from 'svelte'
4+
5+
export let raised = false
6+
export let outlined = false
7+
export let uploading = false
8+
export let mimeType = 'application/pdf,image/*'
9+
10+
let fileInput = {}
11+
12+
let highlighted = false
13+
14+
const dispatch = createEventDispatcher()
15+
16+
function highlight() {
17+
highlighted = true
18+
}
19+
20+
function unhighlight() {
21+
highlighted = false
22+
}
23+
24+
function handleDrop(e) {
25+
unhighlight()
26+
27+
let dt = e.dataTransfer
28+
let files = dt.files
29+
30+
handleFiles(files)
31+
}
32+
33+
function handleFiles(files) {
34+
if (!uploading) {
35+
uploading = true
36+
files = [...files] //turns files into an array so forEach works
37+
files.forEach(uploadFile)
38+
}
39+
}
40+
41+
function uploadFile(file) {
42+
const formData = new FormData()
43+
44+
formData.append('file', file)
45+
46+
dispatch('upload', formData)
47+
}
48+
</script>
49+
50+
<style>
51+
form > * {
52+
margin-top: 0;
53+
}
54+
#drop-area {
55+
border: 2px dashed #ccc;
56+
}
57+
#drop-area.highlighted {
58+
border-color: var(--mdc-theme-primary);
59+
}
60+
61+
#fileElem {
62+
display: none;
63+
}
64+
.disabled {
65+
cursor: progress;
66+
}
67+
.icon {
68+
color: hsla(213, 6%, 55%, 1);
69+
}
70+
</style>
71+
72+
<div
73+
id="drop-area"
74+
class="br-8px {$$props.class}"
75+
class:highlighted
76+
on:dragenter|preventDefault|stopPropagation={highlight}
77+
on:dragleave|preventDefault|stopPropagation={unhighlight}
78+
on:dragover|preventDefault|stopPropagation={highlight}
79+
on:drop|preventDefault|stopPropagation={handleDrop}
80+
>
81+
<form class="flex justify-between align-items-center my-1 px-1" class:column={!isAboveMobile()}>
82+
{#if !uploading}
83+
<input
84+
bind:this={fileInput}
85+
type="file"
86+
id="fileElem"
87+
multiple
88+
accept={mimeType}
89+
disabled={uploading}
90+
on:change={() => handleFiles(fileInput.files)}
91+
/>
92+
{/if}
93+
<label
94+
class="mdc-button m-8px"
95+
for="fileElem"
96+
class:custom-text-button={raised}
97+
class:mdc-button--outlined={outlined}
98+
class:disabled={uploading}
99+
class:mdc-button--raised={raised}>Choose files</label
100+
>
101+
<div class="m-8px">or drop files here</div>
102+
<i class="material-icons icon m-8px" id="upload-icon">cloud_upload</i>
103+
</form>
104+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@use '@material/button/styles';
2+
@use "@material/button";
3+
4+
label.custom-text-button {
5+
--mdc-theme-primary: var(--mdc-theme-upload-button-color, hsla(214, 11%, 37%, 1));
6+
7+
@include button.ink-color(var(--mdc-theme-upload-button-ink-color, hsla(0,0%, 100%, 1)));
8+
}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import './_index.scss'
2+
import FileDropArea from './FileDropArea.svelte'
3+
4+
export default FileDropArea

components/custom/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ import Badge from './Badge'
22
import Form from './Form'
33
import StaticChip from './StaticChip'
44
import SearchableSelect from './SearchableSelect'
5+
import FileDropArea from './FileDropArea'
56

6-
export { Badge, Form, SearchableSelect, StaticChip }
7+
export { Badge, FileDropArea, Form, SearchableSelect, StaticChip }

index.mjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
setNotice,
2929
} from './components/mdc/index.js'
3030

31-
import { Badge, Form, SearchableSelect, StaticChip } from './components/custom/index.js'
31+
import { Badge, FileDropArea, Form, SearchableSelect, StaticChip } from './components/custom/index.js'
3232

3333
export {
3434
actions,
@@ -42,6 +42,7 @@ export {
4242
Dialog,
4343
Drawer,
4444
Fab,
45+
FileDropArea,
4546
IconButton,
4647
List,
4748
Menu,

stories/FileDropArea.stories.svelte

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script>
2+
import { Meta, Template, Story } from '@storybook/addon-svelte-csf'
3+
import { FileDropArea } from '../components/custom'
4+
import { copyAndModifyArgs } from './helpers.js'
5+
6+
const args = {
7+
raised: true,
8+
outlined: false,
9+
uploading: false,
10+
mimeType: 'application/pdf,image/*',
11+
class: '',
12+
'on:upload': () => alert('you uploaded'),
13+
}
14+
</script>
15+
16+
<Meta title="Atoms/FileDropArea" component={FileDropArea} />
17+
18+
<Template let:args>
19+
<FileDropArea {...args} on:upload={args['on:upload']} />
20+
</Template>
21+
22+
<Story name="Default" {args} />
23+
24+
<Story name="Raised" args={copyAndModifyArgs(args, { raised: true })} />
25+
26+
<Story name="Outlined" args={copyAndModifyArgs(args, { outlined: true })} />
27+
28+
<Story name="Uploading" args={copyAndModifyArgs(args, { uploading: true })} />
29+
30+
<Story name="MimeType" args={copyAndModifyArgs(args, { mimeType: 'image/*' })} />

stories/_theme.scss

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
--mdc-list-item__subtitle: #6d7580;
1414
--mdc-menu-icon-color: #6d7580;
1515
--mdc-theme-icon-color: #6d7580;
16+
--mdc-theme-upload-button-color: rgb(205, 171, 201);
17+
--mdc-theme-upload-button-ink-color: rgb(65, 1, 129);
1618
}
1719

1820
.mdc-theme--primary-variant {

0 commit comments

Comments
 (0)