Add shadcn UI

This commit is contained in:
Neshura 2023-12-06 21:00:46 +01:00
parent 8da05a33cb
commit 3fd683b6ee
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
32 changed files with 860 additions and 0 deletions

View file

@ -0,0 +1,19 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = AvatarPrimitive.FallbackProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Fallback
class={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className
)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Fallback>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
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 };
</script>
<AvatarPrimitive.Image
{src}
{alt}
class={cn("aspect-square h-full w-full", className)}
{...$$restProps}
/>

View file

@ -0,0 +1,21 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = AvatarPrimitive.Props;
let className: $$Props["class"] = undefined;
export let delayMs: $$Props["delayMs"] = undefined;
export { className as class };
</script>
<AvatarPrimitive.Root
{delayMs}
class={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className
)}
{...$$restProps}
>
<slot />
</AvatarPrimitive.Root>

View file

@ -0,0 +1,13 @@
import Root from "./avatar.svelte";
import Image from "./avatar-image.svelte";
import Fallback from "./avatar-fallback.svelte";
export {
Root,
Image,
Fallback,
//
Root as Avatar,
Image as AvatarImage,
Fallback as AvatarFallback
};

View file

@ -0,0 +1,25 @@
<script lang="ts">
import { Button as ButtonPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { buttonVariants, type Props, type Events } from ".";
type $$Props = Props;
type $$Events = Events;
let className: $$Props["class"] = undefined;
export let variant: $$Props["variant"] = "default";
export let size: $$Props["size"] = "default";
export let builders: $$Props["builders"] = [];
export { className as class };
</script>
<ButtonPrimitive.Root
{builders}
class={cn(buttonVariants({ variant, size, className }))}
type="button"
{...$$restProps}
on:click
on:keydown
>
<slot />
</ButtonPrimitive.Root>

View file

@ -0,0 +1,52 @@
import type { Button as ButtonPrimitive } from "bits-ui";
import { tv, type VariantProps } from "tailwind-variants";
import Root from "./button.svelte";
const buttonVariants = tv({
base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline"
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9"
}
},
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;
};
type Events = ButtonPrimitive.Events;
export {
Root,
type Props,
type Events,
//
Root as Button,
type Props as ButtonProps,
type Events as ButtonEvents,
buttonVariants
};

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { Check } from "radix-icons-svelte";
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
let className: $$Props["class"] = undefined;
export let checked: $$Props["checked"] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.CheckboxItem
bind:checked
class={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<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 />
</DropdownMenuPrimitive.CheckboxItem>

View file

@ -0,0 +1,26 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn, flyAndScale } from "$lib/utils";
type $$Props = DropdownMenuPrimitive.ContentProps;
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 };
</script>
<DropdownMenuPrimitive.Content
{transition}
{transitionConfig}
{sideOffset}
class={cn(
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
className
)}
{...$$restProps}
on:keydown
>
<slot />
</DropdownMenuPrimitive.Content>

View file

@ -0,0 +1,31 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = DropdownMenuPrimitive.ItemProps & {
inset?: boolean;
};
type $$Events = DropdownMenuPrimitive.ItemEvents;
let className: $$Props["class"] = undefined;
export let inset: $$Props["inset"] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.Item
class={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className
)}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
{...$$restProps}
>
<slot />
</DropdownMenuPrimitive.Item>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = DropdownMenuPrimitive.LabelProps & {
inset?: boolean;
};
let className: $$Props["class"] = undefined;
export let inset: $$Props["inset"] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.Label
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
{...$$restProps}
>
<slot />
</DropdownMenuPrimitive.Label>

View file

@ -0,0 +1,11 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
type $$Props = DropdownMenuPrimitive.RadioGroupProps;
export let value: $$Props["value"] = undefined;
</script>
<DropdownMenuPrimitive.RadioGroup {...$$restProps} bind:value>
<slot />
</DropdownMenuPrimitive.RadioGroup>

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { DotFilled } from "radix-icons-svelte";
type $$Props = DropdownMenuPrimitive.RadioItemProps;
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
let className: $$Props["class"] = undefined;
export let value: DropdownMenuPrimitive.RadioItemProps["value"];
export { className as class };
</script>
<DropdownMenuPrimitive.RadioItem
class={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{value}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerdown
on:pointerleave
on:pointermove
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.RadioIndicator>
<DotFilled class="h-4 w-4 fill-current" />
</DropdownMenuPrimitive.RadioIndicator>
</span>
<slot />
</DropdownMenuPrimitive.RadioItem>

View file

@ -0,0 +1,14 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = DropdownMenuPrimitive.SeparatorProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.Separator
class={cn("-mx-1 my-1 h-px bg-muted", className)}
{...$$restProps}
/>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<span
class={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...$$restProps}
>
<slot />
</span>

View file

@ -0,0 +1,29 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn, flyAndScale } from "$lib/utils";
type $$Props = DropdownMenuPrimitive.SubContentProps;
let className: $$Props["class"] = undefined;
export let transition: $$Props["transition"] = flyAndScale;
export let transitionConfig: $$Props["transitionConfig"] = {
x: -10,
y: 0
};
export { className as class };
</script>
<DropdownMenuPrimitive.SubContent
{transition}
{transitionConfig}
class={cn(
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none",
className
)}
{...$$restProps}
on:keydown
on:focusout
on:pointermove
>
<slot />
</DropdownMenuPrimitive.SubContent>

