@svadmin/ui 0.3.0 → 0.4.1

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 (108) hide show
  1. package/package.json +7 -3
  2. package/src/actions.ts +110 -0
  3. package/src/components/AdminApp.svelte +7 -4
  4. package/src/components/Authenticated.svelte +1 -7
  5. package/src/components/AutoForm.svelte +158 -69
  6. package/src/components/AutoSaveIndicator.svelte +19 -14
  7. package/src/components/AutoTable.svelte +465 -243
  8. package/src/components/Breadcrumbs.svelte +20 -17
  9. package/src/components/ComboboxField.svelte +122 -0
  10. package/src/components/CommandPalette.svelte +93 -0
  11. package/src/components/ConfigErrorScreen.svelte +53 -151
  12. package/src/components/ConfirmDialog.svelte +25 -17
  13. package/src/components/CreatePage.svelte +3 -2
  14. package/src/components/DevTools.svelte +99 -230
  15. package/src/components/DrawerForm.svelte +19 -10
  16. package/src/components/EditPage.svelte +25 -6
  17. package/src/components/EmptyState.svelte +5 -1
  18. package/src/components/ErrorBoundary.svelte +38 -40
  19. package/src/components/ErrorComponent.svelte +18 -17
  20. package/src/components/FieldRenderer.svelte +240 -75
  21. package/src/components/ForgotPasswordPage.svelte +20 -111
  22. package/src/components/Header.svelte +28 -8
  23. package/src/components/InferencerPanel.svelte +136 -110
  24. package/src/components/InfiniteList.svelte +93 -0
  25. package/src/components/Layout.svelte +85 -22
  26. package/src/components/ListPage.svelte +25 -1
  27. package/src/components/LiveIndicator.svelte +30 -87
  28. package/src/components/LoginPage.svelte +33 -154
  29. package/src/components/ModalForm.svelte +6 -2
  30. package/src/components/PageSkeleton.svelte +2 -1
  31. package/src/components/PasswordInput.svelte +95 -0
  32. package/src/components/RegisterPage.svelte +35 -164
  33. package/src/components/ShowPage.svelte +32 -33
  34. package/src/components/Sidebar.svelte +185 -73
  35. package/src/components/StatsCard.svelte +12 -3
  36. package/src/components/StepsForm.svelte +139 -0
  37. package/src/components/Toast.svelte +15 -54
  38. package/src/components/TooltipButton.svelte +52 -0
  39. package/src/components/UndoableNotification.svelte +28 -96
  40. package/src/components/UpdatePasswordPage.svelte +32 -160
  41. package/src/components/buttons/RefreshButton.svelte +7 -2
  42. package/src/components/fieldComponentMap.ts +79 -0
  43. package/src/components/fields/BooleanField.svelte +9 -9
  44. package/src/components/fields/EmailField.svelte +2 -8
  45. package/src/components/fields/FileField.svelte +4 -9
  46. package/src/components/fields/ImageField.svelte +2 -7
  47. package/src/components/fields/JsonField.svelte +72 -0
  48. package/src/components/fields/MarkdownField.svelte +2 -12
  49. package/src/components/fields/MultiSelectField.svelte +20 -0
  50. package/src/components/fields/RelationField.svelte +24 -0
  51. package/src/components/fields/RichTextField.svelte +35 -0
  52. package/src/components/fields/SelectField.svelte +14 -0
  53. package/src/components/fields/TagField.svelte +6 -11
  54. package/src/components/fields/TextField.svelte +2 -7
  55. package/src/components/fields/UrlField.svelte +4 -10
  56. package/src/components/ui/alert-dialog/alert-dialog-content.svelte +25 -0
  57. package/src/components/ui/alert-dialog/alert-dialog-description.svelte +16 -0
  58. package/src/components/ui/alert-dialog/alert-dialog-footer.svelte +8 -0
  59. package/src/components/ui/alert-dialog/alert-dialog-header.svelte +8 -0
  60. package/src/components/ui/alert-dialog/alert-dialog-overlay.svelte +16 -0
  61. package/src/components/ui/alert-dialog/alert-dialog-portal.svelte +6 -0
  62. package/src/components/ui/alert-dialog/alert-dialog-title.svelte +16 -0
  63. package/src/components/ui/alert-dialog/index.ts +20 -0
  64. package/src/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +18 -0
  65. package/src/components/ui/breadcrumb/breadcrumb-item.svelte +15 -0
  66. package/src/components/ui/breadcrumb/breadcrumb-link.svelte +15 -0
  67. package/src/components/ui/breadcrumb/breadcrumb-list.svelte +15 -0
  68. package/src/components/ui/breadcrumb/breadcrumb-page.svelte +18 -0
  69. package/src/components/ui/breadcrumb/breadcrumb-separator.svelte +22 -0
  70. package/src/components/ui/breadcrumb/breadcrumb.svelte +11 -0
  71. package/src/components/ui/breadcrumb/index.ts +7 -0
  72. package/src/components/ui/collapsible/index.ts +7 -0
  73. package/src/components/ui/command/command-dialog.svelte +31 -0
  74. package/src/components/ui/command/index.ts +2 -0
  75. package/src/components/ui/context-menu/index.ts +11 -0
  76. package/src/components/ui/drawer/drawer-content.svelte +21 -0
  77. package/src/components/ui/drawer/drawer-description.svelte +11 -0
  78. package/src/components/ui/drawer/drawer-footer.svelte +11 -0
  79. package/src/components/ui/drawer/drawer-header.svelte +11 -0
  80. package/src/components/ui/drawer/drawer-title.svelte +11 -0
  81. package/src/components/ui/drawer/drawer.svelte +18 -0
  82. package/src/components/ui/drawer/index.ts +6 -0
  83. package/src/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +43 -0
  84. package/src/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +27 -0
  85. package/src/components/ui/dropdown-menu/index.ts +6 -0
  86. package/src/components/ui/label/index.ts +1 -0
  87. package/src/components/ui/label/label.svelte +18 -0
  88. package/src/components/ui/pagination/index.ts +7 -0
  89. package/src/components/ui/pagination/pagination-content.svelte +11 -0
  90. package/src/components/ui/pagination/pagination-ellipsis.svelte +12 -0
  91. package/src/components/ui/pagination/pagination-item.svelte +11 -0
  92. package/src/components/ui/pagination/pagination-link.svelte +26 -0
  93. package/src/components/ui/pagination/pagination-next.svelte +22 -0
  94. package/src/components/ui/pagination/pagination-previous.svelte +22 -0
  95. package/src/components/ui/pagination/pagination.svelte +11 -0
  96. package/src/components/ui/popover/index.ts +12 -0
  97. package/src/components/ui/popover/popover-content.svelte +25 -0
  98. package/src/components/ui/progress/index.ts +1 -0
  99. package/src/components/ui/progress/progress.svelte +22 -0
  100. package/src/components/ui/scroll-area/index.ts +1 -0
  101. package/src/components/ui/scroll-area/scroll-area.svelte +20 -0
  102. package/src/components/ui/sheet/index.ts +15 -1
  103. package/src/components/ui/sheet/sheet-content.svelte +28 -0
  104. package/src/components/ui/sheet/sheet-description.svelte +22 -0
  105. package/src/components/ui/sheet/sheet-footer.svelte +22 -0
  106. package/src/components/ui/sheet/sheet-header.svelte +22 -0
  107. package/src/components/ui/sheet/sheet-title.svelte +22 -0
  108. package/src/index.ts +30 -1
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { Badge } from '../ui/badge/index.js';
3
+
4
+ let { value } = $props<{
5
+ value: (string | number)[] | null | undefined;
6
+ options?: { label: string; value: string | number }[];
7
+ }>();
8
+
9
+ const items = $derived(Array.isArray(value) ? value : []);
10
+ </script>
11
+
12
+ {#if items.length > 0}
13
+ <div class="flex flex-wrap gap-1">
14
+ {#each items as item}
15
+ <Badge variant="secondary">{String(item)}</Badge>
16
+ {/each}
17
+ </div>
18
+ {:else}
19
+ <span class="text-muted-foreground">—</span>
20
+ {/if}
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import { ExternalLink } from 'lucide-svelte';
3
+
4
+ let { value, resourceName, displayValue } = $props<{
5
+ value: string | number | null | undefined;
6
+ resourceName?: string;
7
+ displayValue?: string;
8
+ }>();
9
+
10
+ const display = $derived(displayValue ?? (value != null ? `#${value}` : '—'));
11
+ const href = $derived(resourceName && value != null ? `#/${resourceName}/show/${value}` : undefined);
12
+ </script>
13
+
14
+ {#if href}
15
+ <a
16
+ {href}
17
+ class="inline-flex items-center gap-1 text-primary hover:underline text-sm"
18
+ >
19
+ {display}
20
+ <ExternalLink class="h-3 w-3" />
21
+ </a>
22
+ {:else}
23
+ <span class="text-muted-foreground">{display}</span>
24
+ {/if}
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import { t } from '@svadmin/core/i18n';
3
+ import { Button } from '../ui/button/index.js';
4
+
5
+ let { value, maxLength = 200 } = $props<{
6
+ value: string | null | undefined;
7
+ maxLength?: number;
8
+ }>();
9
+
10
+ const text = $derived(value ?? '');
11
+ const truncated = $derived(text.length > maxLength);
12
+ const display = $derived(truncated ? text.slice(0, maxLength) + '...' : text);
13
+
14
+ let showFull = $state(false);
15
+ </script>
16
+
17
+ {#if !text}
18
+ <span class="text-muted-foreground">—</span>
19
+ {:else}
20
+ <div class="prose prose-sm dark:prose-invert max-w-none">
21
+ <p class="whitespace-pre-wrap text-sm leading-relaxed">
22
+ {showFull ? text : display}
23
+ </p>
24
+ {#if truncated}
25
+ <Button
26
+ variant="link"
27
+ size="sm"
28
+ class="text-xs text-primary h-auto p-0"
29
+ onclick={() => { showFull = !showFull; }}
30
+ >
31
+ {showFull ? t('common.showLess') : t('common.showMore')}
32
+ </Button>
33
+ {/if}
34
+ </div>
35
+ {/if}
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ import { Badge } from '../ui/badge/index.js';
3
+
4
+ let { value, options } = $props<{
5
+ value: string | number | null | undefined;
6
+ options?: { label: string; value: string | number }[];
7
+ }>();
8
+
9
+ const label = $derived(
10
+ options?.find(o => o.value === value)?.label ?? (value != null ? String(value) : '—')
11
+ );
12
+ </script>
13
+
14
+ <Badge variant="outline">{label}</Badge>
@@ -1,17 +1,12 @@
1
1
  <script lang="ts">
2
- interface Props { value: string | string[] | null | undefined; color?: string }
3
- let { value, color = 'var(--color-primary, #3b82f6)' }: Props = $props();
2
+ import { Badge } from '../ui/badge/index.js';
3
+ interface Props { value: string | string[] | null | undefined }
4
+ let { value }: Props = $props();
4
5
  const tags = $derived(Array.isArray(value) ? value : value ? [value] : []);
5
6
  </script>
6
- <span class="field-tags">
7
+ <span class="inline-flex flex-wrap gap-1">
7
8
  {#each tags as tag}
8
- <span class="tag" style="--tag-color: {color}">{tag}</span>
9
+ <Badge variant="secondary">{tag}</Badge>
9
10
  {/each}
10
- {#if tags.length === 0}<span class="field-empty">—</span>{/if}
11
+ {#if tags.length === 0}<span class="text-muted-foreground">—</span>{/if}
11
12
  </span>
12
-
13
- <style>
14
- .field-tags { display: inline-flex; flex-wrap: wrap; gap: 4px; }
15
- .tag { display: inline-block; padding: 2px 8px; border-radius: 9999px; font-size: 12px; background: color-mix(in srgb, var(--tag-color) 15%, transparent); color: var(--tag-color); border: 1px solid color-mix(in srgb, var(--tag-color) 30%, transparent); }
16
- .field-empty { color: var(--color-text-muted, #9ca3af); }
17
- </style>
@@ -5,12 +5,7 @@
5
5
  const needsTooltip = $derived(value && maxLength && value.length > maxLength);
6
6
  </script>
7
7
  {#if value}
8
- <span class="field-text" title={needsTooltip ? value : undefined}>{display}</span>
8
+ <span class="inline-block" title={needsTooltip ? value : undefined}>{display}</span>
9
9
  {:else}
10
- <span class="field-text field-empty">—</span>
10
+ <span class="text-muted-foreground">—</span>
11
11
  {/if}
12
-
13
- <style>
14
- .field-text { display: inline-block; }
15
- .field-empty { color: var(--color-text-muted, #9ca3af); }
16
- </style>
@@ -1,20 +1,14 @@
1
1
  <script lang="ts">
2
+ import { ExternalLink } from 'lucide-svelte';
2
3
  interface Props { value: string | null | undefined; label?: string }
3
4
  let { value, label }: Props = $props();
4
5
  const display = $derived(label ?? value ?? '');
5
6
  </script>
6
7
  {#if value}
7
- <a href={value} target="_blank" rel="noopener noreferrer" class="field-url">
8
+ <a href={value} target="_blank" rel="noopener noreferrer" class="text-primary hover:underline no-underline inline-flex items-center gap-1">
8
9
  {display}
9
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
10
+ <ExternalLink class="h-3 w-3 opacity-60" />
10
11
  </a>
11
12
  {:else}
12
- <span class="field-url field-empty">—</span>
13
+ <span class="text-muted-foreground">—</span>
13
14
  {/if}
14
-
15
- <style>
16
- .field-url { color: var(--color-primary, #3b82f6); text-decoration: none; display: inline-flex; align-items: center; gap: 4px; }
17
- .field-url:hover { text-decoration: underline; }
18
- .field-url svg { opacity: 0.6; }
19
- .field-empty { color: var(--color-text-muted, #9ca3af); }
20
- </style>
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import type { WithoutChildrenOrChild } from "bits-ui";
4
+ import { cn } from "../../../utils.js";
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ class: className,
9
+ ...restProps
10
+ }: WithoutChildrenOrChild<AlertDialogPrimitive.ContentProps> & { class?: string } = $props();
11
+ </script>
12
+
13
+ <AlertDialogPrimitive.Portal>
14
+ <AlertDialogPrimitive.Overlay
15
+ class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
16
+ />
17
+ <AlertDialogPrimitive.Content
18
+ bind:ref
19
+ class={cn(
20
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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%] sm:rounded-lg",
21
+ className,
22
+ )}
23
+ {...restProps}
24
+ />
25
+ </AlertDialogPrimitive.Portal>
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: AlertDialogPrimitive.DescriptionProps & { class?: string } = $props();
10
+ </script>
11
+
12
+ <AlertDialogPrimitive.Description
13
+ bind:ref
14
+ class={cn("text-sm text-muted-foreground", className)}
15
+ {...restProps}
16
+ />
@@ -0,0 +1,8 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let { class: className, ...restProps }: HTMLAttributes<HTMLDivElement> = $props();
6
+ </script>
7
+
8
+ <div class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} {...restProps}></div>
@@ -0,0 +1,8 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let { class: className, ...restProps }: HTMLAttributes<HTMLDivElement> = $props();
6
+ </script>
7
+
8
+ <div class={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...restProps}></div>
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: AlertDialogPrimitive.OverlayProps & { class?: string } = $props();
10
+ </script>
11
+
12
+ <AlertDialogPrimitive.Overlay
13
+ bind:ref
14
+ class={cn("fixed inset-0 z-50 bg-black/80", className)}
15
+ {...restProps}
16
+ />
@@ -0,0 +1,6 @@
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ let { ...restProps }: AlertDialogPrimitive.PortalProps = $props();
4
+ </script>
5
+
6
+ <AlertDialogPrimitive.Portal {...restProps} />
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: AlertDialogPrimitive.TitleProps & { class?: string } = $props();
10
+ </script>
11
+
12
+ <AlertDialogPrimitive.Title
13
+ bind:ref
14
+ class={cn("text-lg font-semibold", className)}
15
+ {...restProps}
16
+ />
@@ -0,0 +1,20 @@
1
+ import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
2
+
3
+ const Root = AlertDialogPrimitive.Root;
4
+ const Trigger = AlertDialogPrimitive.Trigger;
5
+ const Action = AlertDialogPrimitive.Action;
6
+ const Cancel = AlertDialogPrimitive.Cancel;
7
+
8
+ export {
9
+ Root,
10
+ Trigger,
11
+ Action,
12
+ Cancel,
13
+ };
14
+ export { default as Content } from "./alert-dialog-content.svelte";
15
+ export { default as Description } from "./alert-dialog-description.svelte";
16
+ export { default as Footer } from "./alert-dialog-footer.svelte";
17
+ export { default as Header } from "./alert-dialog-header.svelte";
18
+ export { default as Overlay } from "./alert-dialog-overlay.svelte";
19
+ export { default as Portal } from "./alert-dialog-portal.svelte";
20
+ export { default as Title } from "./alert-dialog-title.svelte";
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { Ellipsis } from 'lucide-svelte';
5
+
6
+ let { class: className, ...restProps }: HTMLAttributes<HTMLSpanElement> = $props();
7
+ </script>
8
+
9
+ <span
10
+ role="presentation"
11
+ aria-hidden="true"
12
+ data-slot="breadcrumb-ellipsis"
13
+ class={cn("flex size-9 items-center justify-center", className)}
14
+ {...restProps}
15
+ >
16
+ <Ellipsis class="size-4" />
17
+ <span class="sr-only">More</span>
18
+ </span>
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLLiAttributes } from 'svelte/elements';
5
+
6
+ let { class: className, children, ...restProps }: HTMLLiAttributes & { children?: Snippet } = $props();
7
+ </script>
8
+
9
+ <li
10
+ data-slot="breadcrumb-item"
11
+ class={cn("inline-flex items-center gap-1.5", className)}
12
+ {...restProps}
13
+ >
14
+ {@render children?.()}
15
+ </li>
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
5
+
6
+ let { class: className, children, ...restProps }: HTMLAnchorAttributes & { children?: Snippet } = $props();
7
+ </script>
8
+
9
+ <a
10
+ data-slot="breadcrumb-link"
11
+ class={cn("hover:text-foreground transition-colors", className)}
12
+ {...restProps}
13
+ >
14
+ {@render children?.()}
15
+ </a>
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLOlAttributes } from 'svelte/elements';
5
+
6
+ let { class: className, children, ...restProps }: HTMLOlAttributes & { children?: Snippet } = $props();
7
+ </script>
8
+
9
+ <ol
10
+ data-slot="breadcrumb-list"
11
+ class={cn("text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5", className)}
12
+ {...restProps}
13
+ >
14
+ {@render children?.()}
15
+ </ol>
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLAttributes } from 'svelte/elements';
5
+
6
+ let { class: className, children, ...restProps }: HTMLAttributes<HTMLSpanElement> & { children?: Snippet } = $props();
7
+ </script>
8
+
9
+ <span
10
+ role="link"
11
+ aria-disabled="true"
12
+ aria-current="page"
13
+ data-slot="breadcrumb-page"
14
+ class={cn("text-foreground font-normal", className)}
15
+ {...restProps}
16
+ >
17
+ {@render children?.()}
18
+ </span>
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLLiAttributes } from 'svelte/elements';
5
+ import { ChevronRight } from 'lucide-svelte';
6
+
7
+ let { class: className, children, ...restProps }: HTMLLiAttributes & { children?: Snippet } = $props();
8
+ </script>
9
+
10
+ <li
11
+ role="presentation"
12
+ aria-hidden="true"
13
+ data-slot="breadcrumb-separator"
14
+ class={cn("[&>svg]:size-3.5", className)}
15
+ {...restProps}
16
+ >
17
+ {#if children}
18
+ {@render children()}
19
+ {:else}
20
+ <ChevronRight />
21
+ {/if}
22
+ </li>
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLAttributes } from 'svelte/elements';
5
+
6
+ let { class: className, children, ...restProps }: HTMLAttributes<HTMLElement> & { children?: Snippet } = $props();
7
+ </script>
8
+
9
+ <nav aria-label="breadcrumb" data-slot="breadcrumb" class={cn("", className)} {...restProps}>
10
+ {@render children?.()}
11
+ </nav>
@@ -0,0 +1,7 @@
1
+ export { default as Root } from './breadcrumb.svelte';
2
+ export { default as Item } from './breadcrumb-item.svelte';
3
+ export { default as Link } from './breadcrumb-link.svelte';
4
+ export { default as Page } from './breadcrumb-page.svelte';
5
+ export { default as Separator } from './breadcrumb-separator.svelte';
6
+ export { default as Ellipsis } from './breadcrumb-ellipsis.svelte';
7
+ export { default as List } from './breadcrumb-list.svelte';
@@ -0,0 +1,7 @@
1
+ import { Collapsible as CollapsiblePrimitive } from 'bits-ui';
2
+
3
+ const Root = CollapsiblePrimitive.Root;
4
+ const Trigger = CollapsiblePrimitive.Trigger;
5
+ const Content = CollapsiblePrimitive.Content;
6
+
7
+ export { Root, Trigger, Content };
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import { Command } from 'cmdk-sv';
3
+ import * as Dialog from '../dialog/index.js';
4
+ import { cn } from '../../../utils.js';
5
+ import type { Snippet } from 'svelte';
6
+
7
+ let {
8
+ open = $bindable(false),
9
+ class: className,
10
+ children,
11
+ ...restProps
12
+ }: {
13
+ open?: boolean;
14
+ class?: string;
15
+ children?: Snippet;
16
+ [key: string]: unknown;
17
+ } = $props();
18
+ </script>
19
+
20
+ <Dialog.Dialog bind:open {...restProps}>
21
+ <Dialog.DialogContent class="overflow-hidden p-0">
22
+ <Command.Root
23
+ class={cn(
24
+ "[&_[data-cmdk-group-heading]]:text-muted-foreground flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground [&_[data-cmdk-group-heading]]:px-2 [&_[data-cmdk-group-heading]]:font-medium [&_[data-cmdk-group]:not([hidden])_~[data-cmdk-group]]:pt-0 [&_[data-cmdk-input-wrapper]_svg]:h-5 [&_[data-cmdk-input-wrapper]_svg]:w-5 [&_[data-cmdk-input]]:h-12 [&_[data-cmdk-item]]:px-2 [&_[data-cmdk-item]]:py-3",
25
+ className
26
+ )}
27
+ >
28
+ {@render children?.()}
29
+ </Command.Root>
30
+ </Dialog.DialogContent>
31
+ </Dialog.Dialog>
@@ -0,0 +1,2 @@
1
+ export { Command as Root, Command } from 'cmdk-sv';
2
+ export { default as CommandDialog } from './command-dialog.svelte';
@@ -0,0 +1,11 @@
1
+ import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
2
+
3
+ const Root = ContextMenuPrimitive.Root;
4
+ const Trigger = ContextMenuPrimitive.Trigger;
5
+ const Content = ContextMenuPrimitive.Content;
6
+ const Item = ContextMenuPrimitive.Item;
7
+ const Separator = ContextMenuPrimitive.Separator;
8
+ const Group = ContextMenuPrimitive.Group;
9
+ const GroupHeading = ContextMenuPrimitive.GroupHeading;
10
+
11
+ export { Root, Trigger, Content, Item, Separator, Group, GroupHeading };
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import { Drawer as DrawerPrimitive } from 'vaul-svelte';
3
+ import { cn } from '../../../utils.js';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ let { class: className, children, ...restProps }: { class?: string; children?: Snippet; [key: string]: unknown } = $props();
7
+ </script>
8
+
9
+ <DrawerPrimitive.Portal>
10
+ <DrawerPrimitive.Overlay class="fixed inset-0 z-50 bg-black/80" />
11
+ <DrawerPrimitive.Content
12
+ class={cn(
13
+ "bg-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border",
14
+ className
15
+ )}
16
+ {...restProps}
17
+ >
18
+ <div class="bg-muted mx-auto mt-4 h-2 w-[100px] rounded-full"></div>
19
+ {@render children?.()}
20
+ </DrawerPrimitive.Content>
21
+ </DrawerPrimitive.Portal>
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { Drawer as DrawerPrimitive } from 'vaul-svelte';
3
+ import { cn } from '../../../utils.js';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ let { class: className, children, ...restProps }: { class?: string; children?: Snippet; [key: string]: unknown } = $props();
7
+ </script>
8
+
9
+ <DrawerPrimitive.Description class={cn("text-muted-foreground text-sm", className)} {...restProps}>
10
+ {@render children?.()}
11
+ </DrawerPrimitive.Description>
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLAttributes } from 'svelte/elements';
5
+
6
+ let { class: className, children, ...restProps }: HTMLAttributes<HTMLDivElement> & { children?: Snippet } = $props();
7
+ </script>
8
+
9
+ <div data-slot="drawer-footer" class={cn("mt-auto flex flex-col gap-2 p-4", className)} {...restProps}>
10
+ {@render children?.()}
11
+ </div>
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import type { Snippet } from 'svelte';
4
+ import type { HTMLAttributes } from 'svelte/elements';
5
+
6
+ let { class: className, children, ...restProps }: HTMLAttributes<HTMLDivElement> & { children?: Snippet } = $props();
7
+ </script>
8
+
9
+ <div data-slot="drawer-header" class={cn("grid gap-1.5 p-4 text-center sm:text-left", className)} {...restProps}>
10
+ {@render children?.()}
11
+ </div>
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { Drawer as DrawerPrimitive } from 'vaul-svelte';
3
+ import { cn } from '../../../utils.js';
4
+ import type { Snippet } from 'svelte';
5
+
6
+ let { class: className, children, ...restProps }: { class?: string; children?: Snippet; [key: string]: unknown } = $props();
7
+ </script>
8
+
9
+ <DrawerPrimitive.Title class={cn("text-lg font-semibold leading-none tracking-tight", className)} {...restProps}>
10
+ {@render children?.()}
11
+ </DrawerPrimitive.Title>
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import { Drawer as DrawerPrimitive } from 'vaul-svelte';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ let {
6
+ open = $bindable(false),
7
+ children,
8
+ ...restProps
9
+ }: {
10
+ open?: boolean;
11
+ children?: Snippet;
12
+ [key: string]: unknown;
13
+ } = $props();
14
+ </script>
15
+
16
+ <DrawerPrimitive.Root bind:open {...restProps}>
17
+ {@render children?.()}
18
+ </DrawerPrimitive.Root>
@@ -0,0 +1,6 @@
1
+ export { default as Root } from './drawer.svelte';
2
+ export { default as Content } from './drawer-content.svelte';
3
+ export { default as Header } from './drawer-header.svelte';
4
+ export { default as Footer } from './drawer-footer.svelte';
5
+ export { default as Title } from './drawer-title.svelte';
6
+ export { default as Description } from './drawer-description.svelte';
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "../../../utils.js";
3
+ import type { HTMLButtonAttributes } from "svelte/elements";
4
+
5
+ type Props = WithElementRef<HTMLButtonAttributes> & {
6
+ checked?: boolean;
7
+ onCheckedChange?: (checked: boolean) => void;
8
+ };
9
+
10
+ let {
11
+ ref = $bindable(null),
12
+ class: className,
13
+ checked = false,
14
+ onCheckedChange,
15
+ children,
16
+ ...restProps
17
+ }: Props = $props();
18
+
19
+ function handleClick() {
20
+ const next = !checked;
21
+ onCheckedChange?.(next);
22
+ }
23
+ </script>
24
+
25
+ <button
26
+ bind:this={ref}
27
+ role="menuitemcheckbox"
28
+ aria-checked={checked}
29
+ data-slot="dropdown-menu-checkbox-item"
30
+ class={cn(
31
+ "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
32
+ className
33
+ )}
34
+ onclick={handleClick}
35
+ {...restProps}
36
+ >
37
+ <span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
38
+ {#if checked}
39
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
40
+ {/if}
41
+ </span>
42
+ {@render children?.()}
43
+ </button>