diff --git a/spinner/spinner.go b/spinner/spinner.go index ced6b1f..e034112 100644 --- a/spinner/spinner.go +++ b/spinner/spinner.go @@ -109,11 +109,17 @@ func (m Model) ID() int { } // New returns a model with default values. -func New() Model { - return Model{ +func New(opts ...Option) Model { + m := Model{ Spinner: Line, id: nextID(), } + + for _, opt := range opts { + opt(&m) + } + + return m } // NewModel returns a model with default values. @@ -199,3 +205,23 @@ func (m Model) tick(id, tag int) tea.Cmd { func Tick() tea.Msg { return TickMsg{Time: time.Now()} } + +// Option is used to set options in New. For example: +// +// spinner := New(WithSpinner(Dot)) +// +type Option func(*Model) + +// WithSpinner is an option to set the spinner. +func WithSpinner(spinner Spinner) Option { + return func(m *Model) { + m.Spinner = spinner + } +} + +// WithStyle is an option to set the spinner style. +func WithStyle(style lipgloss.Style) Option { + return func(m *Model) { + m.Style = style + } +} diff --git a/spinner/spinner_test.go b/spinner/spinner_test.go new file mode 100644 index 0000000..959200b --- /dev/null +++ b/spinner/spinner_test.go @@ -0,0 +1,61 @@ +package spinner_test + +import ( + "testing" + + "github.com/charmbracelet/bubbles/spinner" +) + +func TestSpinnerNew(t *testing.T) { + assertEqualSpinner := func(t *testing.T, exp, got spinner.Spinner) { + t.Helper() + + if exp.FPS != got.FPS { + t.Errorf("expecting %d FPS, got %d", exp.FPS, got.FPS) + } + + if e, g := len(exp.Frames), len(got.Frames); e != g { + t.Fatalf("expecting %d frames, got %d", e, g) + } + + for i, e := range exp.Frames { + if g := got.Frames[i]; e != g { + t.Errorf("expecting frame index %d with value %q, got %q", i, e, g) + } + } + } + t.Run("default", func(t *testing.T) { + s := spinner.New() + + assertEqualSpinner(t, spinner.Line, s.Spinner) + }) + + t.Run("WithSpinner", func(t *testing.T) { + customSpinner := spinner.Spinner{ + Frames: []string{"a", "b", "c", "d"}, + FPS: 16, + } + + s := spinner.New(spinner.WithSpinner(customSpinner)) + + assertEqualSpinner(t, customSpinner, s.Spinner) + }) + + tests := map[string]spinner.Spinner{ + "Line": spinner.Line, + "Dot": spinner.Dot, + "MiniDot": spinner.MiniDot, + "Jump": spinner.Jump, + "Pulse": spinner.Pulse, + "Points": spinner.Points, + "Globe": spinner.Globe, + "Moon": spinner.Moon, + "Monkey": spinner.Monkey, + } + + for name, s := range tests { + t.Run(name, func(t *testing.T) { + assertEqualSpinner(t, spinner.New(spinner.WithSpinner(s)).Spinner, s) + }) + } +}