mirror of
https://github.com/Maks1mS/bubbles.git
synced 2025-10-19 00:49:54 +03:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
34cd93d6b5 |
@@ -36,6 +36,11 @@ the common, and many customization options.
|
|||||||
* [Example code, many fields](https://github.com/charmbracelet/tea/tree/master/examples/textinputs/main.go)
|
* [Example code, many fields](https://github.com/charmbracelet/tea/tree/master/examples/textinputs/main.go)
|
||||||
|
|
||||||
|
|
||||||
|
## Button
|
||||||
|
|
||||||
|
A button component.
|
||||||
|
|
||||||
|
|
||||||
## Paginator
|
## Paginator
|
||||||
|
|
||||||
<img src="https://stuff.charm.sh/bubbles-examples/pagination.gif" width="200" alt="Paginator Example">
|
<img src="https://stuff.charm.sh/bubbles-examples/pagination.gif" width="200" alt="Paginator Example">
|
||||||
|
90
button/button.go
Normal file
90
button/button.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package button
|
||||||
|
|
||||||
|
import (
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/muesli/termenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// color is a helper for returning colors.
|
||||||
|
color func(s string) termenv.Color = termenv.ColorProfile().Color
|
||||||
|
)
|
||||||
|
|
||||||
|
// Model is the Bubble Tea model for a button element.
|
||||||
|
type Model struct {
|
||||||
|
Err error
|
||||||
|
|
||||||
|
Label string
|
||||||
|
Default bool
|
||||||
|
|
||||||
|
TextColor string
|
||||||
|
BackgroundColor string
|
||||||
|
FocusedTextColor string
|
||||||
|
FocusedBackgroundColor string
|
||||||
|
|
||||||
|
// Focus indicates whether user focus should be on this button component
|
||||||
|
focus bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewModel creates a new model with default settings.
|
||||||
|
func NewModel() Model {
|
||||||
|
return Model{
|
||||||
|
Label: "Button",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update is the Tea update loop.
|
||||||
|
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||||
|
if !m.focus {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch msg.String() {
|
||||||
|
case "enter":
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// View renders the button in its current state.
|
||||||
|
func (m Model) View() string {
|
||||||
|
margin := m.styled(" ").String()
|
||||||
|
label := m.styled(m.Label)
|
||||||
|
if m.Default {
|
||||||
|
label = label.Underline()
|
||||||
|
}
|
||||||
|
|
||||||
|
return margin + label.String() + margin
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focused returns the focus state on the model.
|
||||||
|
func (m Model) Focused() bool {
|
||||||
|
return m.focus
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus sets the focus state on the model.
|
||||||
|
func (m *Model) Focus() {
|
||||||
|
m.focus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blur removes the focus state on the model.
|
||||||
|
func (m *Model) Blur() {
|
||||||
|
m.focus = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Model) styled(s string) termenv.Style {
|
||||||
|
view := termenv.String(s)
|
||||||
|
if m.focus {
|
||||||
|
view = view.Foreground(color(m.FocusedTextColor)).
|
||||||
|
Background(color(m.FocusedBackgroundColor))
|
||||||
|
} else {
|
||||||
|
view = view.Foreground(color(m.TextColor)).
|
||||||
|
Background(color(m.BackgroundColor))
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
@@ -1,118 +0,0 @@
|
|||||||
package layouts
|
|
||||||
|
|
||||||
import (
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Model is the Bubble Tea model for a vertical layout element.
|
|
||||||
type Model struct {
|
|
||||||
Index int
|
|
||||||
Items []tea.Model
|
|
||||||
|
|
||||||
// Focus indicates whether user focus should be on this component
|
|
||||||
focus bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type FocusItem interface {
|
|
||||||
Focus() tea.Model
|
|
||||||
Blur() tea.Model
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewModel creates a new model with default settings.
|
|
||||||
func NewModel() Model {
|
|
||||||
return Model{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update is the Tea update loop.
|
|
||||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
|
||||||
if !m.focus {
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case tea.KeyMsg:
|
|
||||||
switch msg.String() {
|
|
||||||
case "shift+tab", "up":
|
|
||||||
m.Index--
|
|
||||||
if m.Index < 0 {
|
|
||||||
m.Index = len(m.Items) - 1
|
|
||||||
}
|
|
||||||
m.updateFocus()
|
|
||||||
|
|
||||||
case "tab", "down":
|
|
||||||
m.Index++
|
|
||||||
if m.Index >= len(m.Items) {
|
|
||||||
m.Index = 0
|
|
||||||
}
|
|
||||||
m.updateFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := m.updateItems(msg)
|
|
||||||
return m, cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// View renders the layout in its current state.
|
|
||||||
func (m Model) View() string {
|
|
||||||
var view string
|
|
||||||
|
|
||||||
for _, v := range m.Items {
|
|
||||||
if mi, ok := v.(tea.Model); ok {
|
|
||||||
view += mi.View() + "\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) updateFocus() {
|
|
||||||
for i, v := range m.Items {
|
|
||||||
if m.Index == i {
|
|
||||||
if fi, ok := v.(FocusItem); ok {
|
|
||||||
// new focused item
|
|
||||||
m.Items[i] = fi.Focus()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if fi, ok := v.(FocusItem); ok {
|
|
||||||
m.Items[i] = fi.Blur()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass messages and models through to text input components. Only text inputs
|
|
||||||
// with Focus() set will respond, so it's safe to simply update all of them
|
|
||||||
// here without any further logic.
|
|
||||||
func (m *Model) updateItems(msg tea.Msg) tea.Cmd {
|
|
||||||
var (
|
|
||||||
cmd tea.Cmd
|
|
||||||
cmds []tea.Cmd
|
|
||||||
)
|
|
||||||
|
|
||||||
for i, v := range m.Items {
|
|
||||||
if mi, ok := v.(tea.Model); ok {
|
|
||||||
m.Items[i], cmd = mi.Update(msg)
|
|
||||||
if cmd != nil {
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tea.Batch(cmds...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Focused returns the focus state on the model.
|
|
||||||
func (m Model) Focused() bool {
|
|
||||||
return m.focus
|
|
||||||
}
|
|
||||||
|
|
||||||
// Focus sets the focus state on the model.
|
|
||||||
func (m *Model) Focus() {
|
|
||||||
m.focus = true
|
|
||||||
m.updateFocus()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blur removes the focus state on the model.
|
|
||||||
func (m *Model) Blur() {
|
|
||||||
m.focus = false
|
|
||||||
}
|
|
@@ -67,7 +67,6 @@ type Model struct {
|
|||||||
Cursor string
|
Cursor string
|
||||||
BlinkSpeed time.Duration
|
BlinkSpeed time.Duration
|
||||||
TextColor string
|
TextColor string
|
||||||
FocusedTextColor string
|
|
||||||
BackgroundColor string
|
BackgroundColor string
|
||||||
PlaceholderColor string
|
PlaceholderColor string
|
||||||
CursorColor string
|
CursorColor string
|
||||||
@@ -115,7 +114,6 @@ func NewModel() Model {
|
|||||||
Placeholder: "",
|
Placeholder: "",
|
||||||
BlinkSpeed: defaultBlinkSpeed,
|
BlinkSpeed: defaultBlinkSpeed,
|
||||||
TextColor: "",
|
TextColor: "",
|
||||||
FocusedTextColor: "205",
|
|
||||||
PlaceholderColor: "240",
|
PlaceholderColor: "240",
|
||||||
CursorColor: "",
|
CursorColor: "",
|
||||||
EchoCharacter: '*',
|
EchoCharacter: '*',
|
||||||
@@ -184,19 +182,15 @@ func (m Model) Focused() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Focus sets the focus state on the model.
|
// Focus sets the focus state on the model.
|
||||||
func (m Model) Focus() tea.Model {
|
func (m *Model) Focus() {
|
||||||
m.focus = true
|
m.focus = true
|
||||||
m.blink = m.cursorMode == cursorHide // show the cursor unless we've explicitly hidden it
|
m.blink = m.cursorMode == cursorHide // show the cursor unless we've explicitly hidden it
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blur removes the focus state on the model.
|
// Blur removes the focus state on the model.
|
||||||
func (m Model) Blur() tea.Model {
|
func (m *Model) Blur() {
|
||||||
m.focus = false
|
m.focus = false
|
||||||
m.blink = true
|
m.blink = true
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset sets the input to its default state with no input. Returns whether
|
// Reset sets the input to its default state with no input. Returns whether
|
||||||
@@ -456,12 +450,8 @@ func (m Model) echoTransform(v string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) Init() tea.Cmd {
|
|
||||||
return Blink
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update is the Bubble Tea update loop.
|
// Update is the Bubble Tea update loop.
|
||||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||||
if !m.focus {
|
if !m.focus {
|
||||||
m.blink = true
|
m.blink = true
|
||||||
return m, nil
|
return m, nil
|
||||||
@@ -570,14 +560,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
|
|
||||||
// View renders the textinput in its current state.
|
// View renders the textinput in its current state.
|
||||||
func (m Model) View() string {
|
func (m Model) View() string {
|
||||||
prompt := termenv.String(m.Prompt)
|
|
||||||
if m.focus {
|
|
||||||
prompt = prompt.Foreground(color(m.FocusedTextColor))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Placeholder text
|
// Placeholder text
|
||||||
if len(m.value) == 0 && m.Placeholder != "" {
|
if len(m.value) == 0 && m.Placeholder != "" {
|
||||||
return prompt.String() + m.placeholderView()
|
return m.placeholderView()
|
||||||
}
|
}
|
||||||
|
|
||||||
value := m.value[m.offset:m.offsetRight]
|
value := m.value[m.offset:m.offsetRight]
|
||||||
@@ -605,7 +590,7 @@ func (m Model) View() string {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return prompt.String() + v
|
return m.Prompt + v
|
||||||
}
|
}
|
||||||
|
|
||||||
// placeholderView returns the prompt and placeholder view, if any.
|
// placeholderView returns the prompt and placeholder view, if any.
|
||||||
@@ -625,7 +610,7 @@ func (m Model) placeholderView() string {
|
|||||||
// The rest of the placeholder text
|
// The rest of the placeholder text
|
||||||
v += m.colorPlaceholder(p[1:])
|
v += m.colorPlaceholder(p[1:])
|
||||||
|
|
||||||
return v
|
return m.Prompt + v
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursorView styles the cursor.
|
// cursorView styles the cursor.
|
||||||
|
Reference in New Issue
Block a user