Repository: Evertras/bubble-table
Pull request #177 (2024-06-16 09:07:30)

Send highlighted status to row style func
https://github.com/Evertras/bubble-table/issues/173

The highlighted row style was not being applied properly with the new style func.  In hindsight, this is going to be very difficult to properly do, because a highlighted row may need to look different depending on whether it's a zebra stripe, etc.  Therefore, we can just pass the input as a bool to the style func and let the user decide what a highlighted row needs to look like there.


Patch:
diff --git a/table/options.go b/table/options.go
index eed61d9..9db863c 100644
--- a/table/options.go
+++ b/table/options.go
@@ -17,12 +17,16 @@ type RowStyleFuncInput struct {
 
 	// Row is the full row data.
 	Row Row
+
+	// IsHighlighted is true if the row is currently highlighted.
+	IsHighlighted bool
 }
 
 // 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.
+// This will override any HighlightStyle settings.
 func (m Model) WithRowStyleFunc(f func(RowStyleFuncInput) lipgloss.Style) Model {
 	m.rowStyleFunc = f
 
@@ -136,7 +140,8 @@ func (m Model) SelectedRows() []Row {
 }
 
 // HighlightStyle sets a custom style to use when the row is being highlighted
-// by the cursor.
+// by the cursor.  This should not be used with WithRowStyleFunc.  Instead, use
+// the IsHighlighted field in the style function.
 func (m Model) HighlightStyle(style lipgloss.Style) Model {
 	m.highlightStyle = style
 
diff --git a/table/row.go b/table/row.go
index f2cf5d3..2ba4519 100644
--- a/table/row.go
+++ b/table/row.go
@@ -117,14 +117,13 @@ func (m Model) renderRow(rowIndex int, last bool) string {
 
 	if m.rowStyleFunc != nil {
 		styleResult := m.rowStyleFunc(RowStyleFuncInput{
-			Index: rowIndex,
-			Row:   row,
+			Index:         rowIndex,
+			Row:           row,
+			IsHighlighted: m.focused && highlighted,
 		})
 
 		rowStyle = rowStyle.Inherit(styleResult)
-	}
-
-	if m.focused && highlighted {
+	} else if m.focused && highlighted {
 		rowStyle = rowStyle.Inherit(m.highlightStyle)
 	}
 


Test patch:
diff --git a/table/view_test.go b/table/view_test.go
index fe07155..b4b8cf8 100644
--- a/table/view_test.go
+++ b/table/view_test.go
@@ -849,6 +849,59 @@ func TestStyleFuncAppliesAfterBaseStyleAndColStylesAndBeforeRowStyle(t *testing.
 	assert.Equal(t, expectedTable, rendered)
 }
 
+func TestStyleFuncAppliesHighlighted(t *testing.T) {
+	styleFunc := func(input RowStyleFuncInput) lipgloss.Style {
+		if input.IsHighlighted {
+			return lipgloss.NewStyle().Align(lipgloss.Center)
+		}
+
+		if input.Index%2 == 0 {
+			return lipgloss.NewStyle().Align(lipgloss.Right)
+		}
+
+		return lipgloss.NewStyle().Align(lipgloss.Left)
+	}
+
+	model := New([]Column{
+		NewColumn("1", "1", 6),
+		NewColumn("2", "2", 6),
+		NewColumn("3", "3", 6),
+	}).
+		WithRowStyleFunc(styleFunc).
+		Focused(true)
+
+	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))
+	}
+
+	model = model.WithRows(rows).
+		WithHighlightedRow(2)
+
+	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