svelte-firekit 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/auth/sign-up.svelte +1 -1
  2. package/dist/components/auth/user-button/settings-dialog.svelte +95 -0
  3. package/dist/components/auth/user-button/settings-dialog.svelte.d.ts +2 -0
  4. package/dist/components/auth/{user-button.svelte → user-button/user-button.svelte} +12 -9
  5. package/dist/components/auth/{user-button.svelte.d.ts → user-button/user-button.svelte.d.ts} +1 -1
  6. package/dist/components/nav/nav.js +27 -27
  7. package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +2 -2
  8. package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +1 -1
  9. package/dist/components/ui/dialog/dialog-content.svelte +36 -0
  10. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +6 -0
  11. package/dist/components/ui/dialog/dialog-description.svelte +16 -0
  12. package/dist/components/ui/dialog/dialog-description.svelte.d.ts +3 -0
  13. package/dist/components/ui/dialog/dialog-footer.svelte +20 -0
  14. package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +4 -0
  15. package/dist/components/ui/dialog/dialog-header.svelte +20 -0
  16. package/dist/components/ui/dialog/dialog-header.svelte.d.ts +4 -0
  17. package/dist/components/ui/dialog/dialog-overlay.svelte +19 -0
  18. package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +3 -0
  19. package/dist/components/ui/dialog/dialog-title.svelte +16 -0
  20. package/dist/components/ui/dialog/dialog-title.svelte.d.ts +3 -0
  21. package/dist/components/ui/dialog/index.d.ts +12 -0
  22. package/dist/components/ui/dialog/index.js +14 -0
  23. package/dist/components/ui/sheet/sheet-content.svelte +2 -2
  24. package/dist/firebase/auth/auth-guard.svelte.d.ts +13 -7
  25. package/dist/firebase/auth/auth-guard.svelte.js +47 -24
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.js +1 -1
  28. package/package.json +2 -2
@@ -2,7 +2,7 @@
2
2
  import SignInWithGoogle from "../components/auth/google-sign-in.svelte";
3
3
  import SignUpForm from "../components/auth/sign-up-form.svelte";
4
4
  import Button from "../components/ui/button/button.svelte";
5
- import * as Card from "../components/ui/card";
5
+ import * as Card from "../components/ui/card/index.js";
6
6
  let { title = "Sign up" }: { title: string } = $props();
7
7
  </script>
8
8
 
