From 3097a209f04ce1ceb5e05c8fa76bc641295e8fb0 Mon Sep 17 00:00:00 2001 From: dev Date: Fri, 15 May 2026 03:02:30 +0200 Subject: [PATCH] Consolidate Soma command runtime --- .../command/command-provider.svelte.ts | 118 +++++++++++------- 1 file changed, 71 insertions(+), 47 deletions(-) diff --git a/src/uix/soma/components/command/command-provider.svelte.ts b/src/uix/soma/components/command/command-provider.svelte.ts index 455935907..e5bc7d634 100644 --- a/src/uix/soma/components/command/command-provider.svelte.ts +++ b/src/uix/soma/components/command/command-provider.svelte.ts @@ -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('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 = 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. */