|
|
|
|
@ -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 =
|
|
|
|
|
|