Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add row style func #176

Merged
merged 1 commit into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ determining overrides. The default base style is a basic right-alignment.
[See the main feature example](./examples/features) to see styles and
how they override each other.

Styles can also be applied via a style function which can be used to apply
zebra striping, data-specific formatting, etc.

Can be focused to highlight a row and navigate with up/down (and j/k). These
keys can be customized with a KeyMap.

Expand Down
35 changes: 22 additions & 13 deletions examples/updates/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,30 @@ type Model struct {
data []*SomeData
}

func rowStyleFunc(input table.RowStyleFuncInput) lipgloss.Style {
calculatedStyle := lipgloss.NewStyle()

switch input.Row.Data[columnKeyStatus] {
case "Critical":
calculatedStyle = styleCritical.Copy()
case "Stable":
calculatedStyle = styleStable.Copy()
case "Good":
calculatedStyle = styleGood.Copy()
}

if input.Index%2 == 0 {
calculatedStyle = calculatedStyle.Background(lipgloss.Color("#222"))
} else {
calculatedStyle = calculatedStyle.Background(lipgloss.Color("#444"))
}

return calculatedStyle
}

func NewModel() Model {
return Model{
table: table.New(generateColumns(0)),
table: table.New(generateColumns(0)).WithRowStyleFunc(rowStyleFunc),
updateDelay: time.Second,
}
}
Expand Down Expand Up @@ -152,18 +173,6 @@ func generateRowsFromData(data []*SomeData) []table.Row {
columnKeyStatus: entry.Status,
})

// Highlight different statuses
switch entry.Status {
case "Critical":
row = row.WithStyle(styleCritical)

case "Stable":
row = row.WithStyle(styleStable)

case "Good":
row = row.WithStyle(styleGood)
}

rows = append(rows, row)
}

Expand Down
1 change: 1 addition & 0 deletions table/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type Model struct {
baseStyle lipgloss.Style
highlightStyle lipgloss.Style
headerStyle lipgloss.Style
rowStyleFunc func(RowStyleFuncInput) lipgloss.Style
border Border
selectedText string
unselectedText string
Expand Down
24 changes: 24 additions & 0 deletions table/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,30 @@ import (
"github.com/charmbracelet/lipgloss"
)

// RowStyleFuncInput is the input to the style function that can
// be applied to each row. This is useful for things like zebra
// striping or other data-based styles.
//
// Note that we use a struct here to allow for future expansion
// while keeping backwards compatibility.
type RowStyleFuncInput struct {
// Index is the index of the row, starting at 0.
Index int

// Row is the full row data.
Row Row
}

// WithRowStyleFunc sets a function that can be used to apply a style to each row
// based on the row data. This is useful for things like zebra striping or other
// data-based styles. It can be safely set to nil to remove it later.
// This style is applied after the base style and before individual row styles.
func (m Model) WithRowStyleFunc(f func(RowStyleFuncInput) lipgloss.Style) Model {
m.rowStyleFunc = f

return m
}

// WithHighlightedRow sets the highlighted row to the given index.
func (m Model) WithHighlightedRow(index int) Model {
m.rowCursorIndex = index
Expand Down
9 changes: 9 additions & 0 deletions table/row.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ func (m Model) renderRow(rowIndex int, last bool) string {

rowStyle := row.Style.Copy()

if m.rowStyleFunc != nil {
styleResult := m.rowStyleFunc(RowStyleFuncInput{
Index: rowIndex,
Row: row,
})

rowStyle = rowStyle.Inherit(styleResult)
}

if m.focused && highlighted {
rowStyle = rowStyle.Inherit(m.highlightStyle)
}
Expand Down
51 changes: 51 additions & 0 deletions table/view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,57 @@ func TestSimple3x3StyleOverridesAsBaseColumnRowCell(t *testing.T) {
assert.Equal(t, expectedTable, rendered)
}

func TestStyleFuncAppliesAfterBaseStyleAndColStylesAndBeforeRowStyle(t *testing.T) {
styleFunc := func(input RowStyleFuncInput) lipgloss.Style {
if input.Index%2 == 0 {
return lipgloss.NewStyle().Align(lipgloss.Left)
}

return lipgloss.NewStyle()
}

model := New([]Column{
NewColumn("1", "1", 6),
// This column style should be overridden by the style func
NewColumn("2", "2", 6).WithStyle(lipgloss.NewStyle().Align(lipgloss.Right)),
NewColumn("3", "3", 6),
}).
WithBaseStyle(lipgloss.NewStyle().Align(lipgloss.Center)).
WithRowStyleFunc(styleFunc)

rows := []Row{}

for rowIndex := 1; rowIndex <= 5; rowIndex++ {
rowData := RowData{}

for columnIndex := 1; columnIndex <= 3; columnIndex++ {
id := fmt.Sprintf("%d", columnIndex)

rowData[id] = fmt.Sprintf("%d,%d", columnIndex, rowIndex)
}

rows = append(rows, NewRow(rowData))
}

rows[0] = rows[0].WithStyle(lipgloss.NewStyle().Align(lipgloss.Right))

model = model.WithRows(rows)

const expectedTable = `┏━━━━━━┳━━━━━━┳━━━━━━┓
┃ 1 ┃ 2┃ 3 ┃
┣━━━━━━╋━━━━━━╋━━━━━━┫
┃ 1,1┃ 2,1┃ 3,1┃
┃ 1,2 ┃ 2,2┃ 3,2 ┃
┃1,3 ┃2,3 ┃3,3 ┃
┃ 1,4 ┃ 2,4┃ 3,4 ┃
┃1,5 ┃2,5 ┃3,5 ┃
┗━━━━━━┻━━━━━━┻━━━━━━┛`

rendered := model.View()

assert.Equal(t, expectedTable, rendered)
}

// This is a long test due to typing and multiple big table strings, that's okay
//
//nolint:funlen
Expand Down
Loading