mirror of
https://github.com/zoriya/bubbles.git
synced 2026-08-05 04:36:07 +00:00
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.
This commit is contained in:
+14
@@ -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)
|
||||
}
|
||||
|
||||
+4
-13
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestFullHelp(t *testing.T) {
|
||||
m := New()
|
||||
m := New(true)
|
||||
m.FullSeparator = " | "
|
||||
k := key.WithKeys("x")
|
||||
kb := [][]key.Binding{
|
||||
|
||||
+4
-6
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -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()
|
||||
|
||||
+5
-5
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1703,7 +1703,7 @@ func TestView(t *testing.T) {
|
||||
}
|
||||
|
||||
func newTextArea() Model {
|
||||
textarea := New()
|
||||
textarea := New(true)
|
||||
|
||||
textarea.Prompt = "> "
|
||||
textarea.Placeholder = "Hello, World!"
|
||||
|
||||
Reference in New Issue
Block a user