-
Notifications
You must be signed in to change notification settings - Fork 132
/
form.go
128 lines (108 loc) · 2.42 KB
/
form.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package huh
import (
"github.com/charmbracelet/bubbles/paginator"
tea "github.com/charmbracelet/bubbletea"
)
// Form represents a Huh? form.
// It is a collection of groups and controls navigation between pages.
type Form struct {
groups []*Group
paginator paginator.Model
accessible bool
quitting bool
}
// NewForm creates a new form with the given groups.
func NewForm(groups ...*Group) *Form {
p := paginator.New()
p.SetTotalPages(len(groups))
return &Form{
groups: groups,
paginator: p,
}
}
// Field is a form field.
type Field interface {
// Bubble Tea Model
Init() tea.Cmd
Update(tea.Msg) (tea.Model, tea.Cmd)
View() string
// Bubble Tea Events
Blur() tea.Cmd
Focus() tea.Cmd
// Accessible Prompt (non-redraw)
Run()
}
type nextGroupMsg struct{}
type prevGroupMsg struct{}
func nextGroup() tea.Msg {
return nextGroupMsg{}
}
func prevGroup() tea.Msg {
return prevGroupMsg{}
}
// Accessible sets the form to run in accessible mode to avoid redrawing the
// views which makes it easier for screen readers to read and describe the form.
//
// This avoids using the Bubble Tea renderer and instead simply uses basic
// terminal prompting to gather input which degrades the user experience but
// provides accessibility.
func (f *Form) Accessible(b bool) *Form {
f.accessible = b
return f
}
// Init initializes the form.
func (f *Form) Init() tea.Cmd {
var cmds []tea.Cmd
for _, group := range f.groups {
cmds = append(cmds, group.Init())
}
return tea.Batch(cmds...)
}
// Update updates the form.
func (f *Form) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
f.quitting = true
return f, tea.Quit
}
case nextGroupMsg:
if f.paginator.OnLastPage() {
f.quitting = true
return f, tea.Quit
}
f.paginator.NextPage()
case prevGroupMsg:
f.paginator.PrevPage()
}
m, cmd := f.groups[f.paginator.Page].Update(msg)
f.groups[f.paginator.Page] = m.(*Group)
return f, cmd
}
// View renders the form.
func (f *Form) View() string {
if f.quitting {
return ""
}
return f.groups[f.paginator.Page].View()
}
// Run runs the form.
func (f *Form) Run() error {
if f.accessible {
for _, group := range f.groups {
for _, field := range group.fields {
field.Init()
field.Focus()
field.Run()
}
}
return nil
}
p := tea.NewProgram(f)
_, err := p.Run()
if err != nil {
return err
}
return nil
}