View file

@ -0,0 +1,32 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { ChevronRight } from "radix-icons-svelte";
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
inset?: boolean;
};
type $$Events = DropdownMenuPrimitive.SubTriggerEvents;
let className: $$Props["class"] = undefined;
export let inset: $$Props["inset"] = undefined;
export { className as class };
</script>
<DropdownMenuPrimitive.SubTrigger
class={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent",
inset && "pl-8",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
>
<slot />
<ChevronRight class="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>

View file

@ -0,0 +1,48 @@
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
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 RadioItem from "./dropdown-menu-radio-item.svelte";
import Separator from "./dropdown-menu-separator.svelte";
import RadioGroup from "./dropdown-menu-radio-group.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";
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,
//
Root as DropdownMenu,
Sub as DropdownMenuSub,
Item as DropdownMenuItem,
Label as DropdownMenuLabel,
Group as DropdownMenuGroup,
Content as DropdownMenuContent,
Trigger as DropdownMenuTrigger,
Shortcut as DropdownMenuShortcut,
RadioItem as DropdownMenuRadioItem,
Separator as DropdownMenuSeparator,
RadioGroup as DropdownMenuRadioGroup,
SubContent as DropdownMenuSubContent,
SubTrigger as DropdownMenuSubTrigger,
CheckboxItem as DropdownMenuCheckboxItem
};

View file

@ -0,0 +1,52 @@
import { Menubar as MenubarPrimitive } from "bits-ui";
import Root from "./menubar.svelte";
import CheckboxItem from "./menubar-checkbox-item.svelte";
import Content from "./menubar-content.svelte";
import Item from "./menubar-item.svelte";
import Label from "./menubar-label.svelte";
import RadioItem from "./menubar-radio-item.svelte";
import Separator from "./menubar-separator.svelte";
import Shortcut from "./menubar-shortcut.svelte";
import SubContent from "./menubar-sub-content.svelte";
import SubTrigger from "./menubar-sub-trigger.svelte";
import Trigger from "./menubar-trigger.svelte";
const Menu = MenubarPrimitive.Menu;
const Group = MenubarPrimitive.Group;
const Sub = MenubarPrimitive.Sub;
const RadioGroup = MenubarPrimitive.RadioGroup;
export {
Root,
CheckboxItem,
Content,
Item,
Label,
RadioItem,
Separator,
Shortcut,
SubContent,
SubTrigger,
Trigger,
Menu,
Group,
Sub,
RadioGroup,
//
Root as Menubar,
CheckboxItem as MenubarCheckboxItem,
Content as MenubarContent,
Item as MenubarItem,
Label as MenubarLabel,
RadioItem as MenubarRadioItem,
Separator as MenubarSeparator,
Shortcut as MenubarShortcut,
SubContent as MenubarSubContent,
SubTrigger as MenubarSubTrigger,
Trigger as MenubarTrigger,
Menu as MenubarMenu,
Group as MenubarGroup,
Sub as MenubarSub,
RadioGroup as MenubarRadioGroup
};

View file

@ -0,0 +1,33 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { Check } from "radix-icons-svelte";
type $$Props = MenubarPrimitive.CheckboxItemProps;
let className: $$Props["class"] = undefined;
export { className as class };
export let checked: $$Props["checked"] = undefined;
</script>
<MenubarPrimitive.CheckboxItem
bind:checked
class={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
on:pointerdown
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenubarPrimitive.CheckboxIndicator>
<Check class="h-4 w-4" />
</MenubarPrimitive.CheckboxIndicator>
</span>
<slot />
</MenubarPrimitive.CheckboxItem>

View file

@ -0,0 +1,28 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn, flyAndScale } from "$lib/utils";
type $$Props = MenubarPrimitive.ContentProps;
let className: $$Props["class"] = undefined;
export let align: $$Props["align"] = "start";
export let alignOffset: $$Props["alignOffset"] = -4;
export let sideOffset: $$Props["sideOffset"] = 8;
export let transition: $$Props["transition"] = flyAndScale;
export let transitionConfig: $$Props["transitionConfig"] = undefined;
export { className as class };
</script>
<MenubarPrimitive.Content
{transition}
{transitionConfig}
{sideOffset}
{align}
{alignOffset}
class={cn(
"z-50 min-w-[12rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
className
)}
{...$$restProps}
>
<slot />
</MenubarPrimitive.Content>

View file

