Consolidate Soma virtual list runtimes

active-uix
dev 5 months ago
parent 48b0c4ae2f
commit cac7e89232

@ -10,7 +10,7 @@ import { GRID_LIST_LANGS } from './langs';
import type { GridListSelectionMode } from './types';
import { gridListMorfo } from '../../../morfo/components/grid-list';
import type { SomaRuntimePart } from '../../runtime.svelte';
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
const attrs = createAttrs(gridListMorfo);
@ -38,6 +38,8 @@ interface GridListOpts
export class GridListProvider {
readonly opts: GridListOpts;
readonly runtimePart: SomaRuntimePart;
readonly soma: Soma;
readonly runtime: SomaRuntime;
static readonly ctx = context<GridListProvider>('GridList');
static get(): GridListProvider | undefined {
return this.ctx.getOr(undefined) as GridListProvider | undefined;
@ -50,7 +52,6 @@ export class GridListProvider {
return new GridListProvider(opts);
}
readonly soma = Soma.get();
readonly field = FieldProvider.get();
private typeaheadBuffer = '';
@ -60,9 +61,14 @@ export class GridListProvider {
private constructor(opts: GridListOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(gridListMorfo, {})
.part('provider', { id: opts.id, ref: opts.ref, owner: this, context: GridListProvider.ctx });
this.soma = Soma.require();
this.runtime = this.soma.runtime(gridListMorfo, {});
this.runtimePart = this.runtime.part('provider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: GridListProvider.ctx
});
$effect(() => {
return () => {
@ -87,13 +93,13 @@ export class GridListProvider {
);
readonly resolvedDir: Active<Direction> = readableActive(
() => this.soma?.prefs.getDir() ?? 'ltr'
() => this.soma.prefs.getDir() ?? 'ltr'
);
readonly resolvedAriaLabel: Active<string | undefined> = readableActive(() =>
this.opts.ariaLabelledby.current
? undefined
: this.opts.ariaLabel.current || this.soma?.langs.ts(GRID_LIST_LANGS.LABEL) || undefined
: this.opts.ariaLabel.current || this.soma.langs.ts(GRID_LIST_LANGS.LABEL) || undefined
);
readonly isEmpty = $derived.by(() => this.opts.value.current.length === 0);
@ -448,10 +454,12 @@ export class GridListRowProvider {
private constructor(opts: GridListRowOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(gridListMorfo, {})
.part('row', { id: opts.id, ref: opts.ref, owner: this });
this.provider = GridListProvider.require();
this.runtimePart = this.provider.runtime.part('row', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly isSelected = $derived.by(() => this.provider.isSelected(this.opts.value.current));
@ -508,10 +516,12 @@ export class GridListCellProvider {
private constructor(opts: GridListCellOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(gridListMorfo, {})
.part('cell', { id: opts.id, ref: opts.ref, owner: this });
this.provider = GridListProvider.require();
this.runtimePart = this.provider.runtime.part('cell', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
/**
@ -550,10 +560,12 @@ export class GridListSelectionCheckboxProvider {
private constructor(opts: GridListSelectionCheckboxOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(gridListMorfo, {})
.part('selection-checkbox', { id: opts.id, ref: opts.ref, owner: this });
this.provider = GridListProvider.require();
this.runtimePart = this.provider.runtime.part('selection-checkbox', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
/** Read the enclosing row's value lazily (on click). */
@ -579,7 +591,7 @@ export class GridListSelectionCheckboxProvider {
readonly resolvedAriaLabel = $derived.by(
() =>
this.opts.ariaLabel.current ||
this.provider.soma?.langs.ts(GRID_LIST_LANGS.SELECT_ROW) ||
this.provider.soma.langs.ts(GRID_LIST_LANGS.SELECT_ROW) ||
undefined
);

@ -4,7 +4,7 @@ import type { ScrollToCellOptions, VirtualCell } from './types';
import { virtualGridMorfo } from '../../../morfo/components/virtual-grid';
import { Soma } from '../../core/soma.svelte';
import type { SomaRuntimePart } from '../../runtime.svelte';
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
// ── Helpers (1D per-axis) ──────────────────────────────────────────────────
@ -74,6 +74,8 @@ interface VirtualGridOpts
export class VirtualGridProvider {
readonly opts: VirtualGridOpts;
readonly runtimePart: SomaRuntimePart;
readonly soma: Soma;
readonly runtime: SomaRuntime;
static readonly ctx = context<VirtualGridProvider>('VirtualGrid');
static get(): VirtualGridProvider | undefined {
return this.ctx.getOr(undefined) as VirtualGridProvider | undefined;
@ -94,14 +96,14 @@ export class VirtualGridProvider {
private constructor(opts: VirtualGridOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(virtualGridMorfo, {})
.part('provider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: VirtualGridProvider.ctx
});
this.soma = Soma.require();
this.runtime = this.soma.runtime(virtualGridMorfo, {});
this.runtimePart = this.runtime.part('provider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: VirtualGridProvider.ctx
});
}
readonly totalHeight = $derived.by(() => this.opts.rowCount.current * this.opts.rowSize.current);
@ -214,17 +216,15 @@ export class VirtualGridViewportProvider {
private constructor(opts: VirtualGridViewportOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(virtualGridMorfo, {})
.part('viewport', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (el) => {
this.provider.viewportRef = el;
}
});
this.provider = VirtualGridProvider.require();
this.runtimePart = this.provider.runtime.part('viewport', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (el) => {
this.provider.viewportRef = el;
}
});
$effect(() => {
const el = this.opts.ref.current;
@ -290,10 +290,12 @@ export class VirtualGridCellProvider {
private constructor(opts: VirtualGridCellOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(virtualGridMorfo, {})
.part('cell', { id: opts.id, ref: opts.ref, owner: this });
this.provider = VirtualGridProvider.require();
this.runtimePart = this.provider.runtime.part('cell', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly props = $derived.by(() => {

@ -6,7 +6,7 @@ import type { ScrollToIndexOptions, VirtualItem } from './types';
import { virtualListMorfo } from '../../../morfo/components/virtual-list';
import { Soma } from '../../core/soma.svelte';
import type { SomaRuntimePart } from '../../runtime.svelte';
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
// ── Root provider ──────────────────────────────────────────────────────────
@ -26,6 +26,8 @@ interface VirtualListOpts
export class VirtualListProvider {
readonly opts: VirtualListOpts;
readonly runtimePart: SomaRuntimePart;
readonly soma: Soma;
readonly runtime: SomaRuntime;
static readonly ctx = context<VirtualListProvider>('VirtualList');
static get(): VirtualListProvider | undefined {
return this.ctx.getOr(undefined) as VirtualListProvider | undefined;
@ -65,14 +67,14 @@ export class VirtualListProvider {
private constructor(opts: VirtualListOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(virtualListMorfo, {})
.part('provider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: VirtualListProvider.ctx
});
this.soma = Soma.require();
this.runtime = this.soma.runtime(virtualListMorfo, {});
this.runtimePart = this.runtime.part('provider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: VirtualListProvider.ctx
});
}
readonly isHorizontal = $derived.by(() => this.opts.orientation.current === 'horizontal');
@ -308,17 +310,15 @@ export class VirtualListViewportProvider {
private constructor(opts: VirtualListViewportOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(virtualListMorfo, {})
.part('viewport', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (el) => {
this.provider.viewportRef = el;
}
});
this.provider = VirtualListProvider.require();
this.runtimePart = this.provider.runtime.part('viewport', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (el) => {
this.provider.viewportRef = el;
}
});
$effect(() => {
const el = this.opts.ref.current;
@ -383,17 +383,15 @@ export class VirtualListWindowViewportProvider {
private constructor(opts: VirtualListWindowViewportOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(virtualListMorfo, {})
.part('window-viewport', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (el) => {
this.provider.windowHostRef = el;
}
});
this.provider = VirtualListProvider.require();
this.runtimePart = this.provider.runtime.part('window-viewport', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (el) => {
this.provider.windowHostRef = el;
}
});
$effect(() => {
const el = this.opts.ref.current;
@ -460,10 +458,12 @@ export class VirtualListItemProvider {
private constructor(opts: VirtualListItemOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(virtualListMorfo, {})
.part('item', { id: opts.id, ref: opts.ref, owner: this });
this.provider = VirtualListProvider.require();
this.runtimePart = this.provider.runtime.part('item', {
id: opts.id,
ref: opts.ref,
owner: this
});
// ResizeObserver: report real rendered size back to the provider so
// the cache reflects actual layout. Only attaches when the consumer

Loading…
Cancel
Save

Powered by TurnKey Linux.