|
|
|
|
@ -19,7 +19,7 @@ import { computeCommandScore } from './score';
|
|
|
|
|
import type { CommandFilterFn, CommandSnippetProps } from './types';
|
|
|
|
|
|
|
|
|
|
import { commandMorfo } from '../../../morfo/components/command';
|
|
|
|
|
import type { SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ── Registry shapes ──────────────────────────────────────────────────────────
|
|
|
|
|
@ -90,6 +90,8 @@ interface CommandOpts
|
|
|
|
|
export class CommandProvider {
|
|
|
|
|
readonly opts: CommandOpts;
|
|
|
|
|
readonly runtimePart: SomaRuntimePart;
|
|
|
|
|
readonly soma: Soma;
|
|
|
|
|
readonly runtime: SomaRuntime;
|
|
|
|
|
static readonly ctx = context<CommandProvider>('Command');
|
|
|
|
|
static get(): CommandProvider | undefined {
|
|
|
|
|
return this.ctx.getOr(undefined) as CommandProvider | undefined;
|
|
|
|
|
@ -102,8 +104,6 @@ export class CommandProvider {
|
|
|
|
|
return new CommandProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly soma = Soma.get();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Plain storage + a version counter that increments synchronously on each
|
|
|
|
|
* mutation. Synchronous = consumer event handlers (clicks) see up-to-date
|
|
|
|
|
@ -123,9 +123,14 @@ export class CommandProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('provider', { id: opts.id, ref: opts.ref, owner: this, context: CommandProvider.ctx });
|
|
|
|
|
this.soma = Soma.require();
|
|
|
|
|
this.runtime = this.soma.runtime(commandMorfo, {});
|
|
|
|
|
this.runtimePart = this.runtime.part('provider', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
context: CommandProvider.ctx
|
|
|
|
|
});
|
|
|
|
|
dbg('Provider.ctor');
|
|
|
|
|
|
|
|
|
|
// Build the stable snippet props object. Getters read reactive state
|
|
|
|
|
@ -413,10 +418,12 @@ export class CommandInputProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandInputOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('input', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CommandProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('input', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.provider.inputId.current = opts.id.current;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -524,10 +531,12 @@ export class CommandListProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandListOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('list', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CommandProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('list', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.provider.listId.current = opts.id.current;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -536,7 +545,7 @@ export class CommandListProvider {
|
|
|
|
|
...this.runtimePart.props,
|
|
|
|
|
role: 'listbox' as const,
|
|
|
|
|
'aria-label':
|
|
|
|
|
this.provider.opts.label.current ?? this.provider.soma?.langs.ts(COMMAND_LANGS.LIST)
|
|
|
|
|
this.provider.opts.label.current ?? this.provider.soma.langs.ts(COMMAND_LANGS.LIST)
|
|
|
|
|
} as const)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
@ -556,9 +565,12 @@ export class CommandViewportProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandViewportOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('viewport', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
const provider = CommandProvider.require();
|
|
|
|
|
this.runtimePart = provider.runtime.part('viewport', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
const el = opts.ref.current;
|
|
|
|
|
@ -606,11 +618,13 @@ export class CommandItemProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandItemOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('item', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CommandProvider.require();
|
|
|
|
|
this.group = CommandGroupProvider.get();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('item', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
dbg('Item.ctor', opts.value.current);
|
|
|
|
|
|
|
|
|
|
const groupValue = this.group?.opts.value.current;
|
|
|
|
|
@ -730,11 +744,13 @@ export class CommandLinkItemProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandLinkItemOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('link-item', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CommandProvider.require();
|
|
|
|
|
this.group = CommandGroupProvider.get();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('link-item', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
const groupValue = this.group?.opts.value.current;
|
|
|
|
|
|
|
|
|
|
// See the matching block in CommandItemProvider: register once per
|
|
|
|
|
@ -842,15 +858,13 @@ export class CommandGroupProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandGroupOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('group', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
context: CommandGroupProvider.ctx
|
|
|
|
|
});
|
|
|
|
|
this.provider = CommandProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('group', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
context: CommandGroupProvider.ctx
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Register ONCE per group identity. The register/unregister calls read
|
|
|
|
|
// from the reactive `groups` array internally, so wrap in untrack to
|
|
|
|
|
@ -894,10 +908,12 @@ export class CommandGroupHeadingProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandGroupHeadingOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('group-heading', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.group = CommandGroupProvider.require();
|
|
|
|
|
this.runtimePart = this.group.provider.runtime.part('group-heading', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.group.headingId.current = opts.id.current;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -919,10 +935,12 @@ export class CommandGroupItemsProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandGroupItemsOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('group-items', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
CommandGroupProvider.require();
|
|
|
|
|
const group = CommandGroupProvider.require();
|
|
|
|
|
this.runtimePart = group.provider.runtime.part('group-items', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
@ -948,10 +966,12 @@ export class CommandEmptyProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandEmptyOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('empty', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CommandProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('empty', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly shouldRender = $derived.by(() => this.provider.isEmpty);
|
|
|
|
|
@ -978,10 +998,12 @@ export class CommandLoadingProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandLoadingOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('loading', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
CommandProvider.require();
|
|
|
|
|
const provider = CommandProvider.require();
|
|
|
|
|
this.runtimePart = provider.runtime.part('loading', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly percent: Active<number | undefined> = readableActive(() => {
|
|
|
|
|
@ -1017,10 +1039,12 @@ export class CommandSeparatorProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CommandSeparatorOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(commandMorfo, {})
|
|
|
|
|
.part('separator', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CommandProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('separator', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Hide the separator when the palette has no visible items, unless forced. */
|
|
|
|
|
|