From 4b7fe0d58402c7ad112f3c4fc5983d81cb037b5f Mon Sep 17 00:00:00 2001 From: Snider Date: Thu, 23 Jul 2026 17:07:19 +0100 Subject: [PATCH] =?UTF-8?q?feat(display/tui/style):=20AdaptiveColor=20?= =?UTF-8?q?=E2=80=94=20the=20light/dark=20pair=20lipgloss=20v2=20dropped?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lipgloss v2 removed the v1 AdaptiveColor type (implicit light/dark adaptation) in favour of an explicit isDark resolve. This restores the paired shape as data — AdaptiveColor{Light, Dark string} + Resolve(isDark) delegating to NewLightDark — so a consumer's theme keeps its v1 shape and adds one resolve step per frame. Unblocks go-inference cli/tui's charm-free migration (10-field theme, 22 paint sites). One test per variant + an Example. Co-Authored-By: Virgil --- go/display/tui/style/color.go | 18 +++++++++++++++ go/display/tui/style/color_test.go | 33 ++++++++++++++++++++++++++++ go/display/tui/style/example_test.go | 12 ++++++++++ 3 files changed, 63 insertions(+) create mode 100644 go/display/tui/style/color_test.go diff --git a/go/display/tui/style/color.go b/go/display/tui/style/color.go index d075f17..a3951bb 100644 --- a/go/display/tui/style/color.go +++ b/go/display/tui/style/color.go @@ -21,3 +21,21 @@ type LightDark = lipgloss.LightDarkFunc // NewLightDark builds a LightDark chooser for the given background. func NewLightDark(isDark bool) LightDark { return lipgloss.LightDark(isDark) } + +// AdaptiveColor pairs a light-background and a dark-background colour for one +// role, resolved once the terminal background is known — the render-time +// replacement for lipgloss v1's implicit adaptation, which v2 removed. A theme +// keeps the pair as data and resolves it per frame, e.g. +// +// accent := style.AdaptiveColor{Light: "#2e5cc5", Dark: "#7aa2f7"} +// st := style.New().Foreground(accent.Resolve(isDark)) +type AdaptiveColor struct { + Light, Dark string +} + +// Resolve returns the Light Paint on a light terminal and the Dark Paint on a +// dark one, delegating to NewLightDark so it matches every other light/dark +// choice in the package. +func (a AdaptiveColor) Resolve(isDark bool) Paint { + return NewLightDark(isDark)(Color(a.Light), Color(a.Dark)) +} diff --git a/go/display/tui/style/color_test.go b/go/display/tui/style/color_test.go new file mode 100644 index 0000000..9d2acb2 --- /dev/null +++ b/go/display/tui/style/color_test.go @@ -0,0 +1,33 @@ +package style_test + +import ( + "testing" + + "dappco.re/go/html/display/tui/style" +) + +func TestAdaptiveColor_Resolve_PicksDarkOnADarkTerminal(t *testing.T) { + c := style.AdaptiveColor{Light: "#000000", Dark: "#ffffff"} + + r, g, b, _ := c.Resolve(true).RGBA() + if r != 0xffff || g != 0xffff || b != 0xffff { + t.Fatalf("Resolve(isDark=true) = %d,%d,%d, want the Dark colour white (65535,65535,65535)", r, g, b) + } +} + +func TestAdaptiveColor_Resolve_PicksLightOnALightTerminal(t *testing.T) { + c := style.AdaptiveColor{Light: "#000000", Dark: "#ffffff"} + + r, g, b, _ := c.Resolve(false).RGBA() + if r != 0 || g != 0 || b != 0 { + t.Fatalf("Resolve(isDark=false) = %d,%d,%d, want the Light colour black (0,0,0)", r, g, b) + } +} + +func TestAdaptiveColor_Resolve_ZeroValueResolvesWithoutPanicking(t *testing.T) { + var c style.AdaptiveColor // both fields empty — an unset theme role + + if got := c.Resolve(true); got == nil { + t.Fatal("Resolve on a zero AdaptiveColor returned a nil Paint, want a non-nil no-colour") + } +} diff --git a/go/display/tui/style/example_test.go b/go/display/tui/style/example_test.go index cd03791..9849e4c 100644 --- a/go/display/tui/style/example_test.go +++ b/go/display/tui/style/example_test.go @@ -32,3 +32,15 @@ func ExampleBlend1D() { // Output: // true } + +// ExampleAdaptiveColor_Resolve keeps one light/dark colour pair and resolves it +// for a dark terminal — the per-frame replacement for lipgloss v1's implicit +// AdaptiveColor, which v2 removed. +func ExampleAdaptiveColor_Resolve() { + accent := style.AdaptiveColor{Light: "#000000", Dark: "#ffffff"} + + r, g, b, _ := accent.Resolve(true).RGBA() + fmt.Printf("%d %d %d\n", r, g, b) + // Output: + // 65535 65535 65535 +}