You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
88 lines
2.4 KiB
88 lines
2.4 KiB
<script lang="ts">
|
|
/**
|
|
* Eidos `<Command.Dialog>` — modal palette built on top of the eidos
|
|
* `<Dialog>` wrapper (so panel chrome + overlay + sizing stay
|
|
* consistent with the rest of the system). Mirrors soma's
|
|
* CommandDialog API but routes through the eidos layer.
|
|
*
|
|
* <Command.Dialog bind:open shortcut="mod+k">
|
|
* <Command.Input placeholder="Search…" />
|
|
* <Command.List>…</Command.List>
|
|
* </Command.Dialog>
|
|
*
|
|
* Default `shortcut='mod+k'` opens the dialog on the canonical
|
|
* keyboard binding. Set `shortcut={null}` to disable.
|
|
*/
|
|
import { ActiveEidos } from '$uix/eidos';
|
|
import { Dialog } from '$uix/eidos/components/dialog';
|
|
import CommandRoot from './command.svelte';
|
|
import type { CommandDialogProps } from './types';
|
|
import { bindCommandShortcut } from './command-shortcut.svelte';
|
|
|
|
let {
|
|
open = $bindable(false),
|
|
onOpenChange,
|
|
modal = true,
|
|
shortcut = 'mod+k',
|
|
size = 'md',
|
|
dialogSize = 'md',
|
|
// Command pass-through
|
|
label,
|
|
value = $bindable(''),
|
|
onValueChange,
|
|
search = $bindable(''),
|
|
onSearchChange,
|
|
shouldFilter = true,
|
|
filter,
|
|
loop = false,
|
|
vimBindings = true,
|
|
columns = 1,
|
|
disablePointerSelection = false,
|
|
overlay,
|
|
// Rename to avoid shadowing the inner snippet
|
|
children: bodyContent
|
|
}: CommandDialogProps = $props();
|
|
|
|
const eidos = ActiveEidos.require();
|
|
|
|
// Uses `$effect` (see command.svelte — visual layer can't import
|
|
// Svelte 4 lifecycle hooks). DOM binding via `eidos.dom.listen(...)`
|
|
// inside `bindCommandShortcut` so the ActiveDom layer owns cleanup.
|
|
$effect(() => {
|
|
if (!shortcut) return undefined;
|
|
return bindCommandShortcut(eidos.dom, shortcut, () => {
|
|
const next = !open;
|
|
open = next;
|
|
onOpenChange?.(next);
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<Dialog bind:open {modal} onOpenChange={(v) => onOpenChange?.(v)}>
|
|
<Dialog.Portal>
|
|
{#if overlay}{@render overlay()}{:else}<Dialog.Overlay />{/if}
|
|
<Dialog.Content size={dialogSize}>
|
|
<Dialog.Close position="top-right" variant="ghost" color="neutral" />
|
|
<CommandRoot
|
|
{label}
|
|
onSelect={() => (open = false)}
|
|
bind:value
|
|
onValueChange={(v) => onValueChange?.(v)}
|
|
bind:search
|
|
onSearchChange={(v) => onSearchChange?.(v)}
|
|
{shouldFilter}
|
|
{filter}
|
|
{loop}
|
|
{vimBindings}
|
|
{columns}
|
|
{disablePointerSelection}
|
|
{size}
|
|
>
|
|
{#snippet children(snippetProps)}
|
|
{@render bodyContent?.(snippetProps)}
|
|
{/snippet}
|
|
</CommandRoot>
|
|
</Dialog.Content>
|
|
</Dialog.Portal>
|
|
</Dialog>
|