@ -16,9 +16,11 @@
import { colorFieldMorfo } from '@/uix/morfo/components/color-field';
import { popoverMorfo } from '@/uix/morfo/components/popover';
import { getActiveUix } from '$active-uix';
import { ActiveEidos } from '$uix/eidos';
import { colorValueFromRgb , type ColorValue , type ColorFormat } from '$libs/color';
const uix = getActiveUix();
const eidos = ActiveEidos.require();
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
type TraceEntry = { event : string ; family : string ; intent? : string ; at : number } ;
@ -191,42 +193,23 @@
});
// SwatchTrigger commits a parsed ColorValue, so a raw `var(--token)` can't be
// passed — resolve each token to its computed rgb() via a hidden probe. Re-run
// when :root theme attrs change so System/Intent swatches follow retints
// passed. Resolve each token to a concrete sRGB hex via the eidos colour engine
// (config + `$color`) — pure JS, NO DOM probe, so no forced reflow. Re-resolve
// when the :root theme attrs change so System/Intent swatches follow retints
// (palette scales are theme-independent but re-resolve cheaply too).
let resolvedTokens = $state< Record < string , string > >({} );
$effect(() => {
const doc = uix.dom?.getDocument?.() ?? document;
const win = uix.dom?.getWindow?.() ?? window;
if (!doc?.body) return;
const probe = doc.createElement('span');
probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none';
doc.body.appendChild(probe);
const reprobe = () => {
const next: Record< string , string > = {} ;
for (const token of presetTokens) {
// Scale tokens resolve to an oklch() sibling the color parser can't read.
// color-mix(in srgb) coerces to the sRGB gamut; serialize to rgb() so the
// SwatchTrigger can both display AND commit (parse) the value.
probe.style.color = `color-mix(in srgb, var(${ token } ), var(${ token } ))`;
const computed = win.getComputedStyle(probe).color;
const srgb = computed.match(/srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)/);
next[token] = srgb
? `rgb(${ Math . round ( + srgb [ 1 ] * 255 )} , ${ Math . round ( + srgb [ 2 ] * 255 )} , ${ Math . round ( + srgb [ 3 ] * 255 )} )`
: computed;
}
resolvedTokens = next;
const resolve = () => {
resolvedTokens = eidos.resolveTokens(presetTokens);
};
reprob e();
const themeObs = new MutationObserver(reprob e);
resolve();
const themeObs = new MutationObserver(resolve);
themeObs.observe(doc.documentElement, {
attributes: true,
attributeFilter: ['class', 'style', 'data-theme', 'data-uix-theme']
attributeFilter: ['class', 'style', 'data-theme', 'data-mode', 'data-uix-theme']
});
return () => {
themeObs.disconnect();
probe.remove();
};
return () => themeObs.disconnect();
});
const valueLabel = $derived(value?.hex ?? 'empty');
@ -277,8 +260,7 @@
showSwatches & & ' < ColorPicker.SavedSwatches / > ',
' < / PickerShell.Body > ',
showFooter & & ' < PickerShell.Footer > ',
showFooter & &
' < ColorPicker.SaveAction / > ',
showFooter & & ' < ColorPicker.SaveAction / > ',
showFooter & & showClear & & ' < PickerShell.Clear / > ',
showFooter & & showCancel & & ' < PickerShell.Cancel / > ',
showFooter & & showClose & & ' < PickerShell.Close / > ',
@ -334,8 +316,7 @@
showSwatches & & ' < ColorPicker.SavedSwatches / > ',
' < / PickerShell.Body > ',
showFooter & & ' < ColorPicker.Footer > ',
showFooter & &
' < ColorPicker.SaveAction / > ',
showFooter & & ' < ColorPicker.SaveAction / > ',
showFooter & & showClear & & ' < ColorPicker.Clear / > ',
showFooter & & showCancel & & ' < ColorPicker.Cancel / > ',
showFooter & & showClose & & ' < ColorPicker.Close / > ',
@ -421,12 +402,7 @@
< ColorPicker.Portal >
< ColorPicker.Content >
< PickerShell.Body >
< Tabs
variant="segmented"
fitted
{ size }
bind:value={ pickerTab }
>
< Tabs variant = "segmented" fitted { size } bind:value = { pickerTab } >
< Tabs.List aria-label = "Vistas del selector de color" >
< Tabs.Trigger value = "selection" > Selección< / Tabs.Trigger >
< Tabs.Trigger value = "presets" > Presets< / Tabs.Trigger >
@ -522,6 +498,7 @@
{ #if showFooter }
< ColorPicker.Footer >
< ColorPicker.SaveAction / >
{ #if showClear } < ColorPicker.Clear /> { /if }
{ #if showCancel } < ColorPicker.Cancel /> { /if }
{ #if showClose } < ColorPicker.Close /> { /if }