diff --git a/src/uix/soma/components/date-range-field/date-range-field-provider.svelte.ts b/src/uix/soma/components/date-range-field/date-range-field-provider.svelte.ts index 732177db6..c048b9e57 100644 --- a/src/uix/soma/components/date-range-field/date-range-field-provider.svelte.ts +++ b/src/uix/soma/components/date-range-field/date-range-field-provider.svelte.ts @@ -25,7 +25,7 @@ import { FieldProvider } from '../field/field-provider.svelte'; import { dateRangeFieldMorfo } from '../../../morfo/components/date-range-field'; const attrs = createAttrs(dateRangeFieldMorfo); -import type { SomaRuntimePart } from '../../runtime.svelte'; +import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte'; // ── Root ──────────────────────────────────────────────────────────────────── @@ -65,6 +65,8 @@ interface DateRangeFieldOpts export class DateRangeFieldProvider { readonly opts: DateRangeFieldOpts; readonly runtimePart: SomaRuntimePart; + readonly soma: Soma; + readonly runtime: SomaRuntime; static readonly ctx = context('DateRangeField'); static get(): DateRangeFieldProvider | undefined { return this.ctx.getOr(undefined) as DateRangeFieldProvider | undefined; @@ -76,7 +78,6 @@ export class DateRangeFieldProvider { return new DateRangeFieldProvider(opts); } - readonly soma = Soma.get(); readonly field = FieldProvider.get(); labelNode = $state(null); @@ -85,14 +86,14 @@ export class DateRangeFieldProvider { private constructor(opts: DateRangeFieldOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(dateRangeFieldMorfo, {}) - .part('provider', { - id: opts.id, - ref: opts.ref, - owner: this, - context: DateRangeFieldProvider.ctx - }); + this.soma = Soma.require(); + this.runtime = this.soma.runtime(dateRangeFieldMorfo, {}); + this.runtimePart = this.runtime.part('provider', { + id: opts.id, + ref: opts.ref, + owner: this, + context: DateRangeFieldProvider.ctx + }); } // ── Merged flags (own + Field parent via OR) ───────────────────────────── @@ -171,17 +172,15 @@ export class DateRangeFieldLabelProvider { private constructor(opts: DateRangeFieldLabelOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(dateRangeFieldMorfo, {}) - .part('label', { - id: opts.id, - ref: opts.ref, - owner: this, - onRefChange: (v) => { - this.provider.labelNode = v; - } - }); this.provider = DateRangeFieldProvider.require(); + this.runtimePart = this.provider.runtime.part('label', { + id: opts.id, + ref: opts.ref, + owner: this, + onRefChange: (v) => { + this.provider.labelNode = v; + } + }); } readonly onclick = () => { diff --git a/src/uix/soma/components/pin-input/pin-input-provider.svelte.ts b/src/uix/soma/components/pin-input/pin-input-provider.svelte.ts index c052507a7..07f325bc0 100644 --- a/src/uix/soma/components/pin-input/pin-input-provider.svelte.ts +++ b/src/uix/soma/components/pin-input/pin-input-provider.svelte.ts @@ -20,7 +20,7 @@ import { PIN_INPUT_LANGS } from './langs'; import type { PinInputCellData, PinInputType } from './types'; import { pinInputMorfo } from '../../../morfo/components/pin-input'; -import type { SomaRuntimePart } from '../../runtime.svelte'; +import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte'; // ── Preset patterns ──────────────────────────────────────────────────────── @@ -82,6 +82,8 @@ interface PinInputOpts export class PinInputProvider { readonly opts: PinInputOpts; readonly runtimePart: SomaRuntimePart; + readonly soma: Soma; + readonly runtime: SomaRuntime; static readonly ctx = context('PinInput'); static get(): PinInputProvider | undefined { return this.ctx.getOr(undefined) as PinInputProvider | undefined; @@ -94,7 +96,6 @@ export class PinInputProvider { return new PinInputProvider(opts); } - readonly soma = Soma.get(); readonly field = FieldProvider.get(); inputRef = state(null); @@ -105,9 +106,14 @@ export class PinInputProvider { private constructor(opts: PinInputOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(pinInputMorfo, {}) - .part('provider', { id: opts.id, ref: opts.ref, owner: this, context: PinInputProvider.ctx }); + this.soma = Soma.require(); + this.runtime = this.soma.runtime(pinInputMorfo, {}); + this.runtimePart = this.runtime.part('provider', { + id: opts.id, + ref: opts.ref, + owner: this, + context: PinInputProvider.ctx + }); // Register the hidden input id with a parent Field so `Field.Label`'s // `for` attribute lands on the interactive element. Direct assignment @@ -157,7 +163,7 @@ export class PinInputProvider { () => this.opts.autocomplete.current ?? 'one-time-code' ); readonly resolvedAriaLabel: Active = readableActive( - () => this.opts.ariaLabel.current || this.soma?.langs.ts(PIN_INPUT_LANGS.INPUT) || undefined + () => this.opts.ariaLabel.current || this.soma.langs.ts(PIN_INPUT_LANGS.INPUT) || undefined ); readonly isComplete = $derived.by( @@ -326,17 +332,15 @@ export class PinInputInputProvider { private constructor(opts: PinInputInputOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(pinInputMorfo, {}) - .part('input', { - id: opts.id, - ref: opts.ref, - owner: this, - onRefChange: (el) => { - this.provider.setInputRef(el as HTMLInputElement | null); - } - }); this.provider = PinInputProvider.require(); + this.runtimePart = this.provider.runtime.part('input', { + id: opts.id, + ref: opts.ref, + owner: this, + onRefChange: (el) => { + this.provider.setInputRef(el as HTMLInputElement | null); + } + }); } readonly props = $derived.by(() => @@ -384,10 +388,12 @@ export class PinInputCellProvider { private constructor(opts: PinInputCellOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(pinInputMorfo, {}) - .part('cell', { id: opts.id, ref: opts.ref, owner: this }); this.provider = PinInputProvider.require(); + this.runtimePart = this.provider.runtime.part('cell', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly props = $derived.by(() => { diff --git a/src/uix/soma/components/slider/slider-provider.svelte.ts b/src/uix/soma/components/slider/slider-provider.svelte.ts index a5251fcc4..40b62d0c4 100644 --- a/src/uix/soma/components/slider/slider-provider.svelte.ts +++ b/src/uix/soma/components/slider/slider-provider.svelte.ts @@ -6,7 +6,7 @@ import { KEYS, getDirectionalKeys } from '../../keyboard'; import { sliderMorfo } from '../../../morfo/components/slider'; import { Soma } from '../../core/soma.svelte'; -import type { SomaRuntimePart } from '../../runtime.svelte'; +import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte'; export type SliderType = 'single' | 'multiple'; @@ -53,6 +53,8 @@ interface SliderOpts export class SliderProvider { readonly opts: SliderOpts; readonly runtimePart: SomaRuntimePart; + readonly soma: Soma; + readonly runtime: SomaRuntime; static readonly ctx = context('Slider'); static get(): SliderProvider | undefined { return this.ctx.getOr(undefined) as SliderProvider | undefined; @@ -69,9 +71,14 @@ export class SliderProvider { private constructor(opts: SliderOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(sliderMorfo, {}) - .part('provider', { id: opts.id, ref: opts.ref, owner: this, context: SliderProvider.ctx }); + this.soma = Soma.require(); + this.runtime = this.soma.runtime(sliderMorfo, {}); + this.runtimePart = this.runtime.part('provider', { + id: opts.id, + ref: opts.ref, + owner: this, + context: SliderProvider.ctx + }); } getPercent(value: number): number { @@ -237,10 +244,12 @@ export class SliderRangeProvider { private constructor(opts: SliderRangeOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(sliderMorfo, {}) - .part('range', { id: opts.id, ref: opts.ref, owner: this }); this.provider = SliderProvider.require(); + this.runtimePart = this.provider.runtime.part('range', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly rangeStyle = $derived.by(() => { @@ -289,10 +298,12 @@ export class SliderThumbProvider { private constructor(opts: SliderThumbOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(sliderMorfo, {}) - .part('thumb', { id: opts.id, ref: opts.ref, owner: this }); this.provider = SliderProvider.require(); + this.runtimePart = this.provider.runtime.part('thumb', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly value = $derived.by( @@ -401,10 +412,12 @@ export class SliderTickProvider { private constructor(opts: SliderTickOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(sliderMorfo, {}) - .part('tick', { id: opts.id, ref: opts.ref, owner: this }); this.provider = SliderProvider.require(); + this.runtimePart = this.provider.runtime.part('tick', { + id: opts.id, + ref: opts.ref, + owner: this + }); } readonly percent = $derived.by(() => this.provider.getPercent(this.opts.value.current)); diff --git a/src/uix/soma/components/splitter/splitter-provider.svelte.ts b/src/uix/soma/components/splitter/splitter-provider.svelte.ts index 7d50379be..2d66e0ded 100644 --- a/src/uix/soma/components/splitter/splitter-provider.svelte.ts +++ b/src/uix/soma/components/splitter/splitter-provider.svelte.ts @@ -7,7 +7,7 @@ import { Soma } from '../../core/soma.svelte'; import { SPLITTER_LANGS } from './langs'; import { splitterMorfo } from '../../../morfo/components/splitter'; -import type { SomaRuntimePart } from '../../runtime.svelte'; +import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte'; // ── Types ──────────────────────────────────────────────────────────────────── @@ -57,6 +57,8 @@ interface SplitterOpts export class SplitterProvider { readonly opts: SplitterOpts; readonly runtimePart: SomaRuntimePart; + readonly soma: Soma; + readonly runtime: SomaRuntime; static readonly ctx = context('Splitter'); static get(): SplitterProvider | undefined { return this.ctx.getOr(undefined) as SplitterProvider | undefined; @@ -69,15 +71,19 @@ export class SplitterProvider { return new SplitterProvider(opts); } - readonly soma = Soma.get(); private panels: PanelState[] = $state([]); resizing = $state(false); private constructor(opts: SplitterOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(splitterMorfo, {}) - .part('provider', { id: opts.id, ref: opts.ref, owner: this, context: SplitterProvider.ctx }); + this.soma = Soma.require(); + this.runtime = this.soma.runtime(splitterMorfo, {}); + this.runtimePart = this.runtime.part('provider', { + id: opts.id, + ref: opts.ref, + owner: this, + context: SplitterProvider.ctx + }); } // ── Panel registration ─────────────────────────────────────────────────── @@ -282,10 +288,12 @@ export class SplitterPanelProvider { private constructor(opts: SplitterPanelOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(splitterMorfo, {}) - .part('panel', { id: opts.id, ref: opts.ref, owner: this }); this.provider = SplitterProvider.require(); + this.runtimePart = this.provider.runtime.part('panel', { + id: opts.id, + ref: opts.ref, + owner: this + }); this.cleanup = this.provider.registerPanel({ id: opts.panelId.current, @@ -356,10 +364,12 @@ export class SplitterResizeTriggerProvider { private constructor(opts: SplitterResizeTriggerOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(splitterMorfo, {}) - .part('resize-trigger', { id: opts.id, ref: opts.ref, owner: this }); this.provider = SplitterProvider.require(); + this.runtimePart = this.provider.runtime.part('resize-trigger', { + id: opts.id, + ref: opts.ref, + owner: this + }); // Cleanup drag state on unmount $effect(() => { @@ -545,7 +555,7 @@ export class SplitterResizeTriggerProvider { this.runtimePart.assert({ ...this.runtimePart.props, role: 'separator' as const, - 'aria-label': this.provider.soma?.langs.ts(SPLITTER_LANGS.RESIZE), + 'aria-label': this.provider.soma.langs.ts(SPLITTER_LANGS.RESIZE), 'aria-orientation': this.provider.opts.orientation.current, 'aria-valuenow': this.ariaValueNow, 'aria-valuemin': this.ariaValueMin, diff --git a/src/uix/soma/components/time-range-field/time-range-field-provider.svelte.ts b/src/uix/soma/components/time-range-field/time-range-field-provider.svelte.ts index 7548cf0ce..d6872fc0d 100644 --- a/src/uix/soma/components/time-range-field/time-range-field-provider.svelte.ts +++ b/src/uix/soma/components/time-range-field/time-range-field-provider.svelte.ts @@ -20,7 +20,7 @@ import { FieldProvider } from '../field/field-provider.svelte'; import { timeRangeFieldMorfo } from '../../../morfo/components/time-range-field'; const attrs = createAttrs(timeRangeFieldMorfo); -import type { SomaRuntimePart } from '../../runtime.svelte'; +import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte'; // ── Root ──────────────────────────────────────────────────────────────────── @@ -60,6 +60,8 @@ interface TimeRangeFieldOpts export class TimeRangeFieldProvider { readonly opts: TimeRangeFieldOpts; readonly runtimePart: SomaRuntimePart; + readonly soma: Soma; + readonly runtime: SomaRuntime; static readonly ctx = context('TimeRangeField'); static get(): TimeRangeFieldProvider | undefined { return this.ctx.getOr(undefined) as TimeRangeFieldProvider | undefined; @@ -71,7 +73,6 @@ export class TimeRangeFieldProvider { return new TimeRangeFieldProvider(opts); } - readonly soma = Soma.get(); readonly field = FieldProvider.get(); labelNode = $state(null); @@ -80,14 +81,14 @@ export class TimeRangeFieldProvider { private constructor(opts: TimeRangeFieldOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(timeRangeFieldMorfo, {}) - .part('provider', { - id: opts.id, - ref: opts.ref, - owner: this, - context: TimeRangeFieldProvider.ctx - }); + this.soma = Soma.require(); + this.runtime = this.soma.runtime(timeRangeFieldMorfo, {}); + this.runtimePart = this.runtime.part('provider', { + id: opts.id, + ref: opts.ref, + owner: this, + context: TimeRangeFieldProvider.ctx + }); } // ── Merged flags (own + Field parent via OR) ───────────────────────────── @@ -179,17 +180,15 @@ export class TimeRangeFieldLabelProvider { private constructor(opts: TimeRangeFieldLabelOpts) { this.opts = opts; - this.runtimePart = Soma.require() - .runtime(timeRangeFieldMorfo, {}) - .part('label', { - id: opts.id, - ref: opts.ref, - owner: this, - onRefChange: (v) => { - this.provider.labelNode = v; - } - }); this.provider = TimeRangeFieldProvider.require(); + this.runtimePart = this.provider.runtime.part('label', { + id: opts.id, + ref: opts.ref, + owner: this, + onRefChange: (v) => { + this.provider.labelNode = v; + } + }); } readonly onclick = () => {