This repository has no description
1<script module lang="ts">
2 import { tv, type VariantProps } from "tailwind-variants";
3
4 export const dropdownItem = tv({
5 base: "w-full justify-start rounded-none p-2 text-left focus-visible:-outline-offset-2",
6 variants: {
7 danger: {
8 false: "",
9 true: "text-foreground-danger hover:bg-background-danger-subtle"
10 }
11 },
12 defaultVariants: {
13 danger: false
14 }
15 });
16
17 export type DropdownItemVariants = VariantProps<typeof dropdownItem>;
18</script>
19
20<script lang="ts">
21 import { resolve } from "$app/paths";
22 import type { Component, Snippet } from "svelte";
23 import type { SvelteHTMLElements } from "svelte/elements";
24 import { getContext } from "svelte";
25 import Button from "./Button.svelte";
26
27 interface Props {
28 href?: string;
29 icon?: Component<SvelteHTMLElements["svg"]>;
30 danger?: DropdownItemVariants["danger"];
31 onclick?: (event: MouseEvent) => void;
32 /** Button hugs its children, so a two-column row needs `[&>span]:w-full` here. */
33 class?: string;
34 children: Snippet;
35 }
36
37 let { href, icon, danger = false, onclick, class: className, children }: Props = $props();
38 const classes = $derived(dropdownItem({ danger, class: className }));
39
40 const closeDropdown = getContext<(() => void) | undefined>("dropdown-close");
41 const registerItem = getContext<((el: HTMLElement) => () => void) | undefined>(
42 "dropdown-register"
43 );
44
45 let el = $state<HTMLAnchorElement | HTMLButtonElement>();
46
47 $effect(() => {
48 if (!el || !registerItem) return;
49 return registerItem(el);
50 });
51
52 const handleClick = (event: MouseEvent) => {
53 closeDropdown?.();
54 onclick?.(event);
55 };
56</script>
57
58<Button
59 bind:ref={el}
60 variant="ghost"
61 href={href ? resolve(href as "/") : undefined}
62 class={classes}
63 {icon}
64 role="menuitem"
65 tabindex={-1}
66 onclick={handleClick}
67>
68 {@render children()}
69</Button>