bubble.go

 1package selection
 2
 3import (
 4	tea "github.com/charmbracelet/bubbletea"
 5	"github.com/charmbracelet/lipgloss"
 6)
 7
 8type SelectedMsg struct {
 9	Name  string
10	Index int
11}
12
13type ActiveMsg struct {
14	Name  string
15	Index int
16}
17
18type Bubble struct {
19	NormalStyle   lipgloss.Style
20	SelectedStyle lipgloss.Style
21	Items         []string
22	selectedItem  int
23}
24
25func NewBubble(items []string) *Bubble {
26	return &Bubble{
27		NormalStyle:   normalStyle,
28		SelectedStyle: selectedStyle,
29		Items:         items,
30	}
31}
32
33func (b *Bubble) Init() tea.Cmd {
34	return nil
35}
36
37func (b *Bubble) View() string {
38	s := ""
39	for i, item := range b.Items {
40		if i == b.selectedItem {
41			s += b.SelectedStyle.Render(item) + "\n"
42		} else {
43			s += b.NormalStyle.Render(item) + "\n"
44		}
45	}
46	return s
47}
48
49func (b *Bubble) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
50	cmds := make([]tea.Cmd, 0)
51	switch msg := msg.(type) {
52	case tea.KeyMsg:
53		switch msg.String() {
54		case "k", "up":
55			if b.selectedItem > 0 {
56				b.selectedItem--
57				cmds = append(cmds, b.sendActiveMessage)
58			}
59		case "j", "down":
60			if b.selectedItem < len(b.Items)-1 {
61				b.selectedItem++
62				cmds = append(cmds, b.sendActiveMessage)
63			}
64		case "enter":
65			cmds = append(cmds, b.sendSelectedMessage)
66		}
67	}
68	return b, tea.Batch(cmds...)
69}
70
71func (b *Bubble) sendActiveMessage() tea.Msg {
72	if b.selectedItem >= 0 && b.selectedItem < len(b.Items) {
73		return ActiveMsg{
74			Name:  b.Items[b.selectedItem],
75			Index: b.selectedItem,
76		}
77	}
78	return nil
79}
80
81func (b *Bubble) sendSelectedMessage() tea.Msg {
82	if b.selectedItem >= 0 && b.selectedItem < len(b.Items) {
83		return SelectedMsg{
84			Name:  b.Items[b.selectedItem],
85			Index: b.selectedItem,
86		}
87	}
88	return nil
89}