diff --git a/bubbles.go b/bubbles.go index 9b9e8d46..41199354 100644 --- a/bubbles.go +++ b/bubbles.go @@ -1 +1,15 @@ package bubbles + +// Styler represents an interface for styling bubbles. +type Styler[T any] interface { + Styles(isDark bool) T +} + +// StylerFunc is a function type that implements the Styler interface. +type StylerFunc[T any] func(isDark bool) T + +// Styles calls the function. +// It implements the Styler interface. +func (f StylerFunc[T]) Styles(isDark bool) T { + return f(isDark) +} diff --git a/help/help.go b/help/help.go index d9e814be..2d1201fd 100644 --- a/help/help.go +++ b/help/help.go @@ -41,7 +41,8 @@ type Styles struct { FullSeparator lipgloss.Style } -func newStyles(isDark bool) Styles { +// DefaultStyles returns a set of default styles for the help bubble. +func DefaultStyles(isDark bool) Styles { lightDark := lipgloss.LightDark(isDark) keyStyle := lipgloss.NewStyle().Foreground(lightDark("#909090", "#626262")) @@ -59,16 +60,6 @@ func newStyles(isDark bool) Styles { } } -// DefaultDarkStyles returns a set of default styles for dark backgrounds. -func DefaultDarkStyles() Styles { - return newStyles(true) -} - -// DefaultLightStyles returns a set of default styles for light backgrounds. -func DefaultLightStyles() Styles { - return newStyles(false) -} - // Model contains the state of the help view. type Model struct { Width int @@ -85,12 +76,12 @@ type Model struct { } // New creates a new help view with some useful defaults. -func New() Model { +func New(isDark bool) Model { return Model{ ShortSeparator: " • ", FullSeparator: " ", Ellipsis: "…", - Styles: DefaultDarkStyles(), + Styles: DefaultStyles(isDark), } } diff --git a/help/help_test.go b/help/help_test.go index 9214e0fe..a76c3db6 100644 --- a/help/help_test.go +++ b/help/help_test.go @@ -10,7 +10,7 @@ import ( ) func TestFullHelp(t *testing.T) { - m := New() + m := New(true) m.FullSeparator = " | " k := key.WithKeys("x") kb := [][]key.Binding{ diff --git a/list/defaultitem.go b/list/defaultitem.go index e28d1a02..6a417a8e 100644 --- a/list/defaultitem.go +++ b/list/defaultitem.go @@ -94,16 +94,14 @@ type DefaultDelegate struct { } // NewDefaultDelegate creates a new delegate with default styles. -func NewDefaultDelegate() DefaultDelegate { +func NewDefaultDelegate(isDark bool) DefaultDelegate { const defaultHeight = 2 const defaultSpacing = 1 return DefaultDelegate{ ShowDescription: true, - // XXX: Let the user choose between light and dark colors. We've - // temporarily hardcoded the dark colors here. - Styles: NewDefaultItemStyles(true), - height: defaultHeight, - spacing: defaultSpacing, + Styles: NewDefaultItemStyles(isDark), + height: defaultHeight, + spacing: defaultSpacing, } } diff --git a/list/list.go b/list/list.go index 671e1532..f802b8a9 100644 --- a/list/list.go +++ b/list/list.go @@ -196,10 +196,8 @@ type Model struct { } // New returns a new model with sensible defaults. -func New(items []Item, delegate ItemDelegate, width, height int) Model { - // XXX: Let the user choose between light and dark colors. We've - // temporarily hardcoded the dark colors here. - styles := DefaultStyles(true) +func New(items []Item, delegate ItemDelegate, width, height int, isDark bool) Model { + styles := DefaultStyles(isDark) sp := spinner.New() sp.Spinner = spinner.Line @@ -239,7 +237,7 @@ func New(items []Item, delegate ItemDelegate, width, height int) Model { items: items, Paginator: p, spinner: sp, - Help: help.New(), + Help: help.New(isDark), } m.updatePagination() diff --git a/list/list_test.go b/list/list_test.go index d1d8524b..e1f78e76 100644 --- a/list/list_test.go +++ b/list/list_test.go @@ -30,7 +30,7 @@ func (d itemDelegate) Render(w io.Writer, m Model, index int, listItem Item) { } func TestStatusBarItemName(t *testing.T) { - list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10) + list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10, true) expected := "2 items" if !strings.Contains(list.statusView(), expected) { t.Fatalf("Error: expected view to contain %s", expected) @@ -44,7 +44,7 @@ func TestStatusBarItemName(t *testing.T) { } func TestStatusBarWithoutItems(t *testing.T) { - list := New([]Item{}, itemDelegate{}, 10, 10) + list := New([]Item{}, itemDelegate{}, 10, 10, true) expected := "No items" if !strings.Contains(list.statusView(), expected) { @@ -53,7 +53,7 @@ func TestStatusBarWithoutItems(t *testing.T) { } func TestCustomStatusBarItemName(t *testing.T) { - list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10) + list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10, true) list.SetStatusBarItemName("connection", "connections") expected := "2 connections" @@ -77,7 +77,7 @@ func TestCustomStatusBarItemName(t *testing.T) { func TestSetFilterText(t *testing.T) { tc := []Item{item("foo"), item("bar"), item("baz")} - list := New(tc, itemDelegate{}, 10, 10) + list := New(tc, itemDelegate{}, 10, 10, true) list.SetFilterText("ba") list.SetFilterState(Unfiltered) @@ -102,7 +102,7 @@ func TestSetFilterText(t *testing.T) { func TestSetFilterState(t *testing.T) { tc := []Item{item("foo"), item("bar"), item("baz")} - list := New(tc, itemDelegate{}, 10, 10) + list := New(tc, itemDelegate{}, 10, 10, true) list.SetFilterText("ba") list.SetFilterState(Unfiltered) diff --git a/textarea/textarea.go b/textarea/textarea.go index 71694a32..a3ec8b71 100644 --- a/textarea/textarea.go +++ b/textarea/textarea.go @@ -283,12 +283,12 @@ type Model struct { } // New creates a new model with default settings. -func New() Model { +func New(isDark bool) Model { vp := viewport.New(0, 0) vp.KeyMap = viewport.KeyMap{} cur := cursor.New() - styles := DefaultStyles(true) + styles := DefaultStyles(isDark) m := Model{ CharLimit: defaultCharLimit, diff --git a/textarea/textarea_test.go b/textarea/textarea_test.go index 15722653..3f3a643b 100644 --- a/textarea/textarea_test.go +++ b/textarea/textarea_test.go @@ -1703,7 +1703,7 @@ func TestView(t *testing.T) { } func newTextArea() Model { - textarea := New() + textarea := New(true) textarea.Prompt = "> " textarea.Placeholder = "Hello, World!"