refactor: migrate shadcn-components to Svelte 5 and TW4 (#551)

Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
Kyle Mendell
2025-05-21 12:15:27 -05:00
committed by Elias Schneider
parent 05b443d984
commit 28c85990ba
197 changed files with 8142 additions and 7471 deletions

View File

@@ -3,19 +3,16 @@
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
type $$Props = AlertDialogPrimitive.ActionProps;
type $$Events = AlertDialogPrimitive.ActionEvents;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AlertDialogPrimitive.ActionProps = $props();
</script>
<AlertDialogPrimitive.Action
bind:ref
data-slot="alert-dialog-action"
class={cn(buttonVariants(), className)}
{...$$restProps}
on:click
on:keydown
let:builder
>
<slot {builder} />
</AlertDialogPrimitive.Action>
{...restProps}
/>

View File

@@ -3,19 +3,16 @@
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
type $$Props = AlertDialogPrimitive.CancelProps;
type $$Events = AlertDialogPrimitive.CancelEvents;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AlertDialogPrimitive.CancelProps = $props();
</script>
<AlertDialogPrimitive.Cancel
class={cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className)}
{...$$restProps}
on:click
on:keydown
let:builder
>
<slot {builder} />
</AlertDialogPrimitive.Cancel>
bind:ref
data-slot="alert-dialog-cancel"
class={cn(buttonVariants({ variant: 'outline' }), className)}
{...restProps}
/>

View File

@@ -1,28 +1,27 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import * as AlertDialog from './index.js';
import { cn, flyAndScale } from '$lib/utils/style.js';
import AlertDialogOverlay from './alert-dialog-overlay.svelte';
import { cn, type WithoutChild, type WithoutChildrenOrChild } from '$lib/utils/style.js';
type $$Props = AlertDialogPrimitive.ContentProps;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = undefined;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
portalProps,
...restProps
}: WithoutChild<AlertDialogPrimitive.ContentProps> & {
portalProps?: WithoutChildrenOrChild<AlertDialogPrimitive.PortalProps>;
} = $props();
</script>
<AlertDialog.Portal>
<AlertDialog.Overlay />
<AlertDialogPrimitive.Portal {...portalProps}>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
{transition}
{transitionConfig}
bind:ref
data-slot="alert-dialog-content"
class={cn(
'bg-background fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg sm:rounded-lg md:w-full',
'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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
className
)}
{...$$restProps}
>
<slot />
</AlertDialogPrimitive.Content>
</AlertDialog.Portal>
{...restProps}
/>
</AlertDialogPrimitive.Portal>

View File

@@ -2,15 +2,16 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = AlertDialogPrimitive.DescriptionProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AlertDialogPrimitive.DescriptionProps = $props();
</script>
<AlertDialogPrimitive.Description
bind:ref
data-slot="alert-dialog-description"
class={cn('text-muted-foreground text-sm', className)}
{...$$restProps}
>
<slot />
</AlertDialogPrimitive.Description>
{...restProps}
/>

View File

