50 lines
1.3 KiB
Svelte
50 lines
1.3 KiB
Svelte
<script lang="ts" module>
|
|
import type { Component } from "svelte";
|
|
|
|
// The dropdown and the context menu share this shape; only the primitive
|
|
// behind it differs.
|
|
export interface MenuKit {
|
|
// biome-ignore lint/suspicious/noExplicitAny: both bits-ui kits fit, neither shares a type
|
|
CheckboxItem: Component<any>;
|
|
// biome-ignore lint/suspicious/noExplicitAny: see above
|
|
Item: Component<any>;
|
|
// biome-ignore lint/suspicious/noExplicitAny: see above
|
|
Separator: Component<any>;
|
|
}
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import type { MenuAction } from "./actions.svelte";
|
|
|
|
let { kit, actions }: { kit: MenuKit; actions: MenuAction[] } = $props();
|
|
</script>
|
|
|
|
{#each actions as action, index (action.label)}
|
|
{#if action.gap && index > 0}
|
|
<kit.Separator />
|
|
{/if}
|
|
{#if action.checked === undefined}
|
|
<kit.Item
|
|
disabled={action.disabled}
|
|
onSelect={() => action.run()}
|
|
variant={action.danger ? "destructive" : "default"}
|
|
>
|
|
{#if action.icon}
|
|
<action.icon class="size-4" />
|
|
{/if}
|
|
{action.label}
|
|
</kit.Item>
|
|
{:else}
|
|
<kit.CheckboxItem
|
|
checked={action.checked}
|
|
disabled={action.disabled}
|
|
onCheckedChange={() => action.run()}
|
|
>
|
|
{#if action.icon}
|
|
<action.icon class="size-4" />
|
|
{/if}
|
|
{action.label}
|
|
</kit.CheckboxItem>
|
|
{/if}
|
|
{/each}
|