From 432972ae77e8c029e72e4661bab1c57692fd44e6 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 23 Oct 2024 16:21:14 -0400 Subject: [PATCH] feat(textinput): add styles for focused and blurred states --- textinput/textinput.go | 81 +++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/textinput/textinput.go b/textinput/textinput.go index 67ec19a..70b0a2c 100644 --- a/textinput/textinput.go +++ b/textinput/textinput.go @@ -83,6 +83,36 @@ func DefaultKeyMap() KeyMap { } } +// Styles is a collection of styles for the text input. There are two states: +// one for when the input is focused and one for when it is not. +type Styles struct { + Focused StyleState + Blurred StyleState +} + +// StyleState is a set of styles for the text input that pertain to focused +// and unfocused states. +type StyleState struct { + Prompt lipgloss.Style + Text lipgloss.Style + Placeholder lipgloss.Style + Completion lipgloss.Style +} + +// DefaultStyles returns the default styles for the text input. +func DefaultStyles() Styles { + v := StyleState{ + Prompt: lipgloss.NewStyle(), + Text: lipgloss.NewStyle(), + Placeholder: lipgloss.NewStyle().Faint(true), + Completion: lipgloss.NewStyle().Faint(true), + } + return Styles{ + Focused: v, + Blurred: v, + } +} + // Model is the Bubble Tea model for this text input element. type Model struct { Err error @@ -94,14 +124,7 @@ type Model struct { EchoCharacter rune Cursor cursor.Model - // Styles. These will be applied as inline styles. - // - // For an introduction to styling with Lip Gloss see: - // https://github.com/charmbracelet/lipgloss - PromptStyle lipgloss.Style - TextStyle lipgloss.Style - PlaceholderStyle lipgloss.Style - CompletionStyle lipgloss.Style + Styles Styles // Validate is a function that checks whether or not the text within the // input is valid. If it is not valid, the Err field will be set to the @@ -152,14 +175,13 @@ type Model struct { // New creates a new model with default settings. func New() Model { return Model{ - Prompt: "> ", - EchoCharacter: '*', - CharLimit: 0, - PlaceholderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")), - ShowSuggestions: false, - CompletionStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")), - Cursor: cursor.New(), - KeyMap: DefaultKeyMap(), + Prompt: "> ", + EchoCharacter: '*', + CharLimit: 0, + ShowSuggestions: false, + Cursor: cursor.New(), + KeyMap: DefaultKeyMap(), + Styles: DefaultStyles(), suggestions: [][]rune{}, value: nil, @@ -168,6 +190,14 @@ func New() Model { } } +// styles returns the appropriate styles for the current focus state. +func (m Model) styles() StyleState { + if m.focus { + return m.Styles.Focused + } + return m.Styles.Blurred +} + // SetValue sets the value of the text input. func (m *Model) SetValue(s string) { // Clean up any special characters in the input provided by the @@ -656,7 +686,9 @@ func (m Model) View() string { return m.placeholderView() } - styleText := m.TextStyle.Inline(true).Render + s := m.styles() + + styleText := s.Text.Inline(true).Render value := m.value[m.offset:m.offsetRight] pos := max(0, m.pos-m.offset) @@ -672,7 +704,7 @@ func (m Model) View() string { if m.canAcceptSuggestion() { suggestion := m.matchedSuggestions[m.currentSuggestionIndex] if len(value) < len(suggestion) { - m.Cursor.TextStyle = m.CompletionStyle + m.Cursor.TextStyle = s.Completion m.Cursor.SetChar(m.echoTransform(string(suggestion[pos]))) v += m.Cursor.View() v += m.completionView(1) @@ -697,7 +729,7 @@ func (m Model) View() string { v += styleText(strings.Repeat(" ", padding)) } - return m.PromptStyle.Render(m.Prompt) + v + return s.Prompt.Render(m.Prompt) + v } // placeholderView returns the prompt and placeholder view, if any. @@ -705,16 +737,17 @@ func (m Model) placeholderView() string { var ( v string p = []rune(m.Placeholder) - style = m.PlaceholderStyle.Inline(true).Render + s = m.styles() + style = s.Placeholder.Inline(true).Render ) - m.Cursor.TextStyle = m.PlaceholderStyle + m.Cursor.TextStyle = s.Placeholder m.Cursor.SetChar(string(p[:1])) v += m.Cursor.View() // If the entire placeholder is already set and no padding is needed, finish if m.Width() < 1 && len(p) <= 1 { - return m.PromptStyle.Render(m.Prompt) + v + return s.Prompt.Render(m.Prompt) + v } // If Width is set then size placeholder accordingly @@ -736,7 +769,7 @@ func (m Model) placeholderView() string { v += style(string(p[1:])) } - return m.PromptStyle.Render(m.Prompt) + v + return s.Prompt.Render(m.Prompt) + v } // Blink is a command used to initialize cursor blinking. @@ -777,7 +810,7 @@ func max(a, b int) int { func (m Model) completionView(offset int) string { var ( value = m.value - style = m.PlaceholderStyle.Inline(true).Render + style = m.styles().Placeholder.Inline(true).Render ) if m.canAcceptSuggestion() {