@@ -1,16 +1,20 @@
<script lang="ts">
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
class={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
{...$$restProps}
bind:this={ref}
data-slot="alert-dialog-footer"
class={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
{...restProps}
>
<slot />
{@render children?.()}
</div>

View File

@@ -1,13 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div class={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...$$restProps}>
<slot />
<div
bind:this={ref}
data-slot="alert-dialog-header"
class={cn('flex flex-col gap-2 text-center sm:text-left', className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,21 +1,20 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { fade } from 'svelte/transition';
import { cn } from '$lib/utils/style.js';
type $$Props = AlertDialogPrimitive.OverlayProps;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = fade;
export let transitionConfig: $$Props['transitionConfig'] = {
duration: 150
};
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AlertDialogPrimitive.OverlayProps = $props();
</script>
<AlertDialogPrimitive.Overlay
{transition}
{transitionConfig}
class={cn('bg-background/80 fixed inset-0 z-50 backdrop-blur-sm ', className)}
{...$$restProps}
bind:ref
data-slot="alert-dialog-overlay"
class={cn(
'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/50',
className
)}
{...restProps}
/>

View File

@@ -1,9 +0,0 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
type $$Props = AlertDialogPrimitive.PortalProps;
</script>
<AlertDialogPrimitive.Portal {...$$restProps}>
<slot />
</AlertDialogPrimitive.Portal>

View File

@@ -2,13 +2,16 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = AlertDialogPrimitive.TitleProps;
let className: $$Props['class'] = undefined;
export let level: $$Props['level'] = 'h3';
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AlertDialogPrimitive.TitleProps = $props();
</script>
<AlertDialogPrimitive.Title class={cn('text-lg font-semibold', className)} {level} {...$$restProps}>
<slot />
</AlertDialogPrimitive.Title>
<AlertDialogPrimitive.Title
bind:ref
data-slot="alert-dialog-title"
class={cn('text-lg font-semibold', className)}
{...restProps}
/>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: AlertDialogPrimitive.TriggerProps = $props();
</script>
<AlertDialogPrimitive.Trigger bind:ref data-slot="alert-dialog-trigger" {...restProps} />

View File

@@ -1,9 +1,8 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Title from './alert-dialog-title.svelte';
import Action from './alert-dialog-action.svelte';
import Cancel from './alert-dialog-cancel.svelte';
import Portal from './alert-dialog-portal.svelte';
import Footer from './alert-dialog-footer.svelte';
import Header from './alert-dialog-header.svelte';
import Overlay from './alert-dialog-overlay.svelte';
@@ -11,14 +10,12 @@ import Content from './alert-dialog-content.svelte';
import Description from './alert-dialog-description.svelte';
const Root = AlertDialogPrimitive.Root;
const Trigger = AlertDialogPrimitive.Trigger;
export {
Root,
Title,
Action,
Cancel,
Portal,
Footer,
Header,
Trigger,
@@ -30,7 +27,6 @@ export {
Title as AlertDialogTitle,
Action as AlertDialogAction,
Cancel as AlertDialogCancel,
Portal as AlertDialogPortal,
Footer as AlertDialogFooter,
Header as AlertDialogHeader,
Trigger as AlertDialogTrigger,

View File

@@ -1,13 +1,23 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div class={cn('text-sm [&_p]:leading-relaxed', className)} {...$$restProps}>
<slot />
<div
bind:this={ref}
data-slot="alert-description"
class={cn(
'text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed',
className
)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,21 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { HeadingLevel } from './index.js';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLHeadingElement> & {
level?: HeadingLevel;
};
let className: $$Props['class'] = undefined;
export let level: $$Props['level'] = 'h5';
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<svelte:element
this={level}
class={cn('mb-1 leading-none font-medium tracking-tight', className)}
{...$$restProps}
<div
bind:this={ref}
data-slot="alert-title"
class={cn('col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight', className)}
{...restProps}
>
<slot />
</svelte:element>
{@render children?.()}
</div>

View File

@@ -1,21 +1,44 @@
<script lang="ts" module>
import { type VariantProps, tv } from 'tailwind-variants';
export const alertVariants = tv({
base: 'relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
variants: {
variant: {
default: 'bg-card text-card-foreground',
destructive:
'text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current',
warning:
'bg-amber-100 text-amber-900 dark:bg-amber-900 dark:text-amber-100 [&>svg]:text-amber-900 dark:[&>svg]:text-amber-100'
}
},
defaultVariants: {
variant: 'default'
}
});
export type AlertVariant = VariantProps<typeof alertVariants>['variant'];
</script>
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { LucideX } from 'lucide-svelte';
import { onMount } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
import { type Variant, alertVariants } from './index.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
import { onMount } from 'svelte';
import { LucideX } from '@lucide/svelte';
type $$Props = HTMLAttributes<HTMLDivElement> & {
variant?: Variant;
let {
ref = $bindable(null),
class: className,
variant = 'default',
children,
dismissibleId = undefined,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
variant?: AlertVariant;
dismissibleId?: string;
};
} = $props();
let className: $$Props['class'] = undefined;
export let variant: $$Props['variant'] = 'default';
export let dismissibleId: $$Props['dismissibleId'] = undefined;
export { className as class };
let isVisible = !dismissibleId;
let isVisible = $state(!dismissibleId);
onMount(() => {
if (dismissibleId) {
@@ -34,11 +57,17 @@
</script>
{#if isVisible}
<div class={cn(alertVariants({ variant }), className)} {...$$restProps} role="alert">
<slot />
<div
bind:this={ref}
data-slot="alert"
class={cn(alertVariants({ variant }), className)}
{...restProps}
role="alert"
>
{@render children?.()}
{#if dismissibleId}
<button on:click={dismiss} class="absolute top-0 right-0 m-3 text-black dark:text-white"
><LucideX class="w-4" /></button
<button onclick={dismiss} class="absolute top-0 right-0 m-3 text-black dark:text-white"
><LucideX class="size-4" /></button
>
{/if}
</div>

View File

@@ -1,35 +1,14 @@
import { type VariantProps, tv } from 'tailwind-variants';
import Root from './alert.svelte';
import Description from './alert-description.svelte';
import Title from './alert-title.svelte';
import Root from './alert.svelte';
export const alertVariants = tv({
base: '[&>svg]:text-foreground relative w-full rounded-lg border p-4 [&:has(svg)]:pl-11 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4',
variants: {
variant: {
default: 'bg-background text-foreground',
destructive:
'border-destructive/50 text-destructive text-destructive dark:border-destructive [&>svg]:text-destructive',
warning:
'bg-amber-100 text-amber-900 dark:bg-amber-900 dark:text-amber-100 [&>svg]:text-amber-900 dark:[&>svg]:text-amber-100'
}
},
defaultVariants: {
variant: 'default'
}
});
export type Variant = VariantProps<typeof alertVariants>['variant'];
export type HeadingLevel = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export { alertVariants, type AlertVariant } from './alert.svelte';
export {
Root,
Description,
Title,
//
Root as Alert,
Description as AlertDescription,
Title as AlertTitle,
Description,
Root,
Title
Title as AlertTitle
};

View File

@@ -2,15 +2,16 @@
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = AvatarPrimitive.FallbackProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AvatarPrimitive.FallbackProps = $props();
</script>
<AvatarPrimitive.Fallback
class={cn('bg-muted flex h-full w-full items-center justify-center rounded-full', className)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Fallback>
bind:ref
data-slot="avatar-fallback"
class={cn('bg-muted flex size-full items-center justify-center rounded-full', className)}
{...restProps}
/>

View File

@@ -2,17 +2,16 @@
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = AvatarPrimitive.ImageProps;
let className: $$Props['class'] = undefined;
export let src: $$Props['src'] = undefined;
export let alt: $$Props['alt'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AvatarPrimitive.ImageProps = $props();
</script>
<AvatarPrimitive.Image
{src}
{alt}
class={cn('aspect-square h-full w-full', className)}
{...$$restProps}
bind:ref
data-slot="avatar-image"
class={cn('aspect-square size-full', className)}
{...restProps}
/>

View File

@@ -2,17 +2,16 @@
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = AvatarPrimitive.Props;
let className: $$Props['class'] = undefined;
export let delayMs: $$Props['delayMs'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: AvatarPrimitive.RootProps = $props();
</script>
<AvatarPrimitive.Root
{delayMs}
class={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full border', className)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Root>
bind:ref
data-slot="avatar"
class={cn('relative flex size-10 shrink-0 overflow-hidden rounded-full border', className)}
{...restProps}
/>

View File

@@ -1,18 +1,49 @@
<script lang="ts">
import { type Variant, badgeVariants } from './index.js';
import { cn } from '$lib/utils/style.js';
<script lang="ts" module>
import { type VariantProps, tv } from 'tailwind-variants';
let className: string | undefined | null = undefined;
export let href: string | undefined = undefined;
export let variant: Variant = 'default';
export { className as class };
export const badgeVariants = tv({
base: 'focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded-md border px-2 py-0.5 text-xs font-medium transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3',
variants: {
variant: {
default: 'bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent',
secondary:
'bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent',
destructive:
'bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70 border-transparent text-white',
outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground'
}
},
defaultVariants: {
variant: 'default'
}
});
export type BadgeVariant = VariantProps<typeof badgeVariants>['variant'];
</script>
<script lang="ts">
import type { HTMLAnchorAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils/style.js';
let {
ref = $bindable(null),
href,
class: className,
variant = 'default',
children,
...restProps
}: WithElementRef<HTMLAnchorAttributes> & {
variant?: BadgeVariant;
} = $props();
</script>
<svelte:element
this={href ? 'a' : 'span'}
bind:this={ref}
data-slot="badge"
{href}
class={cn(badgeVariants({ variant, className }))}
{...$$restProps}
class={cn(badgeVariants({ variant }), className)}
{...restProps}
>
<slot />
{@render children?.()}
</svelte:element>

View File

@@ -1,20 +1,2 @@
import { type VariantProps, tv } from 'tailwind-variants';
export { default as Badge } from './badge.svelte';
export const badgeVariants = tv({
base: 'inline-flex select-none items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 break-keep whitespace-nowrap',
variants: {
variant: {
default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
destructive:
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
outline: 'text-foreground'
}
},
defaultVariants: {
variant: 'default'
}
});
export type Variant = VariantProps<typeof badgeVariants>['variant'];
export { badgeVariants, type BadgeVariant } from './badge.svelte';

View File

@@ -1,33 +1,90 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { Button as ButtonPrimitive } from 'bits-ui';
import LoaderCircle from 'lucide-svelte/icons/loader-circle';
import type { ClassNameValue } from 'tailwind-merge';
import { type Events, type Props, buttonVariants } from './index.js';
<script lang="ts" module>
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
import { type VariantProps, tv } from 'tailwind-variants';
type $$Props = Props;
type $$Events = Events;
export const buttonVariants = tv({
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
variants: {
variant: {
default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
destructive:
'bg-destructive shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white',
outline:
'bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border',
secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5',
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
icon: 'size-9'
}
},
defaultVariants: {
variant: 'default',
size: 'default'
}
});
let className: $$Props['class'] = undefined;
export let variant: $$Props['variant'] = 'default';
export let size: $$Props['size'] = 'default';
export let disabled: boolean | undefined | null = false;
export let isLoading: $$Props['isLoading'] = false;
export let builders: $$Props['builders'] = [];
export { className as class };
export type ButtonVariant = VariantProps<typeof buttonVariants>['variant'];
export type ButtonSize = VariantProps<typeof buttonVariants>['size'];
export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
WithElementRef<HTMLAnchorAttributes> & {
variant?: ButtonVariant;
size?: ButtonSize;
isLoading?: boolean;
};
</script>
<ButtonPrimitive.Root
{builders}
disabled={isLoading || disabled}
class={cn(buttonVariants({ variant, size, className: className as ClassNameValue }))}
type="button"
{...$$restProps}
on:click
on:keydown
>
{#if isLoading}
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
{/if}
<slot />
</ButtonPrimitive.Root>
<script lang="ts">
import LoaderCircle from '@lucide/svelte/icons/loader-circle';
let {
class: className,
variant = 'default',
size = 'default',
ref = $bindable(null),
href = undefined,
type = 'button',
disabled,
isLoading = false,
children,
...restProps
}: ButtonProps = $props();
</script>
{#if href}
<a
bind:this={ref}
data-slot="button"
class={cn(buttonVariants({ variant, size }), className)}
href={disabled ? undefined : href}
aria-disabled={disabled}
role={disabled ? 'link' : undefined}
tabindex={disabled ? -1 : undefined}
{...restProps}
>
{#if isLoading}
<LoaderCircle class="mr-2 size-4 animate-spin" />
{/if}
{@render children?.()}
</a>
{:else}
<button
bind:this={ref}
data-slot="button"
class={cn(buttonVariants({ variant, size }), className)}
{type}
{disabled}
{...restProps}
>
{#if isLoading}
<LoaderCircle class="mr-2 size-4 animate-spin" />
{/if}
{@render children?.()}
</button>
{/if}

View File

@@ -1,49 +1,17 @@
import { type VariantProps, tv } from 'tailwind-variants';
import type { Button as ButtonPrimitive } from 'bits-ui';
import Root from './button.svelte';
const buttonVariants = tv({
base: 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10'
}
},
defaultVariants: {
variant: 'default',
size: 'default'
}
});
type Variant = VariantProps<typeof buttonVariants>['variant'];
type Size = VariantProps<typeof buttonVariants>['size'];
type Props = ButtonPrimitive.Props & {
variant?: Variant;
size?: Size;
isLoading?: boolean;
};
type Events = ButtonPrimitive.Events;
import Root, {
type ButtonProps,
type ButtonSize,
type ButtonVariant,
buttonVariants
} from './button.svelte';
export {
Root,
type Props,
type Events,
type ButtonProps as Props,
//
Root as Button,
type Props as ButtonProps,
type Events as ButtonEvents,
buttonVariants
buttonVariants,
type ButtonProps,
type ButtonSize,
type ButtonVariant
};

View File

@@ -2,20 +2,18 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.CellProps;
export let date: $$Props['date'];
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.CellProps = $props();
</script>
<CalendarPrimitive.Cell
{date}
bind:ref
class={cn(
'[&:has([data-selected])]:bg-accent [&:has([data-selected][data-outside-month])]:bg-accent/50 relative h-9 w-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:rounded-md',
'[&:has([data-selected])]:bg-accent [&:has([data-selected][data-outside-month])]:bg-accent/50 relative size-8 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:rounded-md',
className
)}
{...$$restProps}
>
<slot />
</CalendarPrimitive.Cell>
{...restProps}
/>

View File

@@ -1,42 +1,30 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
import { Calendar as CalendarPrimitive } from 'bits-ui';
type $$Props = CalendarPrimitive.DayProps;
type $$Events = CalendarPrimitive.DayEvents;
export let date: $$Props['date'];
export let month: $$Props['month'];
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.DayProps = $props();
</script>
<CalendarPrimitive.Day
on:click
{date}
{month}
bind:ref
class={cn(
buttonVariants({ variant: 'ghost' }),
'h-9 w-9 p-0 font-normal ',
'size-8 p-0 font-normal select-none',
'[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground',
// Selected
'data-[selected]:bg-primary data-[selected]:text-primary-foreground data-[selected]:hover:bg-primary data-[selected]:hover:text-primary-foreground data-[selected]:focus:bg-primary data-[selected]:focus:text-primary-foreground data-[selected]:opacity-100',
'data-selected:bg-primary data-selected:text-primary-foreground data-selected:hover:bg-primary data-selected:hover:text-primary-foreground data-selected:focus:bg-primary data-selected:focus:text-primary-foreground dark:data-selected:hover:bg-primary dark:data-selected:focus:bg-primary data-selected:opacity-100',
// Disabled
'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',
'data-disabled:text-muted-foreground data-disabled:opacity-50',
// Unavailable
'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through',
'data-unavailable:text-destructive-foreground data-unavailable:line-through',
// Outside months
'data-[outside-month]:text-muted-foreground [&[data-outside-month][data-selected]]:bg-accent/50 [&[data-outside-month][data-selected]]:text-muted-foreground data-[outside-month]:pointer-events-none data-[outside-month]:opacity-50 [&[data-outside-month][data-selected]]:opacity-30',
className
)}
{...$$restProps}
let:selected
let:disabled
let:unavailable
let:builder
>
<slot {selected} {disabled} {unavailable} {builder}>
{date.day}
</slot>
</CalendarPrimitive.Day>
{...restProps}
/>

View File

@@ -2,12 +2,11 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.GridBodyProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.GridBodyProps = $props();
</script>
<CalendarPrimitive.GridBody class={cn(className)} {...$$restProps}>
<slot />
</CalendarPrimitive.GridBody>
<CalendarPrimitive.GridBody bind:ref class={cn(className)} {...restProps} />

View File

@@ -2,12 +2,11 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.GridHeadProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.GridHeadProps = $props();
</script>
<CalendarPrimitive.GridHead class={cn(className)} {...$$restProps}>
<slot />
</CalendarPrimitive.GridHead>
<CalendarPrimitive.GridHead bind:ref class={cn(className)} {...restProps} />

View File

@@ -2,12 +2,11 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.GridRowProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.GridRowProps = $props();
</script>
<CalendarPrimitive.GridRow class={cn('flex', className)} {...$$restProps}>
<slot />
</CalendarPrimitive.GridRow>
<CalendarPrimitive.GridRow bind:ref class={cn('flex', className)} {...restProps} />

View File

@@ -2,12 +2,15 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.GridProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.GridProps = $props();
</script>
<CalendarPrimitive.Grid class={cn('w-full border-collapse space-y-1', className)} {...$$restProps}>
<slot />
</CalendarPrimitive.Grid>
<CalendarPrimitive.Grid
bind:ref
class={cn('w-full border-collapse space-y-1', className)}
{...restProps}
/>

View File

@@ -2,15 +2,15 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.HeadCellProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.HeadCellProps = $props();
</script>
<CalendarPrimitive.HeadCell
class={cn('text-muted-foreground w-9 rounded-md text-[0.8rem] font-normal', className)}
{...$$restProps}
>
<slot />
</CalendarPrimitive.HeadCell>
bind:ref
class={cn('text-muted-foreground w-8 rounded-md text-[0.8rem] font-normal', className)}
{...restProps}
/>

View File

@@ -2,15 +2,15 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.HeaderProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.HeaderProps = $props();
</script>
<CalendarPrimitive.Header
bind:ref
class={cn('relative flex w-full items-center justify-between pt-1', className)}
{...$$restProps}
>
<slot />
</CalendarPrimitive.Header>
{...restProps}
/>

View File

@@ -2,18 +2,11 @@
import { Calendar as CalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.HeadingProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CalendarPrimitive.HeadingProps = $props();
</script>
<CalendarPrimitive.Heading
let:headingValue
class={cn('text-sm font-medium', className)}
{...$$restProps}
>
<slot {headingValue}>
{headingValue}
</slot>
</CalendarPrimitive.Heading>
<CalendarPrimitive.Heading bind:ref class={cn('text-sm font-medium', className)} {...restProps} />

View File

@@ -1,16 +1,19 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
bind:this={ref}
class={cn('mt-4 flex flex-col space-y-4 sm:flex-row sm:space-y-0 sm:space-x-4', className)}
{...$$restProps}
{...restProps}
>
<slot />
{@render children?.()}
</div>

View File

@@ -1,27 +1,28 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from 'bits-ui';
import ChevronRight from 'lucide-svelte/icons/chevron-right';
import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.NextButtonProps;
type $$Events = CalendarPrimitive.NextButtonEvents;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: CalendarPrimitive.PrevButtonProps = $props();
</script>
{#snippet Fallback()}
<ChevronRightIcon class="size-4" />
{/snippet}
<CalendarPrimitive.NextButton
on:click
bind:ref
class={cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
'size-7 bg-transparent p-0 opacity-50 hover:opacity-100',
className
)}
{...$$restProps}
let:builder
>
<slot {builder}>
<ChevronRight class="h-4 w-4" />
</slot>
</CalendarPrimitive.NextButton>
children={children || Fallback}
{...restProps}
/>

View File

@@ -1,27 +1,28 @@
<script lang="ts">
import { Calendar as CalendarPrimitive } from 'bits-ui';
import ChevronLeft from 'lucide-svelte/icons/chevron-left';
import ChevronLeftIcon from '@lucide/svelte/icons/chevron-left';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.PrevButtonProps;
type $$Events = CalendarPrimitive.PrevButtonEvents;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: CalendarPrimitive.PrevButtonProps = $props();
</script>
{#snippet Fallback()}
<ChevronLeftIcon class="size-4" />
{/snippet}
<CalendarPrimitive.PrevButton
on:click
bind:ref
class={cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
'size-7 bg-transparent p-0 opacity-50 hover:opacity-100',
className
)}
{...$$restProps}
let:builder
>
<slot {builder}>
<ChevronLeft class="h-4 w-4" />
</slot>
</CalendarPrimitive.PrevButton>
children={children || Fallback}
{...restProps}
/>

View File

@@ -1,137 +1,61 @@
<script lang="ts">
import * as Calendar from '$lib/components/ui/calendar/index.js';
import * as Select from '$lib/components/ui/select/index.js';
import { cn } from '$lib/utils/style';
import { DateFormatter, getLocalTimeZone, today } from '@internationalized/date';
import { Calendar as CalendarPrimitive } from 'bits-ui';
import * as Calendar from './index.js';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
type $$Props = CalendarPrimitive.Props;
type $$Events = CalendarPrimitive.Events;
export let value: $$Props['value'] = undefined;
export let placeholder: $$Props['placeholder'] = today(getLocalTimeZone());
export let weekdayFormat: $$Props['weekdayFormat'] = 'short';
const monthOptions = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
].map((month, i) => ({ value: i + 1, label: month }));
const monthFmt = new DateFormatter('en-US', {
month: 'long'
});
const yearOptions = Array.from({ length: 100 }, (_, i) => ({
label: String(new Date().getFullYear() + i),
value: new Date().getFullYear() + i
}));
$: defaultYear = placeholder
? {
value: placeholder.year,
label: String(placeholder.year)
}
: undefined;
$: defaultMonth = placeholder
? {
value: placeholder.month,
label: monthFmt.format(placeholder.toDate(getLocalTimeZone()))
}
: undefined;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
value = $bindable(),
placeholder = $bindable(),
class: className,
weekdayFormat = 'short',
...restProps
}: WithoutChildrenOrChild<CalendarPrimitive.RootProps> = $props();
</script>
<!--
Discriminated Unions + Destructing (required for bindable) do not
get along, so we shut typescript up by casting `value` to `never`.
-->
<CalendarPrimitive.Root
{weekdayFormat}
class={cn('rounded-md border p-3', className)}
{...$$restProps}
on:keydown
let:months
let:weekdays
bind:value
bind:value={value as never}
bind:ref
bind:placeholder
{weekdayFormat}
class={cn('p-3', className)}
{...restProps}
>
<Calendar.Header>
<Calendar.Heading class="flex w-full items-center justify-between gap-2">
<Select.Root
selected={defaultMonth}
items={monthOptions}
onSelectedChange={(v) => {
if (!v || !placeholder) return;
if (v.value === placeholder?.month) return;
placeholder = placeholder.set({ month: v.value });
}}
>
<Select.Trigger aria-label="Select month" class="w-[60%]">
<Select.Value placeholder="Select month" />
</Select.Trigger>
<Select.Content class="max-h-[200px] overflow-y-auto">
{#each monthOptions as { value, label }}
<Select.Item {value} {label}>
{label}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
<Select.Root
selected={defaultYear}
items={yearOptions}
onSelectedChange={(v) => {
if (!v || !placeholder) return;
if (v.value === placeholder?.year) return;
placeholder = placeholder.set({ year: v.value });
}}
>
<Select.Trigger aria-label="Select year" class="w-[40%]">
<Select.Value placeholder="Select year" />
</Select.Trigger>
<Select.Content class="max-h-[200px] overflow-y-auto">
{#each yearOptions as { value, label }}
<Select.Item {value} {label}>
{label}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</Calendar.Heading>
</Calendar.Header>
<Calendar.Months>
{#each months as month}
<Calendar.Grid>
<Calendar.GridHead>
<Calendar.GridRow class="flex">
{#each weekdays as weekday}
<Calendar.HeadCell>
{weekday.slice(0, 2)}
</Calendar.HeadCell>
{/each}
</Calendar.GridRow>
</Calendar.GridHead>
<Calendar.GridBody>
{#each month.weeks as weekDates}
<Calendar.GridRow class="mt-2 w-full">
{#each weekDates as date}
<Calendar.Cell {date}>
<Calendar.Day {date} month={month.value} />
</Calendar.Cell>
{#snippet children({ months, weekdays })}
<Calendar.Header>
<Calendar.PrevButton />
<Calendar.Heading />
<Calendar.NextButton />
</Calendar.Header>
<Calendar.Months>
{#each months as month (month)}
<Calendar.Grid>
<Calendar.GridHead>
<Calendar.GridRow class="flex">
{#each weekdays as weekday (weekday)}
<Calendar.HeadCell>
{weekday.slice(0, 2)}
</Calendar.HeadCell>
{/each}
</Calendar.GridRow>
{/each}
</Calendar.GridBody>
</Calendar.Grid>
{/each}
</Calendar.Months>
</Calendar.GridHead>
<Calendar.GridBody>
{#each month.weeks as weekDates (weekDates)}
<Calendar.GridRow class="mt-2 w-full">
{#each weekDates as date (date)}
<Calendar.Cell {date} month={month.value}>
<Calendar.Day />
</Calendar.Cell>
{/each}
</Calendar.GridRow>
{/each}
</Calendar.GridBody>
</Calendar.Grid>
{/each}
</Calendar.Months>
{/snippet}
</CalendarPrimitive.Root>

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
bind:this={ref}
data-slot="card-action"
class={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,13 +1,15 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div class={cn('bg-muted/20 p-6 pt-5 peer-[.card-header]:border-t', className)} {...$$restProps}>
<slot />
<div bind:this={ref} data-slot="card-content" class={cn('px-6', className)} {...restProps}>
{@render children?.()}
</div>

View File

@@ -1,13 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLParagraphElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();
</script>
<p class={cn('text-muted-foreground mt-1 text-sm', className)} {...$$restProps}>
<slot />
<p
bind:this={ref}
data-slot="card-description"
class={cn('text-muted-foreground text-sm', className)}
{...restProps}
>
{@render children?.()}
</p>

View File

@@ -1,13 +1,20 @@
<script lang="ts">
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div class={cn('flex items-center p-6 pt-0', className)} {...$$restProps}>
<slot />
<div
bind:this={ref}
data-slot="card-footer"
class={cn('flex items-center px-6 [.border-t]:pt-6', className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,13 +1,23 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div class={cn('card-header peer flex flex-col space-y-1.5 p-6', className)} {...$$restProps}>
<slot />
<div
bind:this={ref}
data-slot="card-header"
class={cn(
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
className
)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,21 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { HeadingLevel } from './index.js';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLHeadingElement> & {
tag?: HeadingLevel;
};
let className: $$Props['class'] = undefined;
export let tag: $$Props['tag'] = 'h3';
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<svelte:element
this={tag}
class={cn('flex items-center gap-2 text-xl leading-none font-semibold tracking-tight', className)}
{...$$restProps}
<div
bind:this={ref}
data-slot="card-title"
class={cn('flex flex-row items-center gap-2 text-xl leading-none font-semibold', className)}
{...restProps}
>
<slot />
</svelte:element>
{@render children?.()}
</div>

View File

@@ -1,16 +1,23 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
class={cn('bg-card text-card-foreground overflow-hidden rounded-lg border shadow-sm', className)}
{...$$restProps}
bind:this={ref}
data-slot="card"
class={cn(
'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
className
)}
{...restProps}
>
<slot />
{@render children?.()}
</div>

View File

@@ -4,6 +4,7 @@ import Description from './card-description.svelte';
import Footer from './card-footer.svelte';
import Header from './card-header.svelte';
import Title from './card-title.svelte';
import Action from './card-action.svelte';
export {
Root,
@@ -12,13 +13,13 @@ export {
Footer,
Header,
Title,
Action,
//
Root as Card,
Content as CardContent,
Description as CardDescription,
Footer as CardFooter,
Header as CardHeader,
Title as CardTitle
Title as CardTitle,
Action as CardAction
};
export type HeadingLevel = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';

View File

@@ -1,35 +1,39 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from 'bits-ui';
import Check from 'lucide-svelte/icons/check';
import Minus from 'lucide-svelte/icons/minus';
import { cn } from '$lib/utils/style.js';
import CheckIcon from '@lucide/svelte/icons/check';
import MinusIcon from '@lucide/svelte/icons/minus';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
type $$Props = CheckboxPrimitive.Props;
type $$Events = CheckboxPrimitive.Events;
let className: $$Props['class'] = undefined;
export let checked: $$Props['checked'] = false;
export { className as class };
let {
ref = $bindable(null),
checked = $bindable(false),
indeterminate = $bindable(false),
class: className,
...restProps
}: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props();
</script>
<CheckboxPrimitive.Root
bind:ref
data-slot="checkbox"
class={cn(
'peer border-primary ring-offset-background focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground box-content h-4 w-4 shrink-0 rounded-sm border focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50',
'border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive peer size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
className
)}
bind:checked
{...$$restProps}
on:click
bind:indeterminate
{...restProps}
>
<CheckboxPrimitive.Indicator
class={cn('flex h-4 w-4 items-center justify-center text-current')}
let:isChecked
let:isIndeterminate
>
{#if isChecked}
<Check class="h-3.5 w-3.5" />
{:else if isIndeterminate}
<Minus class="h-3.5 w-3.5" />
{/if}
</CheckboxPrimitive.Indicator>
{#snippet children({ checked, indeterminate })}
<div
data-slot="checkbox-indicator"
class="flex items-center justify-center text-current transition-none"
>
{#if checked}
<CheckIcon class="size-3.5" />
{:else if indeterminate}
<MinusIcon class="size-3.5" />
{/if}
</div>
{/snippet}
</CheckboxPrimitive.Root>

View File

@@ -1,23 +1,40 @@
<script lang="ts">
import type { Dialog as DialogPrimitive } from 'bits-ui';
import type { Command as CommandPrimitive } from 'cmdk-sv';
import type { Command as CommandPrimitive, Dialog as DialogPrimitive } from 'bits-ui';
import type { Snippet } from 'svelte';
import Command from './command.svelte';
import * as Dialog from '$lib/components/ui/dialog/index.js';
import type { WithoutChildrenOrChild } from '$lib/utils/style.js';
type $$Props = DialogPrimitive.Props & CommandPrimitive.CommandProps;
export let open: $$Props['open'] = false;
export let value: $$Props['value'] = undefined;
let {
open = $bindable(false),
ref = $bindable(null),
value = $bindable(''),
title = 'Command Palette',
description = 'Search for a command to run',
portalProps,
children,
...restProps
}: WithoutChildrenOrChild<DialogPrimitive.RootProps> &
WithoutChildrenOrChild<CommandPrimitive.RootProps> & {
portalProps?: DialogPrimitive.PortalProps;
children: Snippet;
title?: string;
description?: string;
} = $props();
</script>
<Dialog.Root bind:open {...$$restProps}>
<Dialog.Content class="overflow-hidden p-0 shadow-lg">
<Dialog.Root bind:open {...restProps}>
<Dialog.Header class="sr-only">
<Dialog.Title>{title}</Dialog.Title>
<Dialog.Description>{description}</Dialog.Description>
</Dialog.Header>
<Dialog.Content class="overflow-hidden p-0" {portalProps}>
<Command
class="[&_[data-cmdk-group-heading]]:text-muted-foreground [&_[data-cmdk-group-heading]]:px-2 [&_[data-cmdk-group-heading]]:font-medium [&_[data-cmdk-group]]:px-2 [&_[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 [&_[data-cmdk-item]_svg]:h-5 [&_[data-cmdk-item]_svg]:w-5"
{...$$restProps}
class="**:data-[slot=command-input-wrapper]:h-12 [&_[data-command-group]]:px-2 [&_[data-command-group]:not([hidden])_~[data-command-group]]:pt-0 [&_[data-command-input-wrapper]_svg]:h-5 [&_[data-command-input-wrapper]_svg]:w-5 [&_[data-command-input]]:h-12 [&_[data-command-item]]:px-2 [&_[data-command-item]]:py-3 [&_[data-command-item]_svg]:h-5 [&_[data-command-item]_svg]:w-5"
{...restProps}
bind:value
>
<slot />
</Command>
bind:ref
{children}
/>
</Dialog.Content>
</Dialog.Root>

View File

@@ -1,13 +1,17 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'cmdk-sv';
import { Command as CommandPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ClassValue } from 'svelte/elements';
type $$Props = CommandPrimitive.EmptyProps;
let className: ClassValue | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CommandPrimitive.EmptyProps = $props();
</script>
<CommandPrimitive.Empty class={cn('py-6 text-center text-sm', className)} {...$$restProps}>
<slot />
</CommandPrimitive.Empty>
<CommandPrimitive.Empty
bind:ref
data-slot="command-empty"
class={cn('py-6 text-center text-sm', className)}
{...restProps}
/>

View File

@@ -1,19 +1,30 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'cmdk-sv';
import { Command as CommandPrimitive, useId } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ClassValue } from 'svelte/elements';
type $$Props = CommandPrimitive.GroupProps;
let className: ClassValue | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
heading,
value,
...restProps
}: CommandPrimitive.GroupProps & {
heading?: string;
} = $props();
</script>
<CommandPrimitive.Group
class={cn(
'text-foreground [&_[data-cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[data-cmdk-group-heading]]:px-2 [&_[data-cmdk-group-heading]]:py-1.5 [&_[data-cmdk-group-heading]]:text-xs [&_[data-cmdk-group-heading]]:font-medium',
className
)}
{...$$restProps}
bind:ref
data-slot="command-group"
class={cn('text-foreground overflow-hidden p-1', className)}
value={value ?? heading ?? `----${useId()}`}
{...restProps}
>
<slot />
{#if heading}
<CommandPrimitive.GroupHeading class="text-muted-foreground px-2 py-1.5 text-xs font-medium">
{heading}
</CommandPrimitive.GroupHeading>
{/if}
<CommandPrimitive.GroupItems {children} />
</CommandPrimitive.Group>

View File

@@ -1,24 +1,26 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'bits-ui';
import SearchIcon from '@lucide/svelte/icons/search';
import { cn } from '$lib/utils/style.js';
import { Command as CommandPrimitive } from 'cmdk-sv';
import Search from 'lucide-svelte/icons/search';
import type { ClassValue } from 'svelte/elements';
type $$Props = CommandPrimitive.InputProps;
let className: ClassValue | undefined | null = undefined;
export { className as class };
export let value: string = '';
let {
ref = $bindable(null),
class: className,
value = $bindable(''),
...restProps
}: CommandPrimitive.InputProps = $props();
</script>
<div class="flex items-center border-b px-2" data-cmdk-input-wrapper="">
<Search class="mr-2 h-4 w-4 shrink-0 opacity-50" />
<div class="flex h-9 items-center gap-2 border-b px-3" data-slot="command-input-wrapper">
<SearchIcon class="size-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
data-slot="command-input"
class={cn(
'placeholder:text-muted-foreground flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50',
'placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
className
)}
{...$$restProps}
bind:ref
{...restProps}
bind:value
/>
</div>

View File

@@ -1,25 +1,20 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'cmdk-sv';
import { Command as CommandPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ClassValue } from 'svelte/elements';
type $$Props = CommandPrimitive.ItemProps;
export let asChild = false;
let className: ClassValue | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CommandPrimitive.ItemProps = $props();
</script>
<CommandPrimitive.Item
{asChild}
bind:ref
data-slot="command-item"
class={cn(
'aria-selected:bg-accent aria-selected:text-accent-foreground relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
"aria-selected:bg-accent aria-selected:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...$$restProps}
let:action
let:attrs
>
<slot {action} {attrs} />
</CommandPrimitive.Item>
{...restProps}
/>

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
let {
ref = $bindable(null),
class: className,
...restProps
}: CommandPrimitive.LinkItemProps = $props();
</script>
<CommandPrimitive.LinkItem
bind:ref
data-slot="command-item"
class={cn(
"aria-selected:bg-accent aria-selected:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...restProps}
/>

View File

@@ -1,16 +1,17 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'cmdk-sv';
import { Command as CommandPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ClassValue } from 'svelte/elements';
type $$Props = CommandPrimitive.ListProps;
let className: ClassValue | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CommandPrimitive.ListProps = $props();
</script>
<CommandPrimitive.List
class={cn('max-h-[300px] overflow-x-hidden overflow-y-auto', className)}
{...$$restProps}
>
<slot />
</CommandPrimitive.List>
bind:ref
data-slot="command-list"
class={cn('max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto', className)}
{...restProps}
/>

View File

@@ -1,11 +1,17 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'cmdk-sv';
import { Command as CommandPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ClassValue } from 'svelte/elements';
type $$Props = CommandPrimitive.SeparatorProps;
let className: ClassValue | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: CommandPrimitive.SeparatorProps = $props();
</script>
<CommandPrimitive.Separator class={cn('bg-border -mx-1 h-px', className)} {...$$restProps} />
<CommandPrimitive.Separator
bind:ref
data-slot="command-separator"
class={cn('bg-border -mx-1 h-px', className)}
{...restProps}
/>

View File

@@ -1,16 +1,20 @@
<script lang="ts">
import type { ClassValue, HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: ClassValue | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
</script>
<span
bind:this={ref}
data-slot="command-shortcut"
class={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
{...$$restProps}
{...restProps}
>
<slot />
{@render children?.()}
</span>

View File

@@ -1,23 +1,22 @@
<script lang="ts">
import { Command as CommandPrimitive } from 'cmdk-sv';
import { Command as CommandPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ClassValue } from 'svelte/elements';
type $$Props = CommandPrimitive.CommandProps;
export let value: $$Props['value'] = undefined;
let className: ClassValue | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
value = $bindable(''),
class: className,
...restProps
}: CommandPrimitive.RootProps = $props();
</script>
<CommandPrimitive.Root
bind:value
bind:ref
data-slot="command"
class={cn(
'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md',
className
)}
bind:value
{...$$restProps}
>
<slot />
</CommandPrimitive.Root>
{...restProps}
/>

View File

@@ -1,4 +1,4 @@
import { Command as CommandPrimitive } from 'cmdk-sv';
import { Command as CommandPrimitive } from 'bits-ui';
import Root from './command.svelte';
import Dialog from './command-dialog.svelte';
@@ -9,6 +9,7 @@ import Input from './command-input.svelte';
import List from './command-list.svelte';
import Separator from './command-separator.svelte';
import Shortcut from './command-shortcut.svelte';
import LinkItem from './command-link-item.svelte';
const Loading = CommandPrimitive.Loading;
@@ -18,6 +19,7 @@ export {
Empty,
Group,
Item,
LinkItem,
Input,
List,
Separator,
@@ -29,6 +31,7 @@ export {
Empty as CommandEmpty,
Group as CommandGroup,
Item as CommandItem,
LinkItem as CommandLinkItem,
Input as CommandInput,
List as CommandList,
Separator as CommandSeparator,

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: DialogPrimitive.CloseProps = $props();
</script>
<DialogPrimitive.Close bind:ref data-slot="dialog-close" {...restProps} />

View File

@@ -1,41 +1,39 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
import X from 'lucide-svelte/icons/x';
import XIcon from '@lucide/svelte/icons/x';
import type { Snippet } from 'svelte';
import * as Dialog from './index.js';
import { cn, flyAndScale } from '$lib/utils/style.js';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
type $$Props = DialogPrimitive.ContentProps & {
closeButton?: boolean;
};
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = flyAndScale;
export let closeButton: $$Props['closeButton'] = true;
export let transitionConfig: $$Props['transitionConfig'] = {
duration: 200
};
export { className as class };
let {
ref = $bindable(null),
class: className,
portalProps,
children,
...restProps
}: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
portalProps?: DialogPrimitive.PortalProps;
children: Snippet;
} = $props();
</script>
<Dialog.Portal>
<Dialog.Portal {...portalProps}>
<Dialog.Overlay />
<DialogPrimitive.Content
{transition}
{transitionConfig}
bind:ref
data-slot="dialog-content"
class={cn(
'bg-background fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg sm:rounded-lg md:w-full',
'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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
className
)}
{...$$restProps}
{...restProps}
>
<slot />
{#if closeButton}
<DialogPrimitive.Close
class="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none"
>
<X class="h-4 w-4" />
<span class="sr-only">Close</span>
</DialogPrimitive.Close>
{/if}
{@render children?.()}
<DialogPrimitive.Close
class="ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
>
<XIcon />
<span class="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</Dialog.Portal>

View File

@@ -2,15 +2,16 @@
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = DialogPrimitive.DescriptionProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: DialogPrimitive.DescriptionProps = $props();
</script>
<DialogPrimitive.Description
bind:ref
data-slot="dialog-description"
class={cn('text-muted-foreground text-sm', className)}
{...$$restProps}
>
<slot />
</DialogPrimitive.Description>
{...restProps}
/>

View File

@@ -1,16 +1,20 @@
<script lang="ts">
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div
class={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
{...$$restProps}
bind:this={ref}
data-slot="dialog-footer"
class={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
{...restProps}
>
<slot />
{@render children?.()}
</div>

View File

@@ -1,13 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script>
<div class={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)} {...$$restProps}>
<slot />
<div
bind:this={ref}
data-slot="dialog-header"
class={cn('flex flex-col gap-2 text-center sm:text-left', className)}
{...restProps}
>
{@render children?.()}
</div>

View File

@@ -1,21 +1,20 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
import { fade } from 'svelte/transition';
import { cn } from '$lib/utils/style.js';
type $$Props = DialogPrimitive.OverlayProps;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = fade;
export let transitionConfig: $$Props['transitionConfig'] = {
duration: 150
};
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: DialogPrimitive.OverlayProps = $props();
</script>
<DialogPrimitive.Overlay
{transition}
{transitionConfig}
class={cn('bg-background/80 fixed inset-0 z-50 backdrop-blur-sm', className)}
{...$$restProps}
bind:ref
data-slot="dialog-overlay"
class={cn(
'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/50',
className
)}
{...restProps}
/>

View File

@@ -1,8 +1,14 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
interface Props {
children?: import('svelte').Snippet;
[key: string]: any;
}
let { children, ...rest }: Props = $props();
type $$Props = DialogPrimitive.PortalProps;
</script>
<DialogPrimitive.Portal {...$$restProps}>
<slot />
<DialogPrimitive.Portal {...rest}>
{@render children?.()}
</DialogPrimitive.Portal>

View File

@@ -2,15 +2,16 @@
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = DialogPrimitive.TitleProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: DialogPrimitive.TitleProps = $props();
</script>
<DialogPrimitive.Title
class={cn('text-lg leading-none font-semibold tracking-tight', className)}
{...$$restProps}
>
<slot />
</DialogPrimitive.Title>
bind:ref
data-slot="dialog-title"
class={cn('text-lg leading-none font-semibold', className)}
{...restProps}
/>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: DialogPrimitive.TriggerProps = $props();
</script>
<DialogPrimitive.Trigger bind:ref data-slot="dialog-trigger" {...restProps} />

View File

@@ -1,16 +1,16 @@
import { Dialog as DialogPrimitive } from 'bits-ui';
import Title from './dialog-title.svelte';
import Portal from './dialog-portal.svelte';
import Footer from './dialog-footer.svelte';
import Header from './dialog-header.svelte';
import Overlay from './dialog-overlay.svelte';
import Content from './dialog-content.svelte';
import Description from './dialog-description.svelte';
import Trigger from './dialog-trigger.svelte';
import Close from './dialog-close.svelte';
const Root = DialogPrimitive.Root;
const Trigger = DialogPrimitive.Trigger;
const Close = DialogPrimitive.Close;
const Portal = DialogPrimitive.Portal;
export {
Root,

View File

@@ -1,35 +1,41 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import Check from 'lucide-svelte/icons/check';
import { cn } from '$lib/utils/style.js';
import CheckIcon from '@lucide/svelte/icons/check';
import MinusIcon from '@lucide/svelte/icons/minus';
import { cn, type WithoutChildrenOrChild } from '$lib/utils/style.js';
import type { Snippet } from 'svelte';
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
let className: $$Props['class'] = undefined;
export let checked: $$Props['checked'] = undefined;
export { className as class };
let {
ref = $bindable(null),
checked = $bindable(false),
indeterminate = $bindable(false),
class: className,
children: childrenProp,
...restProps
}: WithoutChildrenOrChild<DropdownMenuPrimitive.CheckboxItemProps> & {
children?: Snippet;
} = $props();
</script>
<DropdownMenuPrimitive.CheckboxItem
bind:ref
bind:checked
bind:indeterminate
data-slot="dropdown-menu-checkbox-item"
class={cn(
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
{...restProps}
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.CheckboxIndicator>
<Check class="h-4 w-4" />
</DropdownMenuPrimitive.CheckboxIndicator>
</span>
<slot />
{#snippet children({ checked, indeterminate })}
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
{#if indeterminate}
<MinusIcon class="size-4" />
{:else}
<CheckIcon class={cn('size-4', !checked && 'text-transparent')} />
{/if}
</span>
{@render childrenProp?.()}
{/snippet}
</DropdownMenuPrimitive.CheckboxItem>

View File

@@ -1,27 +1,27 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn, flyAndScale } from '$lib/utils/style.js';
type $$Props = DropdownMenuPrimitive.ContentProps;
type $$Events = DropdownMenuPrimitive.ContentEvents;
let className: $$Props['class'] = undefined;
export let sideOffset: $$Props['sideOffset'] = 4;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = undefined;
export { className as class };
let {
ref = $bindable(null),
sideOffset = 4,
portalProps,
class: className,
...restProps
}: DropdownMenuPrimitive.ContentProps & {
portalProps?: DropdownMenuPrimitive.PortalProps;
} = $props();
</script>
<DropdownMenuPrimitive.Content
{transition}
{transitionConfig}
{sideOffset}
class={cn(
'bg-popover text-popover-foreground z-50 min-w-[8rem] rounded-md border p-1 shadow-md focus:outline-none',
className
)}
{...$$restProps}
on:keydown
>
<slot />
</DropdownMenuPrimitive.Content>
<DropdownMenuPrimitive.Portal {...portalProps}>
<DropdownMenuPrimitive.Content
bind:ref
data-slot="dropdown-menu-content"
{sideOffset}
class={cn(
'bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
className
)}
{...restProps}
/>
</DropdownMenuPrimitive.Portal>

View File

@@ -0,0 +1,22 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import type { ComponentProps } from 'svelte';
let {
ref = $bindable(null),
class: className,
inset,
...restProps
}: ComponentProps<typeof DropdownMenuPrimitive.GroupHeading> & {
inset?: boolean;
} = $props();
</script>
<DropdownMenuPrimitive.GroupHeading
bind:ref
data-slot="dropdown-menu-group-heading"
data-inset={inset}
class={cn('px-2 py-1.5 text-sm font-semibold data-[inset]:pl-8', className)}
{...restProps}
/>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.GroupProps = $props();
</script>
<DropdownMenuPrimitive.Group bind:ref data-slot="dropdown-menu-group" {...restProps} />

View File

@@ -1,31 +1,27 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
type $$Props = DropdownMenuPrimitive.ItemProps & {
let {
ref = $bindable(null),
class: className,
inset,
variant = 'default',
...restProps
}: DropdownMenuPrimitive.ItemProps & {
inset?: boolean;
};
type $$Events = DropdownMenuPrimitive.ItemEvents;
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
variant?: 'default' | 'destructive';
} = $props();
</script>
<DropdownMenuPrimitive.Item
bind:ref
data-slot="dropdown-menu-item"
data-inset={inset}
data-variant={variant}
class={cn(
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
inset && 'pl-8',
"data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 dark:data-[variant=destructive]:data-highlighted:bg-destructive/20 data-[variant=destructive]:data-highlighted:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<slot />
</DropdownMenuPrimitive.Item>
{...restProps}
/>

View File

@@ -1,19 +1,24 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = DropdownMenuPrimitive.LabelProps & {
let {
ref = $bindable(null),
class: className,
inset,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
inset?: boolean;
};
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
} = $props();
</script>
<DropdownMenuPrimitive.Label
class={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
{...$$restProps}
<div
bind:this={ref}
data-slot="dropdown-menu-label"
data-inset={inset}
class={cn('px-2 py-1.5 text-sm font-semibold data-[inset]:pl-8', className)}
{...restProps}
>
<slot />
</DropdownMenuPrimitive.Label>
{@render children?.()}
</div>

View File

@@ -1,11 +1,16 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
type $$Props = DropdownMenuPrimitive.RadioGroupProps;
export let value: $$Props['value'] = undefined;
let {
ref = $bindable(null),
value = $bindable(),
...restProps
}: DropdownMenuPrimitive.RadioGroupProps = $props();
</script>
<DropdownMenuPrimitive.RadioGroup {...$$restProps} bind:value>
<slot />
</DropdownMenuPrimitive.RadioGroup>
<DropdownMenuPrimitive.RadioGroup
bind:ref
bind:value
data-slot="dropdown-menu-radio-group"
{...restProps}
/>

View File

@@ -1,35 +1,31 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import Circle from 'lucide-svelte/icons/circle';
import { cn } from '$lib/utils/style.js';
import CircleIcon from '@lucide/svelte/icons/circle';
import { cn, type WithoutChild } from '$lib/utils/style.js';
type $$Props = DropdownMenuPrimitive.RadioItemProps;
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
let className: $$Props['class'] = undefined;
export let value: $$Props['value'];
export { className as class };
let {
ref = $bindable(null),
class: className,
children: childrenProp,
...restProps
}: WithoutChild<DropdownMenuPrimitive.RadioItemProps> = $props();
</script>
<DropdownMenuPrimitive.RadioItem
bind:ref
data-slot="dropdown-menu-radio-item"
class={cn(
'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{value}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
{...restProps}
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.RadioIndicator>
<Circle class="h-2 w-2 fill-current" />
</DropdownMenuPrimitive.RadioIndicator>
</span>
<slot />
{#snippet children({ checked })}
<span class="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
{#if checked}
<CircleIcon class="size-2 fill-current" />
{/if}
</span>
{@render childrenProp?.({ checked })}
{/snippet}
</DropdownMenuPrimitive.RadioItem>

View File

@@ -2,13 +2,16 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
type $$Props = DropdownMenuPrimitive.SeparatorProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: DropdownMenuPrimitive.SeparatorProps = $props();
</script>
<DropdownMenuPrimitive.Separator
class={cn('bg-muted -mx-1 my-1 h-px', className)}
{...$$restProps}
bind:ref
data-slot="dropdown-menu-separator"
class={cn('bg-border -mx-1 my-1 h-px', className)}
{...restProps}
/>

View File

@@ -1,13 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
</script>
<span class={cn('ml-auto text-xs tracking-widest opacity-60', className)} {...$$restProps}>
<slot />
<span
bind:this={ref}
data-slot="dropdown-menu-shortcut"
class={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
{...restProps}
>
{@render children?.()}
</span>

View File

@@ -1,30 +1,20 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn, flyAndScale } from '$lib/utils/style.js';
import { cn } from '$lib/utils/style.js';
type $$Props = DropdownMenuPrimitive.SubContentProps;
type $$Events = DropdownMenuPrimitive.SubContentEvents;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = {
x: -10,
y: 0
};
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: DropdownMenuPrimitive.SubContentProps = $props();
</script>
<DropdownMenuPrimitive.SubContent
{transition}
{transitionConfig}
bind:ref
data-slot="dropdown-menu-sub-content"
class={cn(
'bg-popover text-popover-foreground z-50 min-w-[8rem] rounded-md border p-1 shadow-lg focus:outline-none',
'bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
className
)}
{...$$restProps}
on:keydown
on:focusout
on:pointermove
>
<slot />
</DropdownMenuPrimitive.SubContent>
{...restProps}
/>

View File

@@ -1,32 +1,29 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import ChevronRight from 'lucide-svelte/icons/chevron-right';
import { cn } from '$lib/utils/style.js';
import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
let {
ref = $bindable(null),
class: className,
inset,
children,
...restProps
}: DropdownMenuPrimitive.SubTriggerProps & {
inset?: boolean;
};
type $$Events = DropdownMenuPrimitive.SubTriggerEvents;
let className: $$Props['class'] = undefined;
export let inset: $$Props['inset'] = undefined;
export { className as class };
} = $props();
</script>
<DropdownMenuPrimitive.SubTrigger
bind:ref
data-slot="dropdown-menu-sub-trigger"
data-inset={inset}
class={cn(
'data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none',
inset && 'pl-8',
"data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
{...restProps}
>
<slot />
<ChevronRight class="ml-auto h-4 w-4" />
{@render children?.()}
<ChevronRightIcon class="ml-auto size-4" />
</DropdownMenuPrimitive.SubTrigger>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.TriggerProps = $props();
</script>
<DropdownMenuPrimitive.Trigger bind:ref data-slot="dropdown-menu-trigger" {...restProps} />

View File

@@ -1,48 +1,49 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte';
import Group from './dropdown-menu-group.svelte';
import Item from './dropdown-menu-item.svelte';
import Label from './dropdown-menu-label.svelte';
import Content from './dropdown-menu-content.svelte';
import Shortcut from './dropdown-menu-shortcut.svelte';
import RadioGroup from './dropdown-menu-radio-group.svelte';
import RadioItem from './dropdown-menu-radio-item.svelte';
import Separator from './dropdown-menu-separator.svelte';
import RadioGroup from './dropdown-menu-radio-group.svelte';
import Shortcut from './dropdown-menu-shortcut.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
import SubContent from './dropdown-menu-sub-content.svelte';
import SubTrigger from './dropdown-menu-sub-trigger.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import GroupHeading from './dropdown-menu-group-heading.svelte';
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
const Trigger = DropdownMenuPrimitive.Trigger;
const Group = DropdownMenuPrimitive.Group;
export {
Sub,
Root,
Item,
Label,
Group,
Trigger,
Content,
Shortcut,
Separator,
RadioItem,
SubContent,
SubTrigger,
RadioGroup,
CheckboxItem,
//
Content,
Root as DropdownMenu,
Sub as DropdownMenuSub,
CheckboxItem as DropdownMenuCheckboxItem,
Content as DropdownMenuContent,
Group as DropdownMenuGroup,
Item as DropdownMenuItem,
Label as DropdownMenuLabel,
Group as DropdownMenuGroup,
Content as DropdownMenuContent,
Trigger as DropdownMenuTrigger,
Shortcut as DropdownMenuShortcut,
RadioGroup as DropdownMenuRadioGroup,
RadioItem as DropdownMenuRadioItem,
Separator as DropdownMenuSeparator,
RadioGroup as DropdownMenuRadioGroup,
Shortcut as DropdownMenuShortcut,
Sub as DropdownMenuSub,
SubContent as DropdownMenuSubContent,
SubTrigger as DropdownMenuSubTrigger,
CheckboxItem as DropdownMenuCheckboxItem
Trigger as DropdownMenuTrigger,
GroupHeading as DropdownMenuGroupHeading,
Group,
GroupHeading,
Item,
Label,
RadioGroup,
RadioItem,
Root,
Separator,
Shortcut,
Sub,
SubContent,
SubTrigger,
Trigger
};

View File

@@ -1,10 +1,7 @@
<script lang="ts">
import * as Button from '$lib/components/ui/button/index.js';
type $$Props = Button.Props;
type $$Events = Button.Events;
let { ref = $bindable(null), ...restProps }: Button.Props = $props();
</script>
<Button.Root type="submit" on:click on:keydown {...$$restProps}>
<slot />
</Button.Root>
<Button.Root bind:ref type="submit" {...restProps} />

View File

@@ -1,17 +1,17 @@
<script lang="ts">
import * as FormPrimitive from 'formsnap';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithoutChild } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLSpanElement> & { class?: string | null | undefined };
let className: string | undefined | null = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: WithoutChild<FormPrimitive.DescriptionProps> = $props();
</script>
<FormPrimitive.Description
bind:ref
data-slot="form-description"
class={cn('text-muted-foreground text-sm', className)}
{...$$restProps}
let:descriptionAttrs
>
<slot {descriptionAttrs} />
</FormPrimitive.Description>
{...restProps}
/>

View File

@@ -1,25 +1,29 @@
<script lang="ts" context="module">
import type { FormPathLeaves, SuperForm } from 'sveltekit-superforms';
<script lang="ts" module>
import type { FormPathLeaves as _FormPathLeaves } from 'sveltekit-superforms';
type T = Record<string, unknown>;
type U = FormPathLeaves<T>;
type U = _FormPathLeaves<T>;
</script>
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
import type { HTMLAttributes } from 'svelte/elements';
<script lang="ts" generics="T extends Record<string, unknown>, U extends _FormPathLeaves<T>">
import * as FormPrimitive from 'formsnap';
import { cn } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef, type WithoutChildren } from '$lib/utils/style.js';
type $$Props = FormPrimitive.ElementFieldProps<T, U> & HTMLAttributes<HTMLElement>;
export let form: SuperForm<T>;
export let name: U;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
form,
name,
children: childrenProp,
...restProps
}: WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> &
FormPrimitive.ElementFieldProps<T, U> = $props();
</script>
<FormPrimitive.ElementField {form} {name} let:constraints let:errors let:tainted let:value>
<div class={cn('space-y-2', className)}>
<slot {constraints} {errors} {tainted} {value} />
</div>
<FormPrimitive.ElementField {form} {name}>
{#snippet children({ constraints, errors, tainted, value })}
<div bind:this={ref} class={cn('space-y-2', className)} {...restProps}>
{@render childrenProp?.({ constraints, errors, tainted, value: value as T[U] })}
</div>
{/snippet}
</FormPrimitive.ElementField>

View File

@@ -1,26 +1,30 @@
<script lang="ts">
import * as FormPrimitive from 'formsnap';
import { cn } from '$lib/utils/style.js';
import { cn, type WithoutChild } from '$lib/utils/style.js';
type $$Props = FormPrimitive.FieldErrorsProps & {
let {
ref = $bindable(null),
class: className,
errorClasses,
children: childrenProp,
...restProps
}: WithoutChild<FormPrimitive.FieldErrorsProps> & {
errorClasses?: string | undefined | null;
};
let className: $$Props['class'] = undefined;
export { className as class };
export let errorClasses: $$Props['class'] = undefined;
} = $props();
</script>
<FormPrimitive.FieldErrors
bind:ref
class={cn('text-destructive text-sm font-medium', className)}
{...$$restProps}
let:errors
let:fieldErrorsAttrs
let:errorAttrs
{...restProps}
>
<slot {errors} {fieldErrorsAttrs} {errorAttrs}>
{#each errors as error}
<div {...errorAttrs} class={cn(errorClasses)}>{error}</div>
{/each}
</slot>
{#snippet children({ errors, errorProps })}
{#if childrenProp}
{@render childrenProp({ errors, errorProps })}
{:else}
{#each errors as error (error)}
<div {...errorProps} class={cn(errorClasses)}>{error}</div>
{/each}
{/if}
{/snippet}
</FormPrimitive.FieldErrors>

View File

@@ -1,25 +1,29 @@
<script lang="ts" context="module">
import type { FormPath, SuperForm } from 'sveltekit-superforms';
<script lang="ts" module>
import type { FormPath as _FormPath } from 'sveltekit-superforms';
type T = Record<string, unknown>;
type U = FormPath<T>;
type U = _FormPath<T>;
</script>
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
import type { HTMLAttributes } from 'svelte/elements';
<script lang="ts" generics="T extends Record<string, unknown>, U extends _FormPath<T>">
import * as FormPrimitive from 'formsnap';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef, type WithoutChildren } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
type $$Props = FormPrimitive.FieldProps<T, U> & HTMLAttributes<HTMLElement>;
export let form: SuperForm<T>;
export let name: U;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
form,
name,
children: childrenProp,
...restProps
}: FormPrimitive.FieldProps<T, U> &
WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> = $props();
</script>
<FormPrimitive.Field {form} {name} let:constraints let:errors let:tainted let:value>
<div class={cn('space-y-2', className)}>
<slot {constraints} {errors} {tainted} {value} />
</div>
<FormPrimitive.Field {form} {name}>
{#snippet children({ constraints, errors, tainted, value })}
<div bind:this={ref} data-slot="form-item" class={cn('space-y-2', className)} {...restProps}>
{@render childrenProp?.({ constraints, errors, tainted, value: value as T[U] })}
</div>
{/snippet}
</FormPrimitive.Field>

View File

@@ -1,30 +1,20 @@
<script lang="ts" context="module">
import type { FormPath, SuperForm } from 'sveltekit-superforms';
<script lang="ts" module>
import type { FormPath as _FormPath } from 'sveltekit-superforms';
type T = Record<string, unknown>;
type U = FormPath<T>;
type U = _FormPath<T>;
</script>
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
<script lang="ts" generics="T extends Record<string, unknown>, U extends _FormPath<T>">
import * as FormPrimitive from 'formsnap';
import { cn } from '$lib/utils/style.js';
import { cn, type WithoutChild } from '$lib/utils/style.js';
type $$Props = FormPrimitive.FieldsetProps<T, U>;
export let form: SuperForm<T>;
export let name: U;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
form,
name,
...restProps
}: WithoutChild<FormPrimitive.FieldsetProps<T, U>> = $props();
</script>
<FormPrimitive.Fieldset
{form}
{name}
let:constraints
let:errors
let:tainted
let:value
class={cn('space-y-2', className)}
>
<slot {constraints} {errors} {tainted} {value} />
</FormPrimitive.Fieldset>
<FormPrimitive.Fieldset bind:ref {form} {name} class={cn('space-y-2', className)} {...restProps} />

View File

@@ -1,17 +1,24 @@
<script lang="ts">
import type { Label as LabelPrimitive } from 'bits-ui';
import { getFormControl } from 'formsnap';
import { cn } from '$lib/utils/style.js';
import * as FormPrimitive from 'formsnap';
import { Label } from '$lib/components/ui/label/index.js';
import { cn, type WithoutChild } from '$lib/utils/style.js';
type $$Props = LabelPrimitive.Props;
let className: $$Props['class'] = undefined;
export { className as class };
const { labelAttrs } = getFormControl();
let {
ref = $bindable(null),
children,
class: className,
...restProps
}: WithoutChild<FormPrimitive.LabelProps> = $props();
</script>
<Label {...$labelAttrs} class={cn('data-[fs-error]:text-destructive', className)} {...$$restProps}>
<slot {labelAttrs} />
</Label>
<FormPrimitive.Label {...restProps} bind:ref>
{#snippet child({ props })}
<Label
{...props}
data-slot="form-label"
class={cn('data-[fs-error]:text-destructive', className)}
>
{@render children?.()}
</Label>
{/snippet}
</FormPrimitive.Label>

View File

@@ -1,17 +1,16 @@
<script lang="ts">
import * as FormPrimitive from 'formsnap';
import { cn } from '$lib/utils/style.js';
import { cn, type WithoutChild } from '$lib/utils/style.js';
type $$Props = FormPrimitive.LegendProps;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: WithoutChild<FormPrimitive.LegendProps> = $props();
</script>
<FormPrimitive.Legend
{...$$restProps}
bind:ref
class={cn('data-[fs-error]:text-destructive text-sm leading-none font-medium', className)}
let:legendAttrs
>
<slot {legendAttrs} />
</FormPrimitive.Legend>
{...restProps}
/>

View File

@@ -1,5 +1,4 @@
import Root from './input.svelte';
export type FormInputEvent<T extends Event = Event> = T & {
currentTarget: EventTarget & HTMLInputElement;
};

View File

@@ -1,42 +1,51 @@
<script lang="ts">
import type { HTMLInputAttributes } from 'svelte/elements';
import type { InputEvents } from './index.js';
import { cn } from '$lib/utils/style.js';
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLInputAttributes;
type $$Events = InputEvents;
type InputType = Exclude<HTMLInputTypeAttribute, 'file'>;
let className: $$Props['class'] = undefined;
export let value: $$Props['value'] = undefined;
export { className as class };
type Props = WithElementRef<
Omit<HTMLInputAttributes, 'type'> &
({ type: 'file'; files?: FileList } | { type?: InputType; files?: undefined })
>;
// Workaround for https://github.com/sveltejs/svelte/issues/9305
// Fixed in Svelte 5, but not backported to 4.x.
export let readonly: $$Props['readonly'] = undefined;
let {
ref = $bindable(null),
value = $bindable(),
type,
files = $bindable(),
class: className,
...restProps
}: Props = $props();
</script>
<input
class={cn(
'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',
className
)}
bind:value
{readonly}
on:blur
on:change
on:click
on:focus
on:focusin
on:focusout
on:keydown
on:keypress
on:keyup
on:mouseover
on:mouseenter
on:mouseleave
on:mousemove
on:paste
on:input
on:wheel|passive
{...$$restProps}
/>
{#if type === 'file'}
<input
bind:this={ref}
data-slot="input"
class={cn(
'selection:bg-primary dark:bg-input/30 selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-2 text-sm font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
className
)}
type="file"
bind:files
bind:value
{...restProps}
/>
{:else}
<input
bind:this={ref}
data-slot="input"
class={cn(
'border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
className
)}
{type}
bind:value
{...restProps}
/>
{/if}

View File

@@ -1,21 +1,20 @@
<script lang="ts">
import { Label as LabelPrimitive } from 'bits-ui';
import { cn } from '$lib/utils/style.js';
import { Label as LabelPrimitive } from 'bits-ui';
type $$Props = LabelPrimitive.Props;
type $$Events = LabelPrimitive.Events;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: LabelPrimitive.RootProps = $props();
</script>
<LabelPrimitive.Root
bind:ref
data-slot="label"
class={cn(
'mb-3 block text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
'mb-3 flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
className
)}
{...$$restProps}
on:mousedown
>
<slot />
</LabelPrimitive.Root>
{...restProps}
/>

View File

@@ -1,13 +1,20 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import { cn, type WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLUListElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLUListElement>> = $props();
</script>
<ul class={cn('flex flex-row items-center gap-1', className)} {...$$restProps}>
<slot />
<ul
bind:this={ref}
data-slot="pagination-content"
class={cn('flex flex-row items-center gap-1', className)}
{...restProps}
>
{@render children?.()}
</ul>

View File

@@ -1,19 +1,22 @@
<script lang="ts">
import Ellipsis from 'lucide-svelte/icons/ellipsis';
import EllipsisIcon from '@lucide/svelte/icons/ellipsis';
import { cn, type WithElementRef, type WithoutChildren } from '$lib/utils/style.js';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
...restProps
}: WithoutChildren<WithElementRef<HTMLAttributes<HTMLSpanElement>>> = $props();
</script>
<span
bind:this={ref}
aria-hidden="true"
class={cn('flex h-9 w-9 items-center justify-center', className)}
{...$$restProps}
data-slot="pagination-ellipsis"
class={cn('flex size-9 items-center justify-center', className)}
{...restProps}
>
<Ellipsis class="h-4 w-4" />
<EllipsisIcon class="size-4" />
<span class="sr-only">More pages</span>
</span>

View File

@@ -1,13 +1,14 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/style.js';
import type { HTMLLiAttributes } from 'svelte/elements';
import type { WithElementRef } from '$lib/utils/style.js';
type $$Props = HTMLAttributes<HTMLLIElement>;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
children,
...restProps
}: WithElementRef<HTMLLiAttributes> = $props();
</script>
<li class={cn('', className)} {...$$restProps}>
<slot />
<li bind:this={ref} data-slot="pagination-item" {...restProps}>
{@render children?.()}
</li>

View File

@@ -3,23 +3,30 @@
import { cn } from '$lib/utils/style.js';
import { type Props, buttonVariants } from '$lib/components/ui/button/index.js';
type $$Props = PaginationPrimitive.PageProps &
let {
ref = $bindable(null),
class: className,
size = 'icon',
isActive = false,
page,
children,
...restProps
}: PaginationPrimitive.PageProps &
Props & {
isActive: boolean;
};
type $$Events = PaginationPrimitive.PageEvents;
let className: $$Props['class'] = undefined;
export let page: $$Props['page'];
export let size: $$Props['size'] = 'sm';
export let isActive: $$Props['isActive'] = false;
export { className as class };
} = $props();
</script>
{#snippet Fallback()}
{page.value}
{/snippet}
<PaginationPrimitive.Page
bind:page
bind:ref
{page}
aria-current={isActive ? 'page' : undefined}
data-slot="pagination-link"
data-active={isActive}
class={cn(
buttonVariants({
variant: isActive ? 'outline' : 'ghost',
@@ -27,8 +34,6 @@
}),
className
)}
{...$$restProps}
on:click
>
<slot>{page.value}</slot>
</PaginationPrimitive.Page>
children={children || Fallback}
{...restProps}
/>

View File

@@ -1,27 +1,32 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
import { Pagination as PaginationPrimitive } from 'bits-ui';
import ChevronRight from 'lucide-svelte/icons/chevron-right';
import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
type $$Props = PaginationPrimitive.NextButtonProps;
type $$Events = PaginationPrimitive.NextButtonEvents;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: PaginationPrimitive.NextButtonProps = $props();
</script>
<PaginationPrimitive.NextButton asChild let:builder>
<Button
variant="ghost"
size="sm"
class={cn('gap-1 pr-2.5', className)}
builders={[builder]}
on:click
{...$$restProps}
>
<slot>
<ChevronRight class="h-4 w-4" />
</slot>
</Button>
</PaginationPrimitive.NextButton>
{#snippet Fallback()}
<ChevronRightIcon class="size-4" />
{/snippet}
<PaginationPrimitive.NextButton
bind:ref
aria-label="Go to next page"
class={cn(
buttonVariants({
size: 'default',
variant: 'ghost',
class: 'gap-1 px-2.5 sm:pr-2.5'
}),
className
)}
children={children || Fallback}
{...restProps}
/>

View File

@@ -1,27 +1,32 @@
<script lang="ts">
import { Pagination as PaginationPrimitive } from 'bits-ui';
import ChevronLeft from 'lucide-svelte/icons/chevron-left';
import { Button } from '$lib/components/ui/button/index.js';
import ChevronLeftIcon from '@lucide/svelte/icons/chevron-left';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils/style.js';
type $$Props = PaginationPrimitive.PrevButtonProps;
type $$Events = PaginationPrimitive.PrevButtonEvents;
let className: $$Props['class'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: PaginationPrimitive.PrevButtonProps = $props();
</script>
<PaginationPrimitive.PrevButton asChild let:builder>
<Button
variant="ghost"
size="sm"
class={cn('gap-1 pl-2.5', className)}
builders={[builder]}
on:click
{...$$restProps}
>
<slot>
<ChevronLeft class="h-4 w-4" />
</slot>
</Button>
</PaginationPrimitive.PrevButton>
{#snippet Fallback()}
<ChevronLeftIcon class="size-4" />
{/snippet}
<PaginationPrimitive.PrevButton
bind:ref
aria-label="Go to previous page"
class={cn(
buttonVariants({
size: 'default',
variant: 'ghost',
class: 'gap-1 px-2.5 sm:pl-2.5'
}),
className
)}
children={children || Fallback}
{...restProps}
/>

View File

@@ -3,31 +3,26 @@
import { cn } from '$lib/utils/style.js';
type $$Props = PaginationPrimitive.Props;
type $$Events = PaginationPrimitive.Events;
let className: $$Props['class'] = undefined;
export let count: $$Props['count'] = 0;
export let perPage: $$Props['perPage'] = 10;
export let page: $$Props['page'] = 1;
export let siblingCount: $$Props['siblingCount'] = 1;
export { className as class };
$: currentPage = page;
let {
ref = $bindable(null),
class: className,
count = 0,
perPage = 10,
page = $bindable(1),
siblingCount = 1,
...restProps
}: PaginationPrimitive.RootProps = $props();
</script>
<PaginationPrimitive.Root
bind:ref
bind:page
role="navigation"
aria-label="pagination"
data-slot="pagination"
class={cn('mx-auto flex w-full justify-center', className)}
{count}
{perPage}
{siblingCount}
bind:page
let:builder
let:pages
let:range
asChild
{...$$restProps}
>
<nav {...builder} class={cn('mx-auto flex w-full flex-col items-center', className)}>
<slot {pages} {range} {currentPage} />
</nav>
</PaginationPrimitive.Root>
{...restProps}
/>

View File

@@ -1,7 +1,7 @@
import { Popover as PopoverPrimitive } from 'bits-ui';
import Content from './popover-content.svelte';
import Trigger from './popover-trigger.svelte';
const Root = PopoverPrimitive.Root;
const Trigger = PopoverPrimitive.Trigger;
const Close = PopoverPrimitive.Close;
export {

View File

@@ -1,22 +1,32 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { Popover as PopoverPrimitive } from 'bits-ui';
import { cn, flyAndScale } from '$lib/utils/style.js';
type $$Props = PopoverPrimitive.ContentProps;
let className: $$Props['class'] = undefined;
export let transition: $$Props['transition'] = flyAndScale;
export let transitionConfig: $$Props['transitionConfig'] = undefined;
export { className as class };
let {
ref = $bindable(null),
class: className,
sideOffset = 4,
align = 'center',
sameWidth = false,
portalProps,
...restProps
}: PopoverPrimitive.ContentProps & {
portalProps?: PopoverPrimitive.PortalProps;
sameWidth?: boolean;
} = $props();
</script>
<PopoverPrimitive.Content
{transition}
{transitionConfig}
class={cn(
'bg-popover text-popover-foreground z-50 w-72 rounded-md border p-4 shadow-md outline-none',
className
)}
{...$$restProps}
>
<slot />
</PopoverPrimitive.Content>
<PopoverPrimitive.Portal {...portalProps}>
<PopoverPrimitive.Content
bind:ref
data-slot="popover-content"
{sideOffset}
{align}
class={cn(
'bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--bits-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden',
sameWidth && 'w-[var(--bits-popover-anchor-width)]',
className
)}
{...restProps}
/>
</PopoverPrimitive.Portal>

View File

@@ -0,0 +1,17 @@
<script lang="ts">
import { cn } from '$lib/utils/style.js';
import { Popover as PopoverPrimitive } from 'bits-ui';
let {
ref = $bindable(null),
class: className,
...restProps
}: PopoverPrimitive.TriggerProps = $props();
</script>
<PopoverPrimitive.Trigger
bind:ref
data-slot="popover-trigger"
class={cn('', className)}
{...restProps}
/>

Some files were not shown because too many files have changed in this diff Show More