Skip to content

Commit 8fdc81c

Browse files
committed
feat: add a Styler interface for styling bubbles
This change introduces a Styler interface that allows users to define custom styles for bubbles. The interface is implemented by the StylerFunc type, which is a function type that takes a boolean argument and returns a value of any type. This allows a user to define a custom StylerFunc that returns a custom style for a bubble based on the background color of the terminal.
1 parent db64e3c commit 8fdc81c

File tree

8 files changed

+34
-33
lines changed

8 files changed

+34
-33
lines changed

bubbles.go

+14
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
11
package bubbles
2+
3+
// Styler represents an interface for styling bubbles.
4+
type Styler[T any] interface {
5+
Styles(isDark bool) T
6+
}
7+
8+
// StylerFunc is a function type that implements the Styler interface.
9+
type StylerFunc[T any] func(isDark bool) T
10+
11+
// Styles calls the function.
12+
// It implements the Styler interface.
13+
func (f StylerFunc[T]) Styles(isDark bool) T {
14+
return f(isDark)
15+
}

help/help.go

+4-13
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ type Styles struct {
4141
FullSeparator lipgloss.Style
4242
}
4343

44-
func newStyles(isDark bool) Styles {
44+
// DefaultStyles returns a set of default styles for the help bubble.
45+
func DefaultStyles(isDark bool) Styles {
4546
lightDark := lipgloss.LightDark(isDark)
4647

4748
keyStyle := lipgloss.NewStyle().Foreground(lightDark("#909090", "#626262"))
@@ -59,16 +60,6 @@ func newStyles(isDark bool) Styles {
5960
}
6061
}
6162

62-
// DefaultDarkStyles returns a set of default styles for dark backgrounds.
63-
func DefaultDarkStyles() Styles {
64-
return newStyles(true)
65-
}
66-
67-
// DefaultLightStyles returns a set of default styles for light backgrounds.
68-
func DefaultLightStyles() Styles {
69-
return newStyles(false)
70-
}
71-
7263
// Model contains the state of the help view.
7364
type Model struct {
7465
Width int
@@ -85,12 +76,12 @@ type Model struct {
8576
}
8677

8778
// New creates a new help view with some useful defaults.
88-
func New() Model {
79+
func New(isDark bool) Model {
8980
return Model{
9081
ShortSeparator: " • ",
9182
FullSeparator: " ",
9283
Ellipsis: "…",
93-
Styles: DefaultDarkStyles(),
84+
Styles: DefaultStyles(isDark),
9485
}
9586
}
9687

help/help_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
)
1111

1212
func TestFullHelp(t *testing.T) {
13-
m := New()
13+
m := New(true)
1414
m.FullSeparator = " | "
1515
k := key.WithKeys("x")
1616
kb := [][]key.Binding{

list/defaultitem.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,14 @@ type DefaultDelegate struct {
9494
}
9595

9696
// NewDefaultDelegate creates a new delegate with default styles.
97-
func NewDefaultDelegate() DefaultDelegate {
97+
func NewDefaultDelegate(isDark bool) DefaultDelegate {
9898
const defaultHeight = 2
9999
const defaultSpacing = 1
100100
return DefaultDelegate{
101101
ShowDescription: true,
102-
// XXX: Let the user choose between light and dark colors. We've
103-
// temporarily hardcoded the dark colors here.
104-
Styles: NewDefaultItemStyles(true),
105-
height: defaultHeight,
106-
spacing: defaultSpacing,
102+
Styles: NewDefaultItemStyles(isDark),
103+
height: defaultHeight,
104+
spacing: defaultSpacing,
107105
}
108106
}
109107

list/list.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,8 @@ type Model struct {
196196
}
197197

198198
// New returns a new model with sensible defaults.
199-
func New(items []Item, delegate ItemDelegate, width, height int) Model {
200-
// XXX: Let the user choose between light and dark colors. We've
201-
// temporarily hardcoded the dark colors here.
202-
styles := DefaultStyles(true)
199+
func New(items []Item, delegate ItemDelegate, width, height int, isDark bool) Model {
200+
styles := DefaultStyles(isDark)
203201

204202
sp := spinner.New()
205203
sp.Spinner = spinner.Line
@@ -239,7 +237,7 @@ func New(items []Item, delegate ItemDelegate, width, height int) Model {
239237
items: items,
240238
Paginator: p,
241239
spinner: sp,
242-
Help: help.New(),
240+
Help: help.New(isDark),
243241
}
244242

245243
m.updatePagination()

list/list_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (d itemDelegate) Render(w io.Writer, m Model, index int, listItem Item) {
3030
}
3131

3232
func TestStatusBarItemName(t *testing.T) {
33-
list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10)
33+
list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10, true)
3434
expected := "2 items"
3535
if !strings.Contains(list.statusView(), expected) {
3636
t.Fatalf("Error: expected view to contain %s", expected)
@@ -44,7 +44,7 @@ func TestStatusBarItemName(t *testing.T) {
4444
}
4545

4646
func TestStatusBarWithoutItems(t *testing.T) {
47-
list := New([]Item{}, itemDelegate{}, 10, 10)
47+
list := New([]Item{}, itemDelegate{}, 10, 10, true)
4848

4949
expected := "No items"
5050
if !strings.Contains(list.statusView(), expected) {
@@ -53,7 +53,7 @@ func TestStatusBarWithoutItems(t *testing.T) {
5353
}
5454

5555
func TestCustomStatusBarItemName(t *testing.T) {
56-
list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10)
56+
list := New([]Item{item("foo"), item("bar")}, itemDelegate{}, 10, 10, true)
5757
list.SetStatusBarItemName("connection", "connections")
5858

5959
expected := "2 connections"
@@ -77,7 +77,7 @@ func TestCustomStatusBarItemName(t *testing.T) {
7777
func TestSetFilterText(t *testing.T) {
7878
tc := []Item{item("foo"), item("bar"), item("baz")}
7979

80-
list := New(tc, itemDelegate{}, 10, 10)
80+
list := New(tc, itemDelegate{}, 10, 10, true)
8181
list.SetFilterText("ba")
8282

8383
list.SetFilterState(Unfiltered)
@@ -102,7 +102,7 @@ func TestSetFilterText(t *testing.T) {
102102
func TestSetFilterState(t *testing.T) {
103103
tc := []Item{item("foo"), item("bar"), item("baz")}
104104

105-
list := New(tc, itemDelegate{}, 10, 10)
105+
list := New(tc, itemDelegate{}, 10, 10, true)
106106
list.SetFilterText("ba")
107107

108108
list.SetFilterState(Unfiltered)

textarea/textarea.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -283,12 +283,12 @@ type Model struct {
283283
}
284284

285285
// New creates a new model with default settings.
286-
func New() Model {
286+
func New(isDark bool) Model {
287287
vp := viewport.New(0, 0)
288288
vp.KeyMap = viewport.KeyMap{}
289289
cur := cursor.New()
290290

291-
styles := DefaultStyles(true)
291+
styles := DefaultStyles(isDark)
292292

293293
m := Model{
294294
CharLimit: defaultCharLimit,

textarea/textarea_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1703,7 +1703,7 @@ func TestView(t *testing.T) {
17031703
}
17041704

17051705
func newTextArea() Model {
1706-
textarea := New()
1706+
textarea := New(true)
17071707

17081708
textarea.Prompt = "> "
17091709
textarea.Placeholder = "Hello, World!"

0 commit comments

Comments
 (0)