From e16c169f3728467b6f05bd699e1a1ad732b752c7 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 18 Jun 2026 00:12:40 +0200 Subject: [PATCH] feat(eidos): color-field leading value swatch + full-width coherence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - renders an opt-in leading colour chip showing the field's current value, sized to the control icon (--icon-size-{size}) via a concrete token — never 1em, so it cannot recompute/jitter. - field-segment-state: drop the active-segment font-weight 600; bold widened the ch-based segment ~0.5px, resizing the highlight on every increment. The accent background already marks the active segment. - color-field stays full-width like the whole field/select family — width is container-driven, not field-driven (no per-component exception). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../color-field/color-field-input.svelte | 5 ++++- .../components/color-field/color-field.css | 17 +++++++++++++++++ .../components/color-field/color-field.svelte | 11 +++++++++++ src/uix/eidos/components/color-field/types.ts | 6 +++++- .../components/field/field-segment-state.css | 4 +++- src/uix/eidos/generated/base.css | 10 +++++----- src/uix/eidos/lib/recipes/base.ts | 13 ++++++++----- .../uix/components/color-field/+page.svelte | 2 +- 8 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/uix/eidos/components/color-field/color-field-input.svelte b/src/uix/eidos/components/color-field/color-field-input.svelte index ddaf750e5..91cf638ec 100644 --- a/src/uix/eidos/components/color-field/color-field-input.svelte +++ b/src/uix/eidos/components/color-field/color-field-input.svelte @@ -2,11 +2,14 @@ import * as ColorField from '$soma/components/color-field'; import type { ColorFieldInputProps, ColorFieldInputSnippetProps } from './types'; - let { children: bodyContent, ...rest }: ColorFieldInputProps = $props(); + let { children: bodyContent, swatch = false, ...rest }: ColorFieldInputProps = $props(); {#snippet children(args: ColorFieldInputSnippetProps)} + {#if swatch} + + {/if} {@render bodyContent?.(args)} {/snippet} diff --git a/src/uix/eidos/components/color-field/color-field.css b/src/uix/eidos/components/color-field/color-field.css index fdab3b2d3..7ad470687 100644 --- a/src/uix/eidos/components/color-field/color-field.css +++ b/src/uix/eidos/components/color-field/color-field.css @@ -182,6 +182,23 @@ min-inline-size: calc(6ch + 2 * var(--_color-field-segment-px)); } +/* Leading value swatch (opt-in via ). Sized to the + control icon for this field size via the `--_color-field-swatch-size` token + (= `--icon-size-{size}`) — a CONCRETE length, not `1em`, so it can never + recompute/jitter on re-render. The colour comes from --cf-swatch-color, set + on the root from the field value. Inset border keeps light colours visible. */ +[data-color-field-swatch] { + flex: 0 0 auto; + inline-size: var(--_color-field-swatch-size); + block-size: var(--_color-field-swatch-size); + /* Shares the field's own corner radius token (no hand-rolled calc) so it + tracks the field and reads as part of the same control. */ + border-radius: var(--color-field-radius); + background: var(--cf-swatch-color, transparent); + box-shadow: inset 0 0 0 var(--border-width) var(--color-border-subtle); + margin-inline-end: var(--_color-field-segment-px); +} + [data-color-field-segment][data-placeholder] { color: var(--color-field-placeholder-color); } diff --git a/src/uix/eidos/components/color-field/color-field.svelte b/src/uix/eidos/components/color-field/color-field.svelte index 203e0e567..3d6d04d5d 100644 --- a/src/uix/eidos/components/color-field/color-field.svelte +++ b/src/uix/eidos/components/color-field/color-field.svelte @@ -11,12 +11,22 @@ value = $bindable(), placeholder = $bindable(), format = $bindable(), + style, children: bodyContent, ...rest }: ColorFieldProps = $props(); const eidos = ActiveEidos.require(); const resolvedSize = $derived(eidos.resolve(size, 'md')); + // Publish the current colour as a CSS var on the root so a leading + // can preview it (inherits the var). Falls back to + // the placeholder colour, else unset (swatch renders transparent). + const swatchColor = $derived(value?.hex ?? placeholder?.hex); + const rootStyle = $derived( + [style, swatchColor && `--cf-swatch-color: ${swatchColor}`] + .filter(Boolean) + .join('; ') || undefined + ); {#if showLabel}{labelText}{/if} - + {#snippet children({ segments }: InputSnippetProps)} {#each segments as { part, value }, index (`${part}-${index}`)} {value}