Skip to content

Commit

Permalink
Form States (#31)
Browse files Browse the repository at this point in the history
* feat: WithOnConfirm and WithOnAbort

Signed-off-by: Carlos Alexandro Becker <[email protected]>

* feat: no tea.Quit on submit / cancel

---------

Signed-off-by: Carlos Alexandro Becker <[email protected]>
Co-authored-by: Carlos Alexandro Becker <[email protected]>
  • Loading branch information
maaslalani and caarlos0 authored Nov 7, 2023
1 parent 5588b7a commit 9250f9d
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 5 deletions.
81 changes: 81 additions & 0 deletions examples/bubbletea/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"fmt"
"os"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
)

var highlight = lipgloss.NewStyle().Foreground(lipgloss.Color("212")).Render
var help = lipgloss.NewStyle().Foreground(lipgloss.Color("240")).Render

type Model struct {
class string
level string

form *huh.Form
}

func NewModel() *Model {
var m Model
m.class = "Warrior"
m.level = "1"
f := huh.NewForm(
huh.NewGroup(
huh.NewSelect[string]().
Options(huh.NewOptions("Warrior", "Mage", "Rogue")...).
Title("Choose your class").
Description("This will determine your department").
Value(&m.class),
huh.NewSelect[string]().
Options(huh.NewOptions("1", "20", "9999")...).
Title("Choose your level").
Description("This will determine your benefits package").
Value(&m.level),
),
)

m.form = f
return &m
}

func (m Model) Init() tea.Cmd {
return m.form.Init()
}

func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "esc", "ctrl+c", "q":
return m, tea.Quit
}
}

form, cmd := m.form.Update(msg)
if f, ok := form.(*huh.Form); ok {
m.form = f
}

return m, cmd
}

func (m Model) View() string {
v := "Charm Employment Application\n\n" + m.form.View()
if m.form.State == huh.StateCompleted {
v += highlight(fmt.Sprintf("You selected: Level %s, %s\n", m.level, m.class))
v += help("\nctrl+c to quit\n")
}
return lipgloss.NewStyle().Margin(1, 2).Render(v)
}

func main() {
_, err := tea.NewProgram(NewModel()).Run()
if err != nil {
fmt.Println("Oh no:", err)
os.Exit(1)
}
}
36 changes: 31 additions & 5 deletions form.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,23 @@ import (
tea "github.com/charmbracelet/bubbletea"
)

// FormState represents the current state of the form.
type FormState int

const (
// StateNormal is when the user is completing the form.
StateNormal FormState = iota

// StateCompleted is when the user has completed the form.
StateCompleted

// StateAborted is when the user has aborted the form.
StateAborted
)

// ErrUserAborted is the error returned when a user exits the form before
// submitting.
var (
// ErrUserAborted is the error returned when a user exits the form before submitting.
ErrUserAborted = errors.New("user aborted")
)

Expand All @@ -24,6 +39,12 @@ type Form struct {
// navigation
paginator paginator.Model

// callbacks
submitCmd tea.Cmd
cancelCmd tea.Cmd

State FormState

// whether or not to use bubble tea rendering for accessibility
// purposes, if true, the form will render with basic prompting primitives
// to be more accessible to screen readers.
Expand All @@ -47,7 +68,7 @@ func NewForm(groups ...*Group) *Form {
p := paginator.New()
p.SetTotalPages(len(groups))

f := Form{
f := &Form{
groups: groups,
paginator: p,
theme: NewCharmTheme(),
Expand All @@ -61,7 +82,7 @@ func NewForm(groups ...*Group) *Form {
f.WithKeyMap(f.keymap)
f.WithWidth(f.width)

return &f
return f
}

// Field is a primitive of a form.
Expand Down Expand Up @@ -206,7 +227,8 @@ func (f *Form) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, f.keymap.Quit):
f.aborted = true
f.quitting = true
return f, tea.Quit
f.State = StateAborted
return f, f.cancelCmd
}

case nextGroupMsg:
Expand All @@ -216,7 +238,8 @@ func (f *Form) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

if f.paginator.OnLastPage() {
f.quitting = true
return f, tea.Quit
f.State = StateCompleted
return f, f.submitCmd
}
f.paginator.NextPage()

Expand Down Expand Up @@ -244,6 +267,9 @@ func (f *Form) View() string {

// Run runs the form.
func (f *Form) Run() error {
f.submitCmd = tea.Quit
f.cancelCmd = tea.Quit

if len(f.groups) == 0 {
return nil
}
Expand Down

0 comments on commit 9250f9d

Please sign in to comment.