@ -0,0 +1,31 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = MenubarPrimitive.ItemProps & {
inset?: boolean;
};
type $$Events = MenubarPrimitive.ItemEvents;
let className: $$Props["class"] = undefined;
export let inset: $$Props["inset"] = undefined;
export { className as class };
</script>
<MenubarPrimitive.Item
class={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
on:pointerdown
>
<slot />
</MenubarPrimitive.Item>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = MenubarPrimitive.LabelProps & {
inset?: boolean;
};
let className: $$Props["class"] = undefined;
export let inset: $$Props["inset"] = undefined;
export { className as class };
</script>
<MenubarPrimitive.Label
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
{...$$restProps}
>
<slot />
</MenubarPrimitive.Label>

View file

@ -0,0 +1,34 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { DotFilled } from "radix-icons-svelte";
type $$Props = MenubarPrimitive.RadioItemProps;
type $$Events = MenubarPrimitive.RadioItemEvents;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"];
export { className as class };
</script>
<MenubarPrimitive.RadioItem
{value}
class={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
on:pointerdown
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenubarPrimitive.RadioIndicator>
<DotFilled class="h-4 w-4 fill-current" />
</MenubarPrimitive.RadioIndicator>
</span>
<slot />
</MenubarPrimitive.RadioItem>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = MenubarPrimitive.SeparatorProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<MenubarPrimitive.Separator
class={cn("-mx-1 my-1 h-px bg-muted", className)}
{...$$restProps}
/>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLSpanElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<span
class={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className
)}
{...$$restProps}
>
<slot />
</span>

View file

@ -0,0 +1,25 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn, flyAndScale } from "$lib/utils";
type $$Props = MenubarPrimitive.SubContentProps;
let className: $$Props["class"] = undefined;
export let transition: $$Props["transition"] = flyAndScale;
export let transitionConfig: $$Props["transitionConfig"] = {
x: -10,
y: 0
};
export { className as class };
</script>
<MenubarPrimitive.SubContent
{transition}
{transitionConfig}
class={cn(
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none",
className
)}
{...$$restProps}
>
<slot />
</MenubarPrimitive.SubContent>

View file

@ -0,0 +1,32 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { ChevronRight } from "radix-icons-svelte";
type $$Props = MenubarPrimitive.SubTriggerProps & {
inset?: boolean;
};
type $$Events = MenubarPrimitive.SubTriggerEvents;
let className: $$Props["class"] = undefined;
export let inset: $$Props["inset"] = undefined;
export { className as class };
</script>
<MenubarPrimitive.SubTrigger
class={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
inset && "pl-8",
className
)}
{...$$restProps}
on:click
on:keydown
on:focusin
on:focusout
on:pointerleave
on:pointermove
>
<slot />
<ChevronRight class="ml-auto h-4 w-4" />
</MenubarPrimitive.SubTrigger>

View file

@ -0,0 +1,23 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = MenubarPrimitive.TriggerProps;
type $$Events = MenubarPrimitive.TriggerEvents;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<MenubarPrimitive.Trigger
class={cn(
"flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
className
)}
{...$$restProps}
on:click
on:keydown
on:pointerenter
>
<slot />
</MenubarPrimitive.Trigger>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { Menubar as MenubarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = MenubarPrimitive.Props;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<MenubarPrimitive.Root
class={cn(
"flex h-9 items-center space-x-1 rounded-md border bg-background p-1 shadow-sm",
className
)}
>
<slot />
</MenubarPrimitive.Root>

View file

@ -0,0 +1,7 @@
import Root from "./separator.svelte";
export {
Root,
//
Root as Separator
};

View file

@ -0,0 +1,22 @@
<script lang="ts">
import { Separator as SeparatorPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = SeparatorPrimitive.Props;
let className: $$Props["class"] = undefined;
export let orientation: $$Props["orientation"] = "horizontal";
export let decorative: $$Props["decorative"] = undefined;
export { className as class };
</script>
<SeparatorPrimitive.Root
class={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className
)}
{orientation}
{decorative}
{...$$restProps}
/>

62
src/lib/utils.ts Normal file
View file

@ -0,0 +1,62 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { cubicOut } from "svelte/easing";
import type { TransitionConfig } from "svelte/transition";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
type FlyAndScaleParams = {
y?: number;
x?: number;
start?: number;
duration?: number;
};
export const flyAndScale = (
node: Element,
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
): TransitionConfig => {
const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform;
const scaleConversion = (
valueA: number,
scaleA: [number, number],
scaleB: [number, number]
) => {
const [minA, maxA] = scaleA;
const [minB, maxB] = scaleB;
const percentage = (valueA - minA) / (maxA - minA);
const valueB = percentage * (maxB - minB) + minB;
return valueB;
};
const styleToString = (
style: Record<string, number | string | undefined>
): string => {
return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined) return str;
return str + `${key}:${style[key]};`;
}, "");
};
return {
duration: params.duration ?? 200,
delay: 0,
css: (t) => {
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
return styleToString({
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
opacity: t
});
},
easing: cubicOut
};
};