Skip to content

Commit 1fcb080

Browse files
committed
fix export conflict in index.js
2 parents b6ade27 + cff7a90 commit 1fcb080

File tree

5 files changed

+343
-0
lines changed

5 files changed

+343
-0
lines changed

README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,3 +436,76 @@ Slot Props & Events:
436436
```
437437

438438
Note: Each data item in the collection contains the document data AND fields for the `id` and `ref` (DocumentReference).
439+
440+
### `<File>`
441+
442+
Retrives a file from Firebase storage.
443+
444+
Props:
445+
446+
- *path (required)* to file in storage i.e `images/mountain.jpg`
447+
448+
Slots:
449+
450+
- *default slot* shown when file is available.
451+
- *loading* shown when waiting for response.
452+
- *fallback* shown when error occurs.
453+
454+
455+
Slot Props & Events:
456+
457+
- *url* url to resource
458+
- *ref* File Reference for direct acess
459+
460+
```html
461+
<File {path} let:url let:ref>
462+
463+
<img src={url} />
464+
465+
<div slot="loading">
466+
Loading...
467+
</div>
468+
469+
<div slot="fallback">
470+
Error
471+
</div>
472+
473+
</File>
474+
```
475+
476+
### `<Upload>`
477+
478+
Props:
479+
480+
- *path (required)* to upload to i.e "images/mountain.jpg"
481+
- *file* file to upload as a file object `Blob` or `Unit8Array`
482+
483+
Slots:
484+
485+
- *default slot* shown before upload is complete.
486+
- *complete* shown when upload is complete.
487+
- *fallback* shown when error occurs or upload is cancelled.
488+
489+
490+
Slot Props & Events:
491+
492+
- *url* url to uploaded file.
493+
- *task* Firebase upload task.
494+
- *snapshot* snapshot of upload, useful for monitoring progress.
495+
496+
497+
```html
498+
<Upload {file} {path} let:task let:snapshot let:url>
499+
500+
Uploading your file... {snaphot.bytesTransferred}
501+
502+
<div slot="complete">
503+
Download here {url}
504+
</div>
505+
506+
<div slot="fallback">
507+
Error or canceled
508+
</div>
509+
510+
</Upload>
511+
```

src/File.svelte

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<script>
2+
export let path;
3+
export let log = false;
4+
export let traceId = "";
5+
export let startWith = undefined; // Why? Firestore returns null for docs that don't exist, predictible loading state.
6+
export let maxWait = 10000;
7+
export let once = false;
8+
9+
import { onDestroy, onMount, createEventDispatcher } from "svelte";
10+
import { uploadFileStore } from "./storage";
11+
12+
const opts = {
13+
startWith,
14+
traceId,
15+
log,
16+
maxWait,
17+
once
18+
}
19+
20+
let store = uploadFileStore(path, opts);
21+
22+
const dispatch = createEventDispatcher();
23+
24+
let unsub;
25+
26+
// Props changed
27+
$: {
28+
if (unsub) {
29+
// Unsub and create new store
30+
unsub();
31+
store = uploadFileStore(path, opts);
32+
dispatch("ref", { ref: store.ref });
33+
}
34+
35+
unsub = store.subscribe(url => {
36+
dispatch("url", {
37+
url
38+
});
39+
});
40+
}
41+
42+
onMount(() => dispatch("ref", { ref: store.ref }))
43+
onDestroy(() => unsub());
44+
</script>
45+
46+
<slot name="before" />
47+
48+
{#if $store}
49+
<slot url={$store} ref={store.ref} error={store.error} />
50+
{:else if store.loading}
51+
<slot name="loading" />
52+
{:else}
53+
<slot name="fallback" />
54+
{/if}
55+
56+
<slot name="after" />

src/Upload.svelte

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<script>
2+
export let path;
3+
export let log = false;
4+
export let traceId = "";
5+
export let startWith = undefined; // Why? Firestore returns null for docs that don't exist, predictible loading state.
6+
export let maxWait = 10000;
7+
export let once = false;
8+
9+
import { onDestroy, onMount, createEventDispatcher } from "svelte";
10+
import { fileStore } from "./storage";
11+
12+
const opts = {
13+
startWith,
14+
traceId,
15+
log,
16+
maxWait,
17+
once
18+
}
19+
20+
let store = fileStore(path, opts);
21+
22+
const dispatch = createEventDispatcher();
23+
24+
let unsub;
25+
26+
// Props changed
27+
$: {
28+
if (unsub) {
29+
// Unsub and create new store
30+
unsub();
31+
store = fileStore(path, opts);
32+
dispatch("ref", { ref: store.ref });
33+
}
34+
35+
unsub = store.subscribe(url => {
36+
dispatch("url", {
37+
url
38+
});
39+
});
40+
}
41+
42+
onMount(() => dispatch("ref", { ref: store.ref }))
43+
onDestroy(() => unsub());
44+
</script>
45+
46+
<slot name="before" />
47+
48+
{#if $store}
49+
<slot url={$store} ref={store.ref} error={store.error} />
50+
{:else if store.complete}
51+
<slot name="complete" />
52+
{:else}
53+
<slot name="fallback" />
54+
{/if}
55+
56+
<slot name="after" />

src/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import Doc from './Doc.svelte';
44
import Collection from './Collection.svelte';
55
import { userStore } from './auth';
66
import { docStore, collectionStore } from './firestore';
7+
<<<<<<< HEAD
8+
=======
9+
import { fileStore, uploadFileStore } from './storage';
10+
import File from './File.svelte';
11+
import Upload from './Upload.svelte';
12+
>>>>>>> cff7a90ef6de662946e8fe2d34d89991af243890
713

814

915
export {
@@ -14,4 +20,11 @@ export {
1420
userStore,
1521
docStore,
1622
collectionStore,
23+
<<<<<<< HEAD
24+
=======
25+
fileStore,
26+
uploadFileStore,
27+
File,
28+
Upload,
29+
>>>>>>> cff7a90ef6de662946e8fe2d34d89991af243890
1730
}

src/storage.js

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { writable } from 'svelte/store';
2+
import { assertApp } from './helpers';
3+
import { startTrace, stopTrace } from './perf';
4+
5+
// Svelte Store for Storage file
6+
export function fileStore(path, opts) {
7+
const storage = assertApp('storage');
8+
9+
const { startWith, log, traceId, maxWait, once } = { maxWait: 10000, ...opts };
10+
11+
const storageRef = storage.ref();
12+
const ref = typeof path === 'string' ? storageRef.child(path) : path;
13+
14+
// Performance trace
15+
const trace = traceId && startTrace(traceId);
16+
17+
// Internal state
18+
let _loading = typeof startWith !== undefined;
19+
let _error = null;
20+
let _teardown;
21+
let _waitForIt;
22+
23+
// State should never change without emitting a new value
24+
// Clears loading state on first call
25+
const next = (val, err) => {
26+
_loading = false;
27+
_waitForIt && clearTimeout(_waitForIt);
28+
_error = err || null;
29+
set(val);
30+
trace && stopTrace(trace);
31+
};
32+
33+
// Timout
34+
// Runs of first subscription
35+
const start = () => {
36+
37+
// Timout for fallback slot
38+
_waitForIt = maxWait && setTimeout(() => _loading && next(null, new Error(`Timeout at ${maxWait}. Using fallback slot.`) ), maxWait)
39+
40+
// Realtime firebase subscription
41+
_teardown = ref.on("value",
42+
snapshot => {
43+
// Emit next value
44+
snapshot.getDownloadURL().then((url) => {
45+
next(url);
46+
if (log) console.log(`URl: ${url}`);
47+
});
48+
49+
50+
if (log) console.log('Snapshot:', snapshot);
51+
52+
// Teardown after first emitted value if once
53+
once && _teardown();
54+
},
55+
56+
// Handle firebase thrown errors
57+
error => {
58+
console.error(error);
59+
next(null, error);
60+
}
61+
);
62+
63+
// Removes firebase listener when store completes
64+
return () => _teardown();
65+
};
66+
67+
// Svelte store
68+
const store = writable(startWith, start);
69+
const { subscribe, set } = store;
70+
71+
return {
72+
subscribe,
73+
firestore,
74+
ref,
75+
get loading() {
76+
return _loading;
77+
},
78+
get error() {
79+
return _error;
80+
}
81+
};
82+
}
83+
84+
export function uploadFileStore(path, opts) {
85+
const storage = assertApp('storage');
86+
87+
const { startWith, log, traceId } = { maxWait: 10000, ...opts };
88+
89+
const storageRef = storage.ref();
90+
const ref = typeof path === 'string' ? storageRef.child(path) : path;
91+
let snapshot;
92+
let task;
93+
94+
// Performance trace
95+
const trace = traceId && startTrace(traceId);
96+
97+
// Internal state
98+
let _loading = typeof startWith !== undefined;
99+
let _error = null;
100+
let _waitForIt;
101+
102+
// State should never change without emitting a new value
103+
// Clears loading state on first call
104+
const next = (val, err) => {
105+
_loading = false;
106+
_waitForIt && clearTimeout(_waitForIt);
107+
_error = err || null;
108+
set(val);
109+
trace && stopTrace(trace);
110+
};
111+
112+
// Timout
113+
// Runs of first subscription
114+
const start = () => {};
115+
116+
// Svelte store
117+
const store = writable(startWith, start);
118+
let { subscribe, set } = store;
119+
120+
const _set = set;
121+
set = (val) => {
122+
task = ref.put(val).then(snap => {
123+
snapshot = snap;
124+
ref.getDownloadURL().then((url) => {
125+
next(url);
126+
if (log) console.log(`URl: ${url}`);
127+
});
128+
});
129+
task.on('state_changed', snap => {
130+
snapshot = snap;
131+
});
132+
}
133+
134+
return {
135+
subscribe,
136+
firestore,
137+
ref,
138+
get loading() {
139+
return _loading;
140+
},
141+
get error() {
142+
return _error;
143+
}
144+
};
145+
}

0 commit comments

Comments
 (0)