summaryrefslogtreecommitdiff
path: root/frontend/src/lib/components/ui/select
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/lib/components/ui/select')
-rw-r--r--frontend/src/lib/components/ui/select/index.ts40
-rw-r--r--frontend/src/lib/components/ui/select/select-content.svelte45
-rw-r--r--frontend/src/lib/components/ui/select/select-group-heading.svelte21
-rw-r--r--frontend/src/lib/components/ui/select/select-group.svelte17
-rw-r--r--frontend/src/lib/components/ui/select/select-item.svelte42
-rw-r--r--frontend/src/lib/components/ui/select/select-label.svelte20
-rw-r--r--frontend/src/lib/components/ui/select/select-portal.svelte7
-rw-r--r--frontend/src/lib/components/ui/select/select-scroll-down-button.svelte20
-rw-r--r--frontend/src/lib/components/ui/select/select-scroll-up-button.svelte20
-rw-r--r--frontend/src/lib/components/ui/select/select-separator.svelte18
-rw-r--r--frontend/src/lib/components/ui/select/select-trigger.svelte29
-rw-r--r--frontend/src/lib/components/ui/select/select-value.svelte7
-rw-r--r--frontend/src/lib/components/ui/select/select.svelte11
13 files changed, 297 insertions, 0 deletions
diff --git a/frontend/src/lib/components/ui/select/index.ts b/frontend/src/lib/components/ui/select/index.ts
new file mode 100644
index 0000000..4960d45
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/index.ts
@@ -0,0 +1,40 @@
+import Content from "./select-content.svelte";
+import GroupHeading from "./select-group-heading.svelte";
+import Group from "./select-group.svelte";
+import Item from "./select-item.svelte";
+import Label from "./select-label.svelte";
+import Portal from "./select-portal.svelte";
+import ScrollDownButton from "./select-scroll-down-button.svelte";
+import ScrollUpButton from "./select-scroll-up-button.svelte";
+import Separator from "./select-separator.svelte";
+import Trigger from "./select-trigger.svelte";
+import Value from "./select-value.svelte";
+import Root from "./select.svelte";
+
+export {
+ Root,
+ Group,
+ Label,
+ Item,
+ Content,
+ Trigger,
+ Separator,
+ ScrollDownButton,
+ ScrollUpButton,
+ GroupHeading,
+ Portal,
+ Value,
+ //
+ Root as Select,
+ Group as SelectGroup,
+ Label as SelectLabel,
+ Item as SelectItem,
+ Content as SelectContent,
+ Trigger as SelectTrigger,
+ Separator as SelectSeparator,
+ ScrollDownButton as SelectScrollDownButton,
+ ScrollUpButton as SelectScrollUpButton,
+ GroupHeading as SelectGroupHeading,
+ Portal as SelectPortal,
+ Value as SelectValue,
+};
diff --git a/frontend/src/lib/components/ui/select/select-content.svelte b/frontend/src/lib/components/ui/select/select-content.svelte
new file mode 100644
index 0000000..3ec8408
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-content.svelte
@@ -0,0 +1,45 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+ import { cn, type WithoutChild } from "$lib/utils.js";
+ import type { WithoutChildrenOrChild } from "$lib/utils.js";
+ import SelectPortal from "./select-portal.svelte";
+ import SelectScrollDownButton from "./select-scroll-down-button.svelte";
+ import SelectScrollUpButton from "./select-scroll-up-button.svelte";
+ import type { ComponentProps } from "svelte";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ sideOffset = 4,
+ portalProps,
+ children,
+ preventScroll = true,
+ ...restProps
+ }: WithoutChild<SelectPrimitive.ContentProps> & {
+ portalProps?: WithoutChildrenOrChild<ComponentProps<typeof SelectPortal>>;
+ } = $props();
+</script>
+
+<SelectPortal {...portalProps}>
+ <SelectPrimitive.Content
+ bind:ref
+ {sideOffset}
+ {preventScroll}
+ data-slot="select-content"
+ class={cn(
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 ring-foreground/10 min-w-32 rounded-lg shadow-md ring-1 duration-100 relative z-50 max-h-(--bits-select-content-available-height) origin-(--bits-select-content-transform-origin) overflow-x-hidden overflow-y-auto",
+ className
+ )}
+ {...restProps}
+ >
+ <SelectScrollUpButton />
+ <SelectPrimitive.Viewport
+ class={cn(
+ "h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1"
+ )}
+ >
+ {@render children?.()}
+ </SelectPrimitive.Viewport>
+ <SelectScrollDownButton />
+ </SelectPrimitive.Content>
+</SelectPortal>
diff --git a/frontend/src/lib/components/ui/select/select-group-heading.svelte b/frontend/src/lib/components/ui/select/select-group-heading.svelte
new file mode 100644
index 0000000..1fab5f0
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-group-heading.svelte
@@ -0,0 +1,21 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+ import { cn } from "$lib/utils.js";
+ import type { ComponentProps } from "svelte";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ children,
+ ...restProps
+ }: ComponentProps<typeof SelectPrimitive.GroupHeading> = $props();
+</script>
+
+<SelectPrimitive.GroupHeading
+ bind:ref
+ data-slot="select-group-heading"
+ class={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
+ {...restProps}
+>
+ {@render children?.()}
+</SelectPrimitive.GroupHeading>
diff --git a/frontend/src/lib/components/ui/select/select-group.svelte b/frontend/src/lib/components/ui/select/select-group.svelte
new file mode 100644
index 0000000..f666cb2
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-group.svelte
@@ -0,0 +1,17 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+ import { cn } from "$lib/utils.js";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ ...restProps
+ }: SelectPrimitive.GroupProps = $props();
+</script>
+
+<SelectPrimitive.Group
+ bind:ref
+ data-slot="select-group"
+ class={cn("scroll-my-1 p-1", className)}
+ {...restProps}
+/>
diff --git a/frontend/src/lib/components/ui/select/select-item.svelte b/frontend/src/lib/components/ui/select/select-item.svelte
new file mode 100644
index 0000000..446dfdc
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-item.svelte
@@ -0,0 +1,42 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+ import CheckIcon from '@lucide/svelte/icons/check';
+ import { cn, type WithoutChild } from "$lib/utils.js";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ value,
+ label,
+ children: childrenProp,
+ ...restProps
+ }: WithoutChild<SelectPrimitive.ItemProps> = $props();
+</script>
+
+<SelectPrimitive.Item
+ bind:ref
+ {value}
+ {label}
+ data-slot="select-item"
+ class={cn(
+ "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground min-h-7 gap-2 rounded-md px-2 py-1 text-xs/relaxed [&_svg:not([class*='size-'])]:size-3.5 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
+ "data-highlighted:bg-accent data-highlighted:text-accent-foreground",
+ className
+ )}
+ {...restProps}
+>
+ {#snippet children({ selected, highlighted })}
+ <span class="pointer-events-none absolute right-2 flex items-center justify-center">
+ {#if selected}
+ <CheckIcon class="pointer-events-none" />
+ {/if}
+ </span>
+ <span class="flex flex-1 gap-2 shrink-0 whitespace-nowrap">
+ {#if childrenProp}
+ {@render childrenProp({ selected, highlighted })}
+ {:else}
+ {label || value}
+ {/if}
+ </span>
+ {/snippet}
+</SelectPrimitive.Item>
diff --git a/frontend/src/lib/components/ui/select/select-label.svelte b/frontend/src/lib/components/ui/select/select-label.svelte
new file mode 100644
index 0000000..4696025
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-label.svelte
@@ -0,0 +1,20 @@
+<script lang="ts">
+ import { cn, type WithElementRef } from "$lib/utils.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="select-label"
+ class={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
+ {...restProps}
+>
+ {@render children?.()}
+</div>
diff --git a/frontend/src/lib/components/ui/select/select-portal.svelte b/frontend/src/lib/components/ui/select/select-portal.svelte
new file mode 100644
index 0000000..424bcdd
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-portal.svelte
@@ -0,0 +1,7 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+
+ let { ...restProps }: SelectPrimitive.PortalProps = $props();
+</script>
+
+<SelectPrimitive.Portal {...restProps} />
diff --git a/frontend/src/lib/components/ui/select/select-scroll-down-button.svelte b/frontend/src/lib/components/ui/select/select-scroll-down-button.svelte
new file mode 100644
index 0000000..7bc111e
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-scroll-down-button.svelte
@@ -0,0 +1,20 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+ import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
+ import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ ...restProps
+ }: WithoutChildrenOrChild<SelectPrimitive.ScrollDownButtonProps> = $props();
+</script>
+
+<SelectPrimitive.ScrollDownButton
+ bind:ref
+ data-slot="select-scroll-down-button"
+ class={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-3.5", className)}
+ {...restProps}
+>
+ <ChevronDownIcon />
+</SelectPrimitive.ScrollDownButton>
diff --git a/frontend/src/lib/components/ui/select/select-scroll-up-button.svelte b/frontend/src/lib/components/ui/select/select-scroll-up-button.svelte
new file mode 100644
index 0000000..6c066ff
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-scroll-up-button.svelte
@@ -0,0 +1,20 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+ import ChevronUpIcon from '@lucide/svelte/icons/chevron-up';
+ import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ ...restProps
+ }: WithoutChildrenOrChild<SelectPrimitive.ScrollUpButtonProps> = $props();
+</script>
+
+<SelectPrimitive.ScrollUpButton
+ bind:ref
+ data-slot="select-scroll-up-button"
+ class={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-3.5", className)}
+ {...restProps}
+>
+ <ChevronUpIcon />
+</SelectPrimitive.ScrollUpButton>
diff --git a/frontend/src/lib/components/ui/select/select-separator.svelte b/frontend/src/lib/components/ui/select/select-separator.svelte
new file mode 100644
index 0000000..aac5ca3
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-separator.svelte
@@ -0,0 +1,18 @@
+<script lang="ts">
+ import { Separator } from "$lib/components/ui/separator/index.js";
+ import { cn } from "$lib/utils.js";
+ import type { Separator as SeparatorPrimitive } from "bits-ui";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ ...restProps
+ }: SeparatorPrimitive.RootProps = $props();
+</script>
+
+<Separator
+ bind:ref
+ data-slot="select-separator"
+ class={cn("bg-border/50 -mx-1 my-1 h-px pointer-events-none", className)}
+ {...restProps}
+/>
diff --git a/frontend/src/lib/components/ui/select/select-trigger.svelte b/frontend/src/lib/components/ui/select/select-trigger.svelte
new file mode 100644
index 0000000..3acff3b
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-trigger.svelte
@@ -0,0 +1,29 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+ import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
+ import { cn, type WithoutChild } from "$lib/utils.js";
+
+ let {
+ ref = $bindable(null),
+ class: className,
+ children,
+ size = "default",
+ ...restProps
+ }: WithoutChild<SelectPrimitive.TriggerProps> & {
+ size?: "sm" | "default";
+ } = $props();
+</script>
+
+<SelectPrimitive.Trigger
+ bind:ref
+ data-slot="select-trigger"
+ data-size={size}
+ class={cn(
+ "border-input data-placeholder:text-muted-foreground bg-input/20 dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-md border px-2 py-1.5 text-xs/relaxed transition-colors focus-visible:ring-2 aria-invalid:ring-2 data-[size=default]:h-7 data-[size=sm]:h-6 *:data-[slot=select-value]:flex *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-3.5 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
+ className
+ )}
+ {...restProps}
+>
+ {@render children?.()}
+ <ChevronDownIcon class="text-muted-foreground size-3.5 pointer-events-none" />
+</SelectPrimitive.Trigger>
diff --git a/frontend/src/lib/components/ui/select/select-value.svelte b/frontend/src/lib/components/ui/select/select-value.svelte
new file mode 100644
index 0000000..ff34b0e
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select-value.svelte
@@ -0,0 +1,7 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+
+ let { ref = $bindable(null), ...restProps }: SelectPrimitive.ValueProps = $props();
+</script>
+
+<SelectPrimitive.Value bind:ref data-slot="select-value" {...restProps} />
diff --git a/frontend/src/lib/components/ui/select/select.svelte b/frontend/src/lib/components/ui/select/select.svelte
new file mode 100644
index 0000000..05eb663
--- /dev/null
+++ b/frontend/src/lib/components/ui/select/select.svelte
@@ -0,0 +1,11 @@
+<script lang="ts">
+ import { Select as SelectPrimitive } from "bits-ui";
+
+ let {
+ open = $bindable(false),
+ value = $bindable(),
+ ...restProps
+ }: SelectPrimitive.RootProps = $props();
+</script>
+
+<SelectPrimitive.Root bind:open bind:value={value as never} {...restProps} />