diff --git a/src/uix/soma/components/menubar/menubar-provider.svelte.ts b/src/uix/soma/components/menubar/menubar-provider.svelte.ts index a16e0955f..440f454b6 100644 --- a/src/uix/soma/components/menubar/menubar-provider.svelte.ts +++ b/src/uix/soma/components/menubar/menubar-provider.svelte.ts @@ -20,7 +20,7 @@ import { FloatingAnchor } from '../../layers/floating'; import { menubarMorfo } from '../../../morfo/components/menubar'; import { Soma } from '../../core/soma.svelte'; -import type { SomaRuntimePart } from '../../runtime.svelte'; +import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte'; // ── Root ───────────────────────────────────────────────────────────────────── @@ -37,6 +37,8 @@ interface MenubarOpts export class MenubarProvider { readonly opts: MenubarOpts; readonly runtimePart: SomaRuntimePart; + readonly soma: Soma; + readonly runtime: SomaRuntime; static readonly ctx = context('Menubar'); static get(): MenubarProvider | undefined { return this.ctx.getOr(undefined) as MenubarProvider | undefined; @@ -57,9 +59,14 @@ export class MenubarProvider { private constructor(opts: MenubarOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(menubarMorfo, {}) - .part('provider', { id: opts.id, ref: opts.ref, owner: this, context: MenubarProvider.ctx }); + this.soma = Soma.require(); + this.runtime = this.soma.runtime(menubarMorfo, {}); + this.runtimePart = this.runtime.part('provider', { + id: opts.id, + ref: opts.ref, + owner: this, + context: MenubarProvider.ctx + }); } registerTrigger(value: string, el: HTMLElement) { @@ -300,11 +307,13 @@ export class MenubarTriggerProvider { private constructor(opts: MenubarTriggerOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(menubarMorfo, {}) - .part('trigger', { id: opts.id, ref: opts.ref, owner: this }); this.menu = MenubarMenuProvider.require(); this.provider = this.menu.provider; + this.runtimePart = this.provider.runtime.part('trigger', { + id: opts.id, + ref: opts.ref, + owner: this + }); // Pipe the trigger id so the internal DropdownMenu.MenuProvider's // content aria-labelledby targets this button. diff --git a/src/uix/soma/components/stepper/stepper-provider.svelte.ts b/src/uix/soma/components/stepper/stepper-provider.svelte.ts index d1dce99f7..c9306c231 100644 --- a/src/uix/soma/components/stepper/stepper-provider.svelte.ts +++ b/src/uix/soma/components/stepper/stepper-provider.svelte.ts @@ -7,7 +7,7 @@ import { Soma } from '../../core/soma.svelte'; import { STEPPER_LANGS } from './langs'; import { stepperMorfo } from '../../../morfo/components/stepper'; -import type { SomaRuntimePart } from '../../runtime.svelte'; +import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte'; export type StepState = 'complete' | 'current' | 'incomplete'; @@ -27,6 +27,8 @@ interface StepperOpts export class StepperProvider { readonly opts: StepperOpts; readonly runtimePart: SomaRuntimePart; + readonly soma: Soma; + readonly runtime: SomaRuntime; static readonly ctx = context('Stepper'); static get(): StepperProvider | undefined { return this.ctx.getOr(undefined) as StepperProvider | undefined; @@ -39,7 +41,6 @@ export class StepperProvider { return new StepperProvider(opts); } - readonly soma = Soma.get(); private _count = $state(0); get count(): number { return this._count; @@ -72,9 +73,14 @@ export class StepperProvider { private constructor(opts: StepperOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('provider', { id: opts.id, ref: opts.ref, owner: this, context: StepperProvider.ctx }); + this.soma = Soma.require(); + this.runtime = this.soma.runtime(stepperMorfo, {}); + this.runtimePart = this.runtime.part('provider', { + id: opts.id, + ref: opts.ref, + owner: this, + context: StepperProvider.ctx + }); } get step(): number { @@ -142,17 +148,19 @@ export class StepperListProvider { private constructor(opts: StepperListOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('list', { id: opts.id, ref: opts.ref, owner: this }); this.provider = StepperProvider.require(); + this.runtimePart = this.provider.runtime.part('list', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly props = $derived.by(() => this.runtimePart.assert({ ...this.runtimePart.props, role: 'tablist' as const, - 'aria-label': this.opts.ariaLabel.current || this.provider.soma?.langs.ts(STEPPER_LANGS.LIST), + 'aria-label': this.opts.ariaLabel.current || this.provider.soma.langs.ts(STEPPER_LANGS.LIST), 'aria-orientation': this.provider.opts.orientation.current, 'data-orientation': this.provider.opts.orientation.current } as const) @@ -189,10 +197,13 @@ export class StepperItemProvider { private constructor(opts: StepperItemOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('item', { id: opts.id, ref: opts.ref, owner: this, context: StepperItemProvider.ctx }); this.provider = StepperProvider.require(); + this.runtimePart = this.provider.runtime.part('item', { + id: opts.id, + ref: opts.ref, + owner: this, + context: StepperItemProvider.ctx + }); // Track count: increment on mount, decrement on unmount this.provider.incrementCount(); @@ -240,11 +251,13 @@ export class StepperTriggerProvider { private constructor(opts: StepperTriggerOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('trigger', { id: opts.id, ref: opts.ref, owner: this }); this.provider = StepperProvider.require(); this.item = StepperItemProvider.require(); + this.runtimePart = this.provider.runtime.part('trigger', { + id: opts.id, + ref: opts.ref, + owner: this + }); this.item.triggerId.current = opts.id.current; // Register in trigger registry for keyboard nav @@ -335,10 +348,12 @@ export class StepperIndicatorProvider { private constructor(opts: StepperIndicatorOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('indicator', { id: opts.id, ref: opts.ref, owner: this }); this.item = StepperItemProvider.require(); + this.runtimePart = this.item.provider.runtime.part('indicator', { + id: opts.id, + ref: opts.ref, + owner: this + }); } /** Proxy to `item.stepState` so the wrapper snippet doesn't need `ctx.get()`. */ @@ -372,11 +387,13 @@ export class StepperSeparatorProvider { private constructor(opts: StepperSeparatorOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('separator', { id: opts.id, ref: opts.ref, owner: this }); this.item = StepperItemProvider.require(); - this.provider = StepperProvider.require(); + this.provider = this.item.provider; + this.runtimePart = this.provider.runtime.part('separator', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly props = $derived.by(() => @@ -412,10 +429,12 @@ export class StepperContentProvider { private constructor(opts: StepperContentOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('content', { id: opts.id, ref: opts.ref, owner: this }); this.provider = StepperProvider.require(); + this.runtimePart = this.provider.runtime.part('content', { + id: opts.id, + ref: opts.ref, + owner: this + }); // Content can be inside or outside an Item — use get() not require() const item = StepperItemProvider.get(); if (item) item.contentId.current = opts.id.current; @@ -450,10 +469,12 @@ export class StepperCompletedContentProvider { private constructor(opts: StepperCompletedContentOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('completed-content', { id: opts.id, ref: opts.ref, owner: this }); this.provider = StepperProvider.require(); + this.runtimePart = this.provider.runtime.part('completed-content', { + id: opts.id, + ref: opts.ref, + owner: this + }); } /** Proxy to `provider.isCompleted` so the wrapper doesn't need `ctx.get()`. */ @@ -487,10 +508,12 @@ export class StepperPrevTriggerProvider { private constructor(opts: StepperPrevTriggerOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('prev-trigger', { id: opts.id, ref: opts.ref, owner: this }); this.provider = StepperProvider.require(); + this.runtimePart = this.provider.runtime.part('prev-trigger', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly isDisabled = $derived.by(() => this.opts.disabled.current || !this.provider.hasPrevStep); @@ -531,10 +554,12 @@ export class StepperNextTriggerProvider { private constructor(opts: StepperNextTriggerOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(stepperMorfo, {}) - .part('next-trigger', { id: opts.id, ref: opts.ref, owner: this }); this.provider = StepperProvider.require(); + this.runtimePart = this.provider.runtime.part('next-trigger', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly isDisabled = $derived.by(() => this.opts.disabled.current || !this.provider.hasNextStep);