@@ -0,0 +1,95 @@
1
+ <script lang="ts">
2
+ import * as Breadcrumb from "../../ui/breadcrumb/index.js";
3
+ import { Button } from "../../ui/button/index.js";
4
+ import * as Dialog from "../../ui/dialog/index.js";
5
+ import * as Sidebar from "../../ui/sidebar/index.js";
6
+
7
+ import Lock from "lucide-svelte/icons/lock";
8
+
9
+ import { firekitUser } from "../../../firebase/auth/user.svelte.js";
10
+ import { User2 } from "lucide-svelte";
11
+
12
+ const data = {
13
+ nav: [
14
+ { name: "Profile", icon: User2 },
15
+ { name: "Security", icon: Lock },
16
+ ],
17
+ };
18
+
19
+ let open = $state(false);
20
+ </script>
21
+
22
+ <Dialog.Root bind:open>
23
+ <Dialog.Trigger>
24
+ {#snippet child({ props })}
25
+ <Button size="sm" {...props}>Profile</Button>
26
+ {/snippet}
27
+ </Dialog.Trigger>
28
+ <Dialog.Content
29
+ class="overflow-hidden p-0 md:max-h-[500px] md:max-w-[700px] lg:max-w-[800px]"
30
+ >
31
+ <Dialog.Title class="sr-only">Settings</Dialog.Title>
32
+ <Dialog.Description class="sr-only"
33
+ >Customize your settings here.</Dialog.Description
34
+ >
35
+ <Sidebar.Provider class="items-start">
36
+ <Sidebar.Root collapsible="none" class="hidden md:flex">
37
+ <Sidebar.Content>
38
+ <Sidebar.Group>
39
+ <Sidebar.GroupContent>
40
+ <Sidebar.Menu>
41
+ {#each data.nav as item (item.name)}
42
+ <Sidebar.MenuItem>
43
+ <Sidebar.MenuButton
44
+ isActive={item.name ===
45
+ "Messages & media"}
46
+ >
47
+ {#snippet child({ props })}
48
+ <a href="##" {...props}>
49
+ <item.icon />
50
+ <span>{item.name}</span>
51
+ </a>
52
+ {/snippet}
53
+ </Sidebar.MenuButton>
54
+ </Sidebar.MenuItem>
55
+ {/each}
56
+ </Sidebar.Menu>
57
+ </Sidebar.GroupContent>
58
+ </Sidebar.Group>
59
+ </Sidebar.Content>
60
+ </Sidebar.Root>
61
+ <main class="flex h-[480px] flex-1 flex-col overflow-hidden">
62
+ <header
63
+ class="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12"
64
+ >
65
+ <div class="flex items-center gap-2 px-4">
66
+ <Breadcrumb.Root>
67
+ <Breadcrumb.List>
68
+ <Breadcrumb.Item class="hidden md:block">
69
+ <Breadcrumb.Link href="#"
70
+ >Settings</Breadcrumb.Link
71
+ >
72
+ </Breadcrumb.Item>
73
+ <Breadcrumb.Separator class="hidden md:block" />
74
+ <Breadcrumb.Item>
75
+ <Breadcrumb.Page
76
+ >Messages & media</Breadcrumb.Page
77
+ >
78
+ </Breadcrumb.Item>
79
+ </Breadcrumb.List>
80
+ </Breadcrumb.Root>
81
+ </div>
82
+ </header>
83
+ <div
84
+ class="flex flex-1 flex-col gap-4 overflow-y-auto p-4 pt-0"
85
+ >
86
+ {#each Array.from({ length: 10 }) as _, i (i)}
87
+ <div
88
+ class="bg-muted/50 aspect-video max-w-3xl rounded-xl"
89
+ ></div>
90
+ {/each}
91
+ </div>
92
+ </main>
93
+ </Sidebar.Provider>
94
+ </Dialog.Content>
95
+ </Dialog.Root>
@@ -0,0 +1,2 @@
1
+ declare const SettingsDialog: import("svelte").Component<Record<string, never>, {}, "">;
2
+ export default SettingsDialog;
@@ -1,14 +1,15 @@
1
1
  <script lang="ts">
2
- import * as DropdownMenu from "../ui/dropdown-menu/index.js";
3
- import * as Avatar from "../ui/avatar/index.js";
4
- import { getInitials } from "../../utils.js";
5
- import type { NavItem } from "../../types/nav.js";
2
+ import * as DropdownMenu from "../../ui/dropdown-menu/index.js";
3
+ import * as Avatar from "../../ui/avatar/index.js";
4
+ import { getInitials } from "../../../utils.js";
5
+ import type { NavItem } from "../../../types/nav.js";
6
6
  let { nav }: { nav?: NavItem[] } = $props();
7
- import * as AlertDialog from "../ui/alert-dialog/index.js";
8
- import Button from "../ui/button/button.svelte";
9
- import { firekitUser } from "../../firebase/auth/user.svelte.js";
10
- import { firekitAuth } from "../../firebase/auth/auth.js";
7
+ import * as AlertDialog from "../../ui/alert-dialog/index.js";
8
+ import Button from "../../ui/button/button.svelte";
9
+ import { firekitUser } from "../../../firebase/auth/user.svelte.js";
10
+ import { firekitAuth } from "../../../firebase/auth/auth.js";
11
11
  import { LogOut } from "lucide-svelte";
12
+ import SettingsDialog from "./settings-dialog.svelte";
12
13
  let isOpen = $state(false);
13
14
 
14
15
  async function handleLogout() {
@@ -53,7 +54,9 @@
53
54
  </DropdownMenu.GroupHeading>
54
55
  <DropdownMenu.Separator />
55
56
  <DropdownMenu.Item onclick={() => (isOpen = true)}>
56
- Profile
57
+ {#snippet child({ props })}
58
+ <SettingsDialog child({ props }) />
59
+ {/snippet}
57
60
  </DropdownMenu.Item>
58
61
  {#if nav}
59
62
  {#each nav as { href, label }}
@@ -1,4 +1,4 @@
1
- import type { NavItem } from "../../types/nav.js";
1
+ import type { NavItem } from "../../../types/nav.js";
2
2
  declare const UserButton: import("svelte").Component<{
3
3
  nav?: NavItem[];
4
4
  }, {}, "">;
@@ -1,5 +1,5 @@
1
1
  export const nav = {
2
- versions: ["0.0.3",],
2
+ versions: ["0.0.3"],
3
3
  navMain: [
4
4
  {
5
5
  title: "Getting Started",
@@ -20,7 +20,7 @@ export const nav = {
20
20
  {
21
21
  title: "Configuration",
22
22
  url: "/docs/configuration",
23
- }
23
+ },
24
24
  ],
25
25
  },
26
26
  {
@@ -29,12 +29,12 @@ export const nav = {
29
29
  items: [
30
30
  {
31
31
  title: "Firebase Config",
32
- url: "/docs/firebase/config",
32
+ url: "/docs/config",
33
33
  },
34
34
  {
35
35
  title: "Firebase Service",
36
- url: "/docs/firebase/service",
37
- }
36
+ url: "/docs/service",
37
+ },
38
38
  ],
39
39
  },
40
40
  {
@@ -43,44 +43,44 @@ export const nav = {
43
43
  items: [
44
44
  {
45
45
  title: "FirekitUser",
46
- url: "/docs/auth/firekit-user",
46
+ url: "/docs/firekit-user",
47
47
  },
48
48
  {
49
49
  title: "FirekitAuth",
50
- url: "/docs/auth/firekit-auth",
50
+ url: "/docs/firekit-auth",
51
51
  },
52
52
  {
53
53
  title: "AuthGuard",
54
- url: "/docs/auth/auth-guard",
54
+ url: "/docs/firekit-auth-guard",
55
55
  },
56
56
  {
57
57
  title: "Sign In Page",
58
- url: "/docs/auth/sign-in-page",
58
+ url: "/docs/sign-in-page",
59
59
  },
60
60
  {
61
61
  title: "Sign Up Page",
62
- url: "/docs/auth/sign-up-page",
62
+ url: "/docs/sign-up-page",
63
63
  },
64
64
  {
65
65
  title: "Reset Password Page",
66
- url: "/docs/auth/reset-password-page",
66
+ url: "/docs/reset-password-page",
67
67
  },
68
68
  {
69
69
  title: "Sign In Form",
70
- url: "/docs/auth/sign-in-form",
70
+ url: "/docs/sign-in-form",
71
71
  },
72
72
  {
73
73
  title: "Sign Up Form",
74
- url: "/docs/auth/sign-up-form",
74
+ url: "/docs/sign-up-form",
75
75
  },
76
76
  {
77
77
  title: "Reset Password Form",
78
- url: "/docs/auth/reset-password-form",
78
+ url: "/docs/reset-password-form",
79
79
  },
80
80
  {
81
81
  title: "User Button",
82
- url: "/docs/auth/user-button",
83
- }
82
+ url: "/docs/user-button",
83
+ },
84
84
  ],
85
85
  },
86
86
  {
@@ -89,19 +89,19 @@ export const nav = {
89
89
  items: [
90
90
  {
91
91
  title: "FirekitDoc",
92
- url: "/docs/firestore/firekit-doc",
92
+ url: "/docs/firekit-doc",
93
93
  },
94
94
  {
95
95
  title: "FirekitAwaitableDoc",
96
- url: "/docs/firestore/awaitable-doc",
96
+ url: "/docs/awaitable-doc",
97
97
  },
98
98
  {
99
99
  title: "FirekitCollection",
100
- url: "/docs/firestore/firekit-collection",
100
+ url: "/docs/firekit-collection",
101
101
  },
102
102
  {
103
103
  title: "Document Mutations",
104
- url: "/docs/firestore/document-mutations",
104
+ url: "/docs/document-mutations",
105
105
  },
106
106
  {
107
107
  title: "Collection Component",
@@ -110,7 +110,7 @@ export const nav = {
110
110
  {
111
111
  title: "Doc Component",
112
112
  url: "/docs/firestore/doc-component",
113
- }
113
+ },
114
114
  ],
115
115
  },
116
116
  {
@@ -119,20 +119,20 @@ export const nav = {
119
119
  items: [
120
120
  {
121
121
  title: "Download URL",
122
- url: "/docs/storage/download-url",
122
+ url: "/docs/download-url",
123
123
  },
124
124
  {
125
125
  title: "Storage List",
126
- url: "/docs/storage/storage-list",
126
+ url: "/docs/storage-list",
127
127
  },
128
128
  {
129
129
  title: "Upload Task",
130
- url: "/docs/storage/upload-task",
130
+ url: "/docs/upload-task",
131
131
  },
132
132
  {
133
133
  title: "Upload Component",
134
- url: "/docs/storage/upload-component",
135
- }
134
+ url: "/docs/upload-component",
135
+ },
136
136
  ],
137
137
  },
138
138
  {
@@ -150,7 +150,7 @@ export const nav = {
150
150
  {
151
151
  title: "Performance Optimization",
152
152
  url: "/docs/advanced/performance-optimization",
153
- }
153
+ },
154
154
  ],
155
155
  },
156
156
  ],
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import DotsHorizontal from "svelte-radix/DotsHorizontal.svelte";
2
+ import Ellipsis from "lucide-svelte/icons/ellipsis";
3
3
  import type { WithElementRef, WithoutChildren } from "bits-ui";
4
4
  import type { HTMLAttributes } from "svelte/elements";
5
5
  import { cn } from "../../../utils.js";
@@ -18,6 +18,6 @@
18
18
  class={cn("flex size-9 items-center justify-center", className)}
19
19
  {...restProps}
20
20
  >
21
- <DotsHorizontal class="size-4 outline-none" tabindex={-1} />
21
+ <Ellipsis class="size-4" />
22
22
  <span class="sr-only">More</span>
23
23
  </span>
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import ChevronRight from "svelte-radix/ChevronRight.svelte";
2
+ import ChevronRight from "lucide-svelte/icons/chevron-right";
3
3
  import type { WithElementRef } from "bits-ui";
4
4
  import type { HTMLLiAttributes } from "svelte/elements";
5
5
  import { cn } from "../../../utils.js";
@@ -0,0 +1,36 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from "bits-ui";
3
+ import X from "lucide-svelte/icons/x";
4
+ import type { Snippet } from "svelte";
5
+ import * as Dialog from "./index.js";
6
+ import { cn } from "../../../utils.js";
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ class: className,
11
+ children,
12
+ ...restProps
13
+ }: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
14
+ children: Snippet;
15
+ } = $props();
16
+ </script>
17
+
18
+ <Dialog.Portal>
19
+ <Dialog.Overlay />
20
+ <DialogPrimitive.Content
21
+ bind:ref
22
+ class={cn(
23
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
24
+ className
25
+ )}
26
+ {...restProps}
27
+ >
28
+ {@render children?.()}
29
+ <DialogPrimitive.Close
30
+ class="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"
31
+ >
32
+ <X class="size-4" />
33
+ <span class="sr-only">Close</span>
34
+ </DialogPrimitive.Close>
35
+ </DialogPrimitive.Content>
36
+ </Dialog.Portal>
@@ -0,0 +1,6 @@
1
+ import { Dialog as DialogPrimitive } from "bits-ui";
2
+ import type { Snippet } from "svelte";
3
+ declare const DialogContent: import("svelte").Component<Omit<Omit<DialogPrimitive.ContentProps, "child">, "children"> & {
4
+ children: Snippet;
5
+ }, {}, "ref">;
6
+ export default DialogContent;
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: DialogPrimitive.DescriptionProps = $props();
10
+ </script>
11
+
12
+ <DialogPrimitive.Description
13
+ bind:ref
14
+ class={cn("text-muted-foreground text-sm", className)}
15
+ {...restProps}
16
+ />
@@ -0,0 +1,3 @@
1
+ import { Dialog as DialogPrimitive } from "bits-ui";
2
+ declare const DialogDescription: import("svelte").Component<DialogPrimitive.DescriptionProps, {}, "ref">;
3
+ export default DialogDescription;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import type { WithElementRef } from "bits-ui";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+ import { cn } from "../../../utils.js";
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ class: className,
9
+ children,
10
+ ...restProps
11
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
12
+ </script>
13
+
14
+ <div
15
+ bind:this={ref}
16
+ class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { WithElementRef } from "bits-ui";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ declare const DialogFooter: import("svelte").Component<WithElementRef<HTMLAttributes<HTMLDivElement>>, {}, "ref">;
4
+ export default DialogFooter;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import type { WithElementRef } from "bits-ui";
4
+ import { cn } from "../../../utils.js";
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ class: className,
9
+ children,
10
+ ...restProps
11
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
12
+ </script>
13
+
14
+ <div
15
+ bind:this={ref}
16
+ class={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { HTMLAttributes } from "svelte/elements";
2
+ import type { WithElementRef } from "bits-ui";
3
+ declare const DialogHeader: import("svelte").Component<WithElementRef<HTMLAttributes<HTMLDivElement>>, {}, "ref">;
4
+ export default DialogHeader;
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: DialogPrimitive.OverlayProps = $props();
10
+ </script>
11
+
12
+ <DialogPrimitive.Overlay
13
+ bind:ref
14
+ class={cn(
15
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
16
+ className
17
+ )}
18
+ {...restProps}
19
+ />
@@ -0,0 +1,3 @@
1
+ import { Dialog as DialogPrimitive } from "bits-ui";
2
+ declare const DialogOverlay: import("svelte").Component<DialogPrimitive.OverlayProps, {}, "ref">;
3
+ export default DialogOverlay;
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: DialogPrimitive.TitleProps = $props();
10
+ </script>
11
+
12
+ <DialogPrimitive.Title
13
+ bind:ref
14
+ class={cn("text-lg font-semibold leading-none tracking-tight", className)}
15
+ {...restProps}
16
+ />
@@ -0,0 +1,3 @@
1
+ import { Dialog as DialogPrimitive } from "bits-ui";
2
+ declare const DialogTitle: import("svelte").Component<DialogPrimitive.TitleProps, {}, "ref">;
3
+ export default DialogTitle;
@@ -0,0 +1,12 @@
1
+ import { Dialog as DialogPrimitive } from "bits-ui";
2
+ import Title from "./dialog-title.svelte";
3
+ import Footer from "./dialog-footer.svelte";
4
+ import Header from "./dialog-header.svelte";
5
+ import Overlay from "./dialog-overlay.svelte";
6
+ import Content from "./dialog-content.svelte";
7
+ import Description from "./dialog-description.svelte";
8
+ declare const Root: typeof DialogPrimitive.Root;
9
+ declare const Trigger: typeof DialogPrimitive.Trigger;
10
+ declare const Close: typeof DialogPrimitive.Close;
11
+ declare const Portal: typeof DialogPrimitive.Portal;
12
+ export { Root, Title, Portal, Footer, Header, Trigger, Overlay, Content, Description, Close, Root as Dialog, Title as DialogTitle, Portal as DialogPortal, Footer as DialogFooter, Header as DialogHeader, Trigger as DialogTrigger, Overlay as DialogOverlay, Content as DialogContent, Description as DialogDescription, Close as DialogClose, };
@@ -0,0 +1,14 @@
1
+ import { Dialog as DialogPrimitive } from "bits-ui";
2
+ import Title from "./dialog-title.svelte";
3
+ import Footer from "./dialog-footer.svelte";
4
+ import Header from "./dialog-header.svelte";
5
+ import Overlay from "./dialog-overlay.svelte";
6
+ import Content from "./dialog-content.svelte";
7
+ import Description from "./dialog-description.svelte";
8
+ const Root = DialogPrimitive.Root;
9
+ const Trigger = DialogPrimitive.Trigger;
10
+ const Close = DialogPrimitive.Close;
11
+ const Portal = DialogPrimitive.Portal;
12
+ export { Root, Title, Portal, Footer, Header, Trigger, Overlay, Content, Description, Close,
13
+ //
14
+ Root as Dialog, Title as DialogTitle, Portal as DialogPortal, Footer as DialogFooter, Header as DialogHeader, Trigger as DialogTrigger, Overlay as DialogOverlay, Content as DialogContent, Description as DialogDescription, Close as DialogClose, };
@@ -21,7 +21,7 @@
21
21
 
22
22
  <script lang="ts">
23
23
  import { Dialog as SheetPrimitive, type WithoutChildrenOrChild } from "bits-ui";
24
- import Cross2 from "svelte-radix/Cross2.svelte";
24
+ import X from "lucide-svelte/icons/x";
25
25
  import type { Snippet } from "svelte";
26
26
  import SheetOverlay from "./sheet-overlay.svelte";
27
27
  import { cn } from "../../../utils.js";
@@ -45,7 +45,7 @@
45
45
  <SheetPrimitive.Close
46
46
  class="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"
47
47
  >
48
- <Cross2 class="size-4" />
48
+ <X class="size-4" />
49
49
  <span class="sr-only">Close</span>
50
50
  </SheetPrimitive.Close>
51
51
  </SheetPrimitive.Content>
@@ -1,23 +1,29 @@
1
1
  import type { DocumentData } from "firebase/firestore";
2
2
  import { firekitUser } from "./user.svelte.js";
3
- type GuardConfig = {
3
+ interface GuardConfig {
4
4
  authRequired?: boolean;
5
5
  redirectTo?: string;
6
6
  requiredClaims?: string[];
7
7
  requiredData?: (data: DocumentData | null) => boolean;
8
8
  allowIf?: (user: typeof firekitUser) => boolean;
9
- };
9
+ redirectParams?: Record<string, string>;
10
+ }
10
11
  export declare class FirekitAuthGuard {
11
12
  private static instance;
12
13
  private _loading;
13
14
  private _error;
15
+ private _lastValidationTime;
16
+ private readonly VALIDATION_THROTTLE;
14
17
  private constructor();
15
18
  static getInstance(): FirekitAuthGuard;
16
- validateAuth({ authRequired, redirectTo, requiredClaims, requiredData, allowIf }?: GuardConfig): Promise<boolean | undefined>;
17
- requireAuth(redirectTo?: string): Promise<boolean | undefined>;
18
- requireNoAuth(redirectTo?: string): Promise<boolean | undefined>;
19
- requireClaims(claims: string[], redirectTo?: string): Promise<boolean | undefined>;
20
- requireData(validator: (data: DocumentData | null) => boolean, redirectTo?: string): Promise<boolean | undefined>;
19
+ private shouldThrottleValidation;
20
+ private handleRedirect;
21
+ private validateClaims;
22
+ validateAuth({ authRequired, redirectTo, requiredClaims, requiredData, allowIf, redirectParams }?: GuardConfig): Promise<boolean>;
23
+ requireAuth(redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
24
+ requireNoAuth(redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
25
+ requireClaims(claims: string[], redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
26
+ requireData(validator: (data: DocumentData | null) => boolean, redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
21
27
  get loading(): boolean;
22
28
  get error(): Error | null;
23
29
  }
@@ -5,6 +5,8 @@ export class FirekitAuthGuard {
5
5
  static instance;
6
6
  _loading = $state(true);
7
7
  _error = $state(null);
8
+ _lastValidationTime = 0;
9
+ VALIDATION_THROTTLE = 1000; // 1 second
8
10
  constructor() { }
9
11
  static getInstance() {
10
12
  if (!FirekitAuthGuard.instance) {
@@ -12,62 +14,83 @@ export class FirekitAuthGuard {
12
14
  }
13
15
  return FirekitAuthGuard.instance;
14
16
  }
15
- async validateAuth({ authRequired = true, redirectTo = '/login', requiredClaims = [], requiredData, allowIf } = {}) {
17
+ shouldThrottleValidation() {
18
+ const now = Date.now();
19
+ if (now - this._lastValidationTime < this.VALIDATION_THROTTLE) {
20
+ return true;
21
+ }
22
+ this._lastValidationTime = now;
23
+ return false;
24
+ }
25
+ async handleRedirect(redirectTo, params) {
26
+ const url = new URL(redirectTo, window.location.origin);
27
+ if (params) {
28
+ Object.entries(params).forEach(([key, value]) => {
29
+ url.searchParams.append(key, value);
30
+ });
31
+ }
32
+ await goto(url.toString());
33
+ }
34
+ async validateClaims(requiredClaims, userClaims) {
35
+ if (!requiredClaims.length)
36
+ return true;
37
+ if (!userClaims)
38
+ return false;
39
+ return requiredClaims.every(claim => userClaims[claim]);
40
+ }
41
+ async validateAuth({ authRequired = true, redirectTo = '/login', requiredClaims = [], requiredData, allowIf, redirectParams } = {}) {
16
42
  if (!browser)
17
- return;
43
+ return true;
44
+ if (this.shouldThrottleValidation())
45
+ return true;
18
46
  try {
19
47
  this._loading = true;
20
48
  this._error = null;
21
- // Wait for auth state to be determined
22
- // if (firekitUser.loading) {
23
- // await new Promise((resolve) => setTimeout(resolve, 100));
24
- // }
25
49
  const isAuthenticated = firekitUser.isLoggedIn;
26
- // Handle authentication requirement
27
50
  if (authRequired && !isAuthenticated) {
28
- await goto(redirectTo);
51
+ await this.handleRedirect(redirectTo, {
52
+ ...redirectParams,
53
+ returnTo: window.location.pathname
54
+ });
29
55
  return false;
30
56
  }
31
- // Handle custom conditions if provided
32
57
  if (allowIf && !allowIf(firekitUser)) {
33
- await goto(redirectTo);
58
+ await this.handleRedirect(redirectTo, redirectParams);
34
59
  return false;
35
60
  }
36
- // Handle required claims if any
37
61
  if (requiredClaims.length > 0) {
38
62
  const userClaims = await firekitUser.user?.getIdTokenResult();
39
- const hasClaims = requiredClaims.every((claim) => userClaims?.claims[claim]);
63
+ const hasClaims = await this.validateClaims(requiredClaims, userClaims?.claims);
40
64
  if (!hasClaims) {
41
- await goto(redirectTo);
65
+ await this.handleRedirect(redirectTo, redirectParams);
42
66
  return false;
43
67
  }
44
68
  }
45
- // Handle required data validation if provided
46
69
  if (requiredData && !requiredData(firekitUser.data)) {
47
- await goto(redirectTo);
70
+ await this.handleRedirect(redirectTo, redirectParams);
48
71
  return false;
49
72
  }
50
73
  return true;
51
74
  }
52
75
  catch (error) {
53
- this._error = error;
76
+ this._error = error instanceof Error ? error : new Error(String(error));
54
77
  return false;
55
78
  }
56
79
  finally {
57
80
  this._loading = false;
58
81
  }
59
82
  }
60
- async requireAuth(redirectTo = '/login') {
61
- return this.validateAuth({ authRequired: true, redirectTo });
83
+ async requireAuth(redirectTo = '/login', redirectParams) {
84
+ return this.validateAuth({ authRequired: true, redirectTo, redirectParams });
62
85
  }
63
- async requireNoAuth(redirectTo = '/dashboard') {
64
- return this.validateAuth({ authRequired: false, redirectTo });
86
+ async requireNoAuth(redirectTo = '/dashboard', redirectParams) {
87
+ return this.validateAuth({ authRequired: false, redirectTo, redirectParams });
65
88
  }
66
- async requireClaims(claims, redirectTo = '/login') {
67
- return this.validateAuth({ requiredClaims: claims, redirectTo });
89
+ async requireClaims(claims, redirectTo = '/login', redirectParams) {
90
+ return this.validateAuth({ requiredClaims: claims, redirectTo, redirectParams });
68
91
  }
69
- async requireData(validator, redirectTo = '/login') {
70
- return this.validateAuth({ requiredData: validator, redirectTo });
92
+ async requireData(validator, redirectTo = '/login', redirectParams) {
93
+ return this.validateAuth({ requiredData: validator, redirectTo, redirectParams });
71
94
  }
72
95
  get loading() {
73
96
  return this._loading;
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ export { default as ResetPassWordPage } from './auth/reset-password.svelte';
16
16
  export { default as ResetPassWordForm } from './components/auth/reset-password-form.svelte';
17
17
  export { default as SignInForm } from './components/auth/sign-in-form.svelte';
18
18
  export { default as SignUpForm } from './components/auth/sign-up-form.svelte';
19
- export { default as UserButton } from './components/auth/user-button.svelte';
19
+ export { default as UserButton } from './components/auth/user-button/user-button.svelte';
20
20
  export { default as Collection } from './components/firestore/collection.svelte';
21
21
  export { default as Doc } from './components/firestore/doc.svelte';
22
22
  export { default as Upload } from './components/storage/upload.svelte';
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ export { default as ResetPassWordPage } from './auth/reset-password.svelte';
21
21
  export { default as ResetPassWordForm } from './components/auth/reset-password-form.svelte';
22
22
  export { default as SignInForm } from './components/auth/sign-in-form.svelte';
23
23
  export { default as SignUpForm } from './components/auth/sign-up-form.svelte';
24
- export { default as UserButton } from './components/auth/user-button.svelte';
24
+ export { default as UserButton } from './components/auth/user-button/user-button.svelte';
25
25
  // firestore components
26
26
  export { default as Collection } from './components/firestore/collection.svelte';
27
27
  export { default as Doc } from './components/firestore/doc.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-firekit",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -53,7 +53,7 @@
53
53
  "@sveltejs/vite-plugin-svelte": "^4.0.0",
54
54
  "@tailwindcss/typography": "^0.5.15",
55
55
  "autoprefixer": "^10.4.20",
56
- "bits-ui": "^1.0.0-next.52",
56
+ "bits-ui": "^1.0.0-next.60",
57
57
  "clsx": "^2.1.1",
58
58
  "formsnap": "^2.0.0-next.1",
59
59
  "lucide-svelte": "^0.456.0",