feat(table): add option for custom StyleFunc

This commit is contained in:
bashbunni
2024-09-26 11:58:13 -07:00
parent 48eb859f21
commit 6548f4e501
5 changed files with 151 additions and 18 deletions
+34 -17
View File
@@ -16,13 +16,14 @@ type Model struct {
KeyMap KeyMap
Help help.Model
yoffset int
height int
headers []string
rows [][]string
cursor int
focus bool
styles Styles
yoffset int
height int
headers []string
rows [][]string
cursor int
focus bool
styles Styles
styleFunc table.StyleFunc
table *table.Table
start int
@@ -138,6 +139,12 @@ func (m *Model) SetStyles(s Styles) {
m.table.BorderHeader(s.BorderHeader)
}
// SetStyleFunc sets the table's custom StyleFunc. Use this for conditional
// styling e.g. styling a cell by its contents or by index.
func (m *Model) SetStyleFunc(s table.StyleFunc) {
m.styleFunc = s
}
// SetBorder is a shorthand function for setting or unsetting borders on a
// table. The arguments work as follows:
//
@@ -311,6 +318,13 @@ func WithStyles(s Styles) Option {
}
}
// WithStyleFunc sets the table StyleFunc for conditional styling.
func WithStyleFunc(s table.StyleFunc) Option {
return func(m *Model) {
m.SetStyleFunc(s)
}
}
// WithKeyMap sets the key map.
func WithKeyMap(km KeyMap) Option {
return func(m *Model) {
@@ -369,16 +383,19 @@ func (m *Model) Blur() {
// View renders the component.
func (m Model) View() string {
m.table.StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return m.styles.Header
}
if row == m.cursor {
return m.styles.Selected
}
return m.styles.Cell
})
if m.styleFunc != nil {
m.table.StyleFunc(m.styleFunc)
} else {
m.table.StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return m.styles.Header
}
if row == m.cursor {
return m.styles.Selected
}
return m.styles.Cell
})
}
return m.table.String()
}
+96 -1
View File
@@ -4,6 +4,8 @@ import (
"reflect"
"testing"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/charmbracelet/x/ansi"
"github.com/charmbracelet/x/exp/golden"
)
@@ -136,7 +138,7 @@ func TestTableAlignment(t *testing.T) {
s := DefaultStyles()
s.BorderHeader = false
biscuits := New(
WithHeight(5),
WithHeight(10),
WithColumns([]Column{
{Title: "Name", Width: 25},
{Title: "Country of Origin", Width: 16},
@@ -174,3 +176,96 @@ func TestTableAlignment(t *testing.T) {
golden.RequireEqual(t, []byte(got))
})
}
func TestSetStyleFunc(t *testing.T) {
t.Run("single cell styling", func(t *testing.T) {
s := DefaultStyles()
s.BorderHeader = false
biscuits := New(
WithColumns([]Column{
{Title: "Name", Width: 25},
{Title: "Country of Origin", Width: 16},
{Title: "Dunk-able", Width: 12},
}),
WithRows([]Row{
{"Chocolate Digestives", "UK", "Yes"},
{"Tim Tams", "Australia", "No"},
{"Hobnobs", "UK", "Yes"},
}),
)
biscuits.SetStyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
// TODO this should be exported to be usable outside of the lib.
return s.Header
}
if row == 1 && col == 1 {
return s.Cell.Bold(true)
}
return s.Cell
})
golden.RequireEqual(t, []byte(biscuits.View()))
})
}
func TestWithStyleFunc(t *testing.T) {
t.Run("single cell styling", func(t *testing.T) {
s := DefaultStyles()
s.BorderHeader = false
biscuits := New(
WithColumns([]Column{
{Title: "Name", Width: 25},
{Title: "Country of Origin", Width: 16},
{Title: "Dunk-able", Width: 12},
}),
WithRows([]Row{
{"Chocolate Digestives", "UK", "Yes"},
{"Tim Tams", "Australia", "No"},
{"Hobnobs", "UK", "Yes"},
}),
WithStyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return s.Header
}
// TODO we should probably make it possible to retrieve Style
// from the model in case it has been modified from the
// defaults.
if row == 1 && col == 1 {
return s.Cell.Bold(true)
}
return s.Cell
}))
golden.RequireEqual(t, []byte(biscuits.View()))
})
t.Run("cell styling by content", func(t *testing.T) {
rows := []Row{
{"Chocolate Digestives", "UK", "Yes"},
{"Tim Tams", "Australia", "No"},
{"Hobnobs", "UK", "Yes"},
}
s := DefaultStyles()
s.BorderHeader = false
biscuits := New(
WithColumns([]Column{
{Title: "Name", Width: 25},
{Title: "Country of Origin", Width: 16},
{Title: "Dunk-able", Width: 12},
}),
WithRows(rows),
WithStyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return s.Header
}
// TODO we should probably make it possible to retrieve Style
// from the model in case it has been modified from the
// defaults.
// you need to pre-define the rows for this to be accessible in
// WithStyleFunc
if rows[row][col] == "Yes" {
return s.Cell.Bold(true)
}
return s.Cell
}))
golden.RequireEqual(t, []byte(biscuits.View()))
})
}
@@ -0,0 +1,7 @@
╭──────────────────────┬───────────────────┬───────────╮
Name │ Country of Origin │ Dunk-able │
├──────────────────────┼───────────────────┼───────────┤
│ Chocolate Digestives │ UK │ Yes │
│ Tim Tams │ Australia │ No │
│ Hobnobs │ UK │ Yes │
╰──────────────────────┴───────────────────┴───────────╯
@@ -0,0 +1,7 @@
╭──────────────────────┬───────────────────┬───────────╮
Name │ Country of Origin │ Dunk-able │
├──────────────────────┼───────────────────┼───────────┤
│ Chocolate Digestives │ UK │ Yes │
│ Tim Tams │ Australia │ No │
│ Hobnobs │ UK │ Yes │
╰──────────────────────┴───────────────────┴───────────╯
@@ -0,0 +1,7 @@
╭──────────────────────┬───────────────────┬───────────╮
Name │ Country of Origin │ Dunk-able │
├──────────────────────┼───────────────────┼───────────┤
│ Chocolate Digestives │ UK │ Yes │
│ Tim Tams │ Australia │ No │
│ Hobnobs │ UK │ Yes │
╰──────────────────────┴───────────────────┴───────────╯