Consolidate Soma color picker runtime

active-uix
dev 5 months ago
parent d3cae96ff2
commit cde839dc5d

@ -102,6 +102,16 @@ export const colorPickerMorfo = {
data: [],
aria: []
},
{
name: 'HiddenInput',
kebab: 'hidden-input',
archetype: 'input',
kind: 'public',
defaultElement: 'input',
optional: true,
data: [],
aria: [{ attr: 'aria-hidden', value: v.literal('true') }]
},
{
name: 'Content',
kebab: 'content',

@ -23,6 +23,7 @@ import type { ColorValidator, ColorOnInvalid } from '../color-field/types';
// ── Contract ────────────────────────────────────────────────────────────────
import { colorPickerMorfo } from '../../../morfo/components/color-picker';
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
const attrs = createAttrs(colorPickerMorfo);
@ -151,6 +152,8 @@ export interface ColorPickerOpts
export class ColorPickerProvider {
readonly opts: ColorPickerOpts;
readonly runtimePart: SomaRuntimePart;
readonly soma: Soma;
readonly runtime: SomaRuntime;
static readonly ctx = context<ColorPickerProvider>('ColorPicker');
static get(): ColorPickerProvider | undefined {
return this.ctx.getOr(undefined) as ColorPickerProvider | undefined;
@ -162,7 +165,6 @@ export class ColorPickerProvider {
return new ColorPickerProvider(opts);
}
readonly soma = Soma.get();
readonly field = FieldProvider.get();
triggerNode = $state<HTMLElement | null>(null);
@ -171,14 +173,14 @@ export class ColorPickerProvider {
private constructor(opts: ColorPickerOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('provider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: ColorPickerProvider.ctx
});
this.soma = Soma.require();
this.runtime = this.soma.runtime(colorPickerMorfo, {});
this.runtimePart = this.runtime.part('provider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: ColorPickerProvider.ctx
});
// Fire `onValueChangeEnd` only on committed transitions (drag end / swatch
// click). `onValueChange` fires on every intermediate change via the
@ -282,7 +284,7 @@ export class ColorPickerProvider {
}
langs(idlangref: string): string {
return this.soma?.langs.ts(idlangref) ?? idlangref;
return this.soma.langs.ts(idlangref) ?? idlangref;
}
// ── Root props ──────────────────────────────────────────────────────────
@ -316,15 +318,13 @@ export class ColorPickerLabelProvider {
private constructor(opts: ColorPickerLabelOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('label', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (v) => this.provider.setLabelNode(v)
});
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('label', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (v) => this.provider.setLabelNode(v)
});
}
readonly onclick = () => {
@ -356,10 +356,12 @@ export class ColorPickerControlProvider {
private constructor(opts: ColorPickerControlOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('control', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('control', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly props = $derived.by(() =>
@ -386,15 +388,13 @@ export class ColorPickerTriggerProvider {
private constructor(opts: ColorPickerTriggerOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('trigger', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (v) => this.provider.setTriggerNode(v)
});
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('trigger', {
id: opts.id,
ref: opts.ref,
owner: this,
onRefChange: (v) => this.provider.setTriggerNode(v)
});
}
readonly resolvedLabel = $derived.by(
@ -430,10 +430,12 @@ export class ColorPickerValueSwatchProvider {
private constructor(opts: ColorPickerValueSwatchOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('value-swatch', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('value-swatch', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly backgroundStyle = $derived.by(
@ -465,10 +467,12 @@ export class ColorPickerValueTextProvider {
private constructor(opts: ColorPickerValueTextOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('value-text', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('value-text', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly displayValue = $derived.by(() => {
@ -495,13 +499,13 @@ export class ColorPickerHiddenInputProvider {
readonly provider: ColorPickerProvider;
private constructor(opts: ColorPickerHiddenInputOpts) {
// `input` isn't a registered part — we borrow the root part attr so the
// contract stays minimal (and the element is aria-hidden anyway).
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('provider', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('hidden-input', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly props = $derived.by(() => {
@ -550,15 +554,13 @@ export class ColorPickerAreaProvider {
private constructor(opts: ColorPickerAreaOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('area', {
id: opts.id,
ref: opts.ref,
owner: this,
context: ColorPickerAreaProvider.ctx
});
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('area', {
id: opts.id,
ref: opts.ref,
owner: this,
context: ColorPickerAreaProvider.ctx
});
}
readonly xChannel: ColorChannel = $derived.by(() => this.provider.opts.areaChannels.current.x);
@ -666,10 +668,12 @@ export class ColorPickerAreaBackgroundProvider {
private constructor(opts: ColorPickerAreaBackgroundOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('area-background', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('area-background', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly backgroundStyle: string = $derived.by(
@ -703,11 +707,13 @@ export class ColorPickerAreaThumbProvider {
private constructor(opts: ColorPickerAreaThumbOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('area-thumb', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.area = ColorPickerAreaProvider.require();
this.runtimePart = this.provider.runtime.part('area-thumb', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
/** Keyboard-driven Area editing — both axes respond to arrows. */
@ -849,15 +855,13 @@ export class ColorPickerChannelSliderProvider {
private constructor(opts: ColorPickerChannelSliderOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('channel-slider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: ColorPickerChannelSliderProvider.ctx
});
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('channel-slider', {
id: opts.id,
ref: opts.ref,
owner: this,
context: ColorPickerChannelSliderProvider.ctx
});
}
readonly channel: ColorChannel = $derived.by(() => this.opts.channel.current);
@ -942,10 +946,12 @@ export class ColorPickerChannelSliderTrackProvider {
private constructor(opts: ColorPickerChannelSliderTrackOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('channel-slider-track', { id: opts.id, ref: opts.ref, owner: this });
this.slider = ColorPickerChannelSliderProvider.require();
this.runtimePart = this.slider.provider.runtime.part('channel-slider-track', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly style: string = $derived.by(() => `background: ${this.slider.backgroundStyle};`);
@ -976,11 +982,13 @@ export class ColorPickerChannelSliderThumbProvider {
private constructor(opts: ColorPickerChannelSliderThumbOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('channel-slider-thumb', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.slider = ColorPickerChannelSliderProvider.require();
this.runtimePart = this.provider.runtime.part('channel-slider-thumb', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly onkeydown = (e: SomaKeyboardEvent) => {
@ -1048,9 +1056,12 @@ export class ColorPickerTransparencyGridProvider {
private constructor(opts: ColorPickerTransparencyGridOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('transparency-grid', { id: opts.id, ref: opts.ref, owner: this });
const provider = ColorPickerProvider.require();
this.runtimePart = provider.runtime.part('transparency-grid', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly style: string = $derived.by(() => {
@ -1075,7 +1086,6 @@ export class ColorPickerTransparencyGridProvider {
// Swatches — SwatchGroup, SwatchTrigger, Swatch, SwatchIndicator.
import { parseColor, hsvToHex } from '../../external/colors';
import type { SomaRuntimePart } from '../../runtime.svelte';
export interface ColorPickerSwatchGroupOpts
extends WithRefOpts, ActiveProps<{ ariaLabel: string | undefined }> {}
@ -1091,10 +1101,12 @@ export class ColorPickerSwatchGroupProvider {
private constructor(opts: ColorPickerSwatchGroupOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('swatch-group', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('swatch-group', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly resolvedLabel = $derived.by(
@ -1124,10 +1136,12 @@ export class ColorPickerSwatchTriggerProvider {
private constructor(opts: ColorPickerSwatchTriggerOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('swatch-trigger', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('swatch-trigger', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
/** `true` when this swatch matches the current value by hex comparison. */
@ -1173,9 +1187,12 @@ export class ColorPickerSwatchProvider {
private constructor(opts: ColorPickerSwatchOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('swatch', { id: opts.id, ref: opts.ref, owner: this });
const provider = ColorPickerProvider.require();
this.runtimePart = provider.runtime.part('swatch', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly effectiveColor: string = $derived.by(() => this.opts.color.current ?? '');
@ -1201,9 +1218,12 @@ export class ColorPickerSwatchIndicatorProvider {
private constructor(opts: ColorPickerSwatchIndicatorOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('swatch-indicator', { id: opts.id, ref: opts.ref, owner: this });
const provider = ColorPickerProvider.require();
this.runtimePart = provider.runtime.part('swatch-indicator', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly props = $derived.by(() =>
@ -1235,10 +1255,12 @@ export class ColorPickerEyeDropperProvider {
private constructor(opts: ColorPickerEyeDropperOpts) {
this.opts = opts;
this.runtimePart = Soma.require()
.runtime(colorPickerMorfo, {})
.part('eye-dropper', { id: opts.id, ref: opts.ref, owner: this });
this.provider = ColorPickerProvider.require();
this.runtimePart = this.provider.runtime.part('eye-dropper', {
id: opts.id,
ref: opts.ref,
owner: this
});
}
readonly isSupported: boolean =

Loading…
Cancel
Save

Powered by TurnKey Linux.