Skip to content

Commit ac98ee8

Browse files
authored
Merge branch 'master' into feature/emulator-tests
2 parents 4ccc814 + 648c0f9 commit ac98ee8

34 files changed

+396
-118
lines changed

.github/workflows/run-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
with:
1717
node-version: 18
1818
- run: npm ci
19-
- run: npx playwright install --with-deps
19+
- run: npx playwright install --with-deps chromium
2020
- run: npx playwright test
2121
- uses: actions/upload-artifact@v3
2222
if: always()

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,47 @@ Collections can also take a Firestore Query instead of a path:
279279
</Collection>
280280
```
281281

282+
### DownloadLink
283+
284+
DownloadLink provides a `link` to download a file from Firebase Storage and its `reference`.
285+
286+
```svelte
287+
<DownloadLink ref={item} let:link let:ref>
288+
<a href="{link}" download>Download {ref?.name}</a>
289+
</DownloadLink>
290+
```
291+
292+
### StorageList
293+
294+
StorageList provides a list of `items` and `prefixes` corresponding to the list of objects and sub-folders at a given Firebase Storage path.
295+
296+
```svelte
297+
<StorageList ref="/" let:list>
298+
<ul>
299+
{#if list === null}
300+
<li>Loading...</li>
301+
{:else if list.prefixes.length === 0 && list.items.length === 0}
302+
<li>Empty</li>
303+
{:else}
304+
<!-- Listing the prefixes -->
305+
{#each list.prefixes as prefix}
306+
<li>
307+
{prefix.name}
308+
</li>
309+
{/each}
310+
<!-- Listing the objects in the given folder -->
311+
{#each list.items as item}
312+
<li>
313+
{item.name}
314+
</li>
315+
{/each}
316+
{/if}
317+
</ul>
318+
</StorageList>
319+
```
320+
321+
You can combine
322+
282323
### Using Components Together
283324

284325
These components can be combined to build complex realtime apps. It's especially powerful when fetching data that requires the current user's UID or a related document's path.

dist/components/Collection.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script>import { collectionStore } from "../stores/firestore.js";
1+
<script generics="Data extends DocumentData">import { collectionStore } from "../stores/firestore.js";
22
import { getFirebaseContext } from "../stores/sdk.js";
33
export let ref;
44
export let startWith = void 0;
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
import { SvelteComponent } from "svelte";
2-
import type { CollectionReference, Firestore, Query } from 'firebase/firestore';
3-
declare const __propDef: {
4-
props: {
5-
ref: string | CollectionReference | Query;
6-
startWith?: any;
2+
import type { CollectionReference, DocumentData, Firestore, Query } from "firebase/firestore";
3+
declare class __sveltets_Render<Data extends DocumentData> {
4+
props(): {
5+
ref: string | CollectionReference<Data> | Query<Data>;
6+
startWith?: Data[] | undefined;
77
};
8-
events: {
8+
events(): {} & {
99
[evt: string]: CustomEvent<any>;
1010
};
11-
slots: {
11+
slots(): {
1212
default: {
13-
data: any[];
14-
ref: CollectionReference | Query | null;
13+
data: Data[];
14+
ref: CollectionReference<Data[]> | Query<Data[]> | null;
1515
count: number;
1616
firestore?: Firestore | undefined;
1717
};
1818
loading: {};
1919
};
20-
};
21-
export type CollectionProps = typeof __propDef.props;
22-
export type CollectionEvents = typeof __propDef.events;
23-
export type CollectionSlots = typeof __propDef.slots;
24-
export default class Collection extends SvelteComponent<CollectionProps, CollectionEvents, CollectionSlots> {
20+
}
21+
export type CollectionProps<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['props']>;
22+
export type CollectionEvents<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['events']>;
23+
export type CollectionSlots<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['slots']>;
24+
export default class Collection<Data extends DocumentData> extends SvelteComponent<CollectionProps<Data>, CollectionEvents<Data>, CollectionSlots<Data>> {
2525
}
2626
export {};

dist/components/Doc.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
<script>import { docStore } from "../stores/firestore.js";
1+
<script generics="Data extends DocumentData">import { docStore } from "../stores/firestore.js";
22
import { getFirebaseContext } from "../stores/sdk.js";
33
export let ref;
44
export let startWith = void 0;
55
const { firestore } = getFirebaseContext();
66
let store = docStore(firestore, ref, startWith);
77
</script>
88

9-
{#if $store !== undefined}
9+
{#if $store !== undefined && $store !== null}
1010
<slot data={$store} ref={store.ref} {firestore} />
1111
{:else}
1212
<slot name="loading" />

dist/components/Doc.svelte.d.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
import { SvelteComponent } from "svelte";
2-
import type { DocumentReference, Firestore } from 'firebase/firestore';
3-
declare const __propDef: {
4-
props: {
5-
ref: string | DocumentReference;
6-
startWith?: any;
2+
import type { DocumentData, DocumentReference, Firestore } from "firebase/firestore";
3+
declare class __sveltets_Render<Data extends DocumentData> {
4+
props(): {
5+
ref: string | DocumentReference<Data>;
6+
startWith?: Data | undefined;
77
};
8-
events: {
8+
events(): {} & {
99
[evt: string]: CustomEvent<any>;
1010
};
11-
slots: {
11+
slots(): {
1212
default: {
13-
data: any;
14-
ref: DocumentReference | null;
13+
data: Data;
14+
ref: DocumentReference<Data> | null;
1515
firestore?: Firestore | undefined;
1616
};
1717
loading: {};
1818
};
19-
};
20-
export type DocProps = typeof __propDef.props;
21-
export type DocEvents = typeof __propDef.events;
22-
export type DocSlots = typeof __propDef.slots;
23-
export default class Doc extends SvelteComponent<DocProps, DocEvents, DocSlots> {
19+
}
20+
export type DocProps<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['props']>;
21+
export type DocEvents<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['events']>;
22+
export type DocSlots<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['slots']>;
23+
export default class Doc<Data extends DocumentData> extends SvelteComponent<DocProps<Data>, DocEvents<Data>, DocSlots<Data>> {
2424
}
2525
export {};

dist/components/FirebaseApp.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<script>import { setFirebaseContext } from "../stores/sdk.js";
22
export let firestore;
33
export let auth;
4-
setFirebaseContext({ firestore, auth });
4+
export let storage;
5+
setFirebaseContext({ firestore, auth, storage });
56
</script>
67

78
<slot />

dist/components/FirebaseApp.svelte.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { SvelteComponent } from "svelte";
22
import type { Auth } from "firebase/auth";
33
import type { Firestore } from "firebase/firestore";
4+
import type { FirebaseStorage } from "firebase/storage";
45
declare const __propDef: {
56
props: {
67
firestore: Firestore;
78
auth: Auth;
9+
storage: FirebaseStorage;
810
};
911
events: {
1012
[evt: string]: CustomEvent<any>;

dist/stores/firestore.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ interface DocStore<T> {
1313
export declare function docStore<T = any>(firestore: Firestore, ref: string | DocumentReference<T>, startWith?: T): DocStore<T>;
1414
interface CollectionStore<T> {
1515
subscribe: (cb: (value: T | []) => void) => void | (() => void);
16-
ref: CollectionReference | Query | null;
16+
ref: CollectionReference<T> | Query<T> | null;
1717
}
1818
/**
1919
* @param {Firestore} firestore firebase firestore instance
2020
* @param {string|Query|CollectionReference} ref collection path, reference, or query
2121
* @param {[]} startWith optional default data
2222
* @returns a store with realtime updates on collection data
2323
*/
24-
export declare function collectionStore<T>(firestore: Firestore, ref: string | Query | CollectionReference, startWith?: T[]): CollectionStore<T[]>;
24+
export declare function collectionStore<T>(firestore: Firestore, ref: string | Query<T> | CollectionReference<T>, startWith?: T[]): CollectionStore<T[]>;
2525
export {};

dist/stores/firestore.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ export function docStore(firestore, ref, startWith) {
2727
id: "",
2828
};
2929
}
30-
const docRef = typeof ref === 'string' ? doc(firestore, ref) : ref;
30+
const docRef = typeof ref === "string"
31+
? doc(firestore, ref)
32+
: ref;
3133
const { subscribe } = writable(startWith, (set) => {
3234
unsubscribe = onSnapshot(docRef, (snapshot) => {
3335
set(snapshot.data() ?? null);

dist/stores/sdk.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import type { Firestore } from "firebase/firestore";
22
import type { Auth } from "firebase/auth";
3+
import type { FirebaseStorage } from "firebase/storage";
34
export interface FirebaseSDKContext {
45
auth?: Auth;
56
firestore?: Firestore;
7+
storage?: FirebaseStorage;
68
}
79
export declare const contextKey = "firebase";
810
export declare function setFirebaseContext(sdks: FirebaseSDKContext): void;

docs/src/pages/firestore/collection-store.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ layout: ../../layouts/MainLayout.astro
77

88
# collectionStore
99

10-
Subscribes to Firestore collection data and listens to realtime updates.
10+
Subscribes to Firestore collection data and listens to real-time updates.
1111

1212
### Parameters
1313

@@ -22,10 +22,10 @@ Subscribes to Firestore collection data and listens to realtime updates.
2222
import { collectionStore } from 'sveltefire';
2323
import { firestore } from '$lib/firebase'; // your firestore instance
2424
25-
const post = collectionStore(firestore, 'posts');
25+
const posts = collectionStore(firestore, 'posts');
2626
</script>
2727
28-
{#each $post as post}
28+
{#each $posts as post}
2929
<p>{post.title}</p>
3030
{/each}
3131
```
@@ -56,8 +56,10 @@ With TypeScript:
5656
content?: string;
5757
}
5858
59-
const post = collectionStore<Post>(firestore, 'posts');
59+
const posts = collectionStore<Post[]>(firestore, 'posts');
6060
</script>
6161
62-
{$post?.title}
63-
```
62+
{#each $posts as post}
63+
<p>{post.title}</p>
64+
{/each}
65+
```

docs/src/pages/guide/start.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ npm i sveltefire firebase
1818

1919
### 2. Initialize
2020

21-
Initialize Firebase and add the `FirebaseApp` component to the component tree. Typically, this is done in the root `+layout.svelte` file to access Firebase in all pages.
21+
Initialize Firebase and add the `FirebaseApp` component to the component tree. Typically, this is done in the root `+layout.svelte` file to access Firebase on all pages.
2222

2323
#### +layout.svelte
2424
```svelte
@@ -30,7 +30,7 @@ Initialize Firebase and add the `FirebaseApp` component to the component tree. T
3030
3131
// Initialize Firebase
3232
const app = initializeApp(/* your firebase config */);
33-
const db = getFirestore(app);
33+
const firestore = getFirestore(app);
3434
const auth = getAuth(app);
3535
</script>
3636

firebase.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"firestore": {
77
"port": 8080
88
},
9+
"storage": {
10+
"port": 9199
11+
},
912
"hosting": {
1013
"port": 5000
1114
},
@@ -14,6 +17,9 @@
1417
},
1518
"singleProjectMode": true
1619
},
20+
"storage": {
21+
"rules": "storage.rules"
22+
},
1723
"hosting": {
1824
"public": "docs/dist",
1925
"ignore": [

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

playwright.config.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import type { PlaywrightTestConfig } from '@playwright/test';
1+
import { defineConfig } from '@playwright/test';
22

3-
const config: PlaywrightTestConfig = {
3+
export default defineConfig({
44
webServer: {
55
command: 'NODE_ENV=ci npm run build && npm run preview',
66
port: 4173
77
},
88
testDir: 'tests',
99
testMatch: /(.+\.)?(test|spec)\.[jt]s/
10-
};
11-
12-
export default config;
10+
});

src/lib/components/Collection.svelte

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
1-
<script lang="ts">
1+
<script lang="ts" generics="Data extends DocumentData">
22
import type {
33
CollectionReference,
4+
DocumentData,
45
Firestore,
56
Query,
6-
} from 'firebase/firestore';
7-
import { collectionStore } from '../stores/firestore.js';
8-
import { getFirebaseContext } from '../stores/sdk.js';
7+
} from "firebase/firestore";
8+
import { collectionStore } from "../stores/firestore.js";
9+
import { getFirebaseContext } from "../stores/sdk.js";
910
10-
// TODO figure out how to make generics work
11-
// current setup will not work without mandatory startWith value
12-
// type T = $$Generic;
13-
14-
// interface $$Slots {
15-
// default: { data: T[], ref: CollectionReference | Query, count: number }
16-
// }
17-
18-
export let ref: string | CollectionReference | Query;
19-
export let startWith: any = undefined;
11+
export let ref: string | CollectionReference<Data> | Query<Data>;
12+
export let startWith: Data[] | undefined = undefined;
2013
2114
const { firestore } = getFirebaseContext();
2215
23-
let store = collectionStore(firestore!, ref, startWith);
16+
let store = collectionStore<Data>(firestore!, ref, startWith);
2417
2518
interface $$Slots {
26-
default: { data: any[]; ref: CollectionReference | Query | null; count: number; firestore?: Firestore },
27-
loading: {},
19+
default: {
20+
data: Data[];
21+
ref: CollectionReference<Data[]> | Query<Data[]> | null;
22+
count: number;
23+
firestore?: Firestore;
24+
};
25+
loading: {};
2826
}
29-
3027
</script>
3128

3229
{#if $store !== undefined}

0 commit comments

Comments
 (0)