Repository: Evertras/bubble-table
Pull request #90 (2022-06-04 16:26:24)

Fix footer size with horizontal scrolling
As described in #83 , the footer would sometimes be too large when scrolled to the right.  This makes the footer always match the table's actual width.

Evertras: Lowering coverage here is fine because it's just removing lines, there are no new uncovered lines added.

Patch:
diff --git a/examples/scrolling/main.go b/examples/scrolling/main.go
index b15fcab..c18467f 100644
--- a/examples/scrolling/main.go
+++ b/examples/scrolling/main.go
@@ -55,6 +55,7 @@ func NewModel() Model {
 		WithRows(rows).
 		WithMaxTotalWidth(30).
 		WithHorizontalFreezeColumnCount(1).
+		WithStaticFooter("A footer").
 		Focused(true)
 
 	return Model{
diff --git a/table/footer.go b/table/footer.go
index d78eb8f..e2abee5 100644
--- a/table/footer.go
+++ b/table/footer.go
@@ -9,19 +9,13 @@ func (m Model) hasFooter() bool {
 	return m.footerVisible && (m.staticFooter != "" || m.pageSize != 0 || m.filtered)
 }
 
-func (m Model) renderFooter() string {
+func (m Model) renderFooter(width int) string {
 	if !m.hasFooter() {
 		return ""
 	}
 
 	const borderAdjustment = 2
 
-	width := m.totalWidth
-
-	if m.maxTotalWidth != 0 {
-		width = m.maxTotalWidth
-	}
-
 	styleFooter := m.baseStyle.Copy().Inherit(m.border.styleFooter).Width(width - borderAdjustment)
 
 	if m.staticFooter != "" {
diff --git a/table/view.go b/table/view.go
index 72242f0..2c7ee91 100644
--- a/table/view.go
+++ b/table/view.go
@@ -23,7 +23,7 @@ func (m Model) View() string {
 		rowStrs = append(rowStrs, m.renderRow(i, i == endRowIndex))
 	}
 
-	footer := m.renderFooter()
+	footer := m.renderFooter(lipgloss.Width(rowStrs[0]))
 
 	if footer != "" {
 		rowStrs = append(rowStrs, footer)


Test patch:
diff --git a/table/options_test.go b/table/options_test.go
index a7b336b..7af8821 100644
--- a/table/options_test.go
+++ b/table/options_test.go
@@ -131,9 +131,9 @@ func TestPageOptions(t *testing.T) {
 	assert.Equal(t, 26, model.rowCursorIndex)
 
 	model = model.WithFooterVisibility(false)
-	assert.Equal(t, "", model.renderFooter())
+	assert.Equal(t, "", model.renderFooter(10))
 
 	model = model.WithFooterVisibility(true)
-	assert.Greater(t, len(model.renderFooter()), 10)
-	assert.Contains(t, model.renderFooter(), "6/6")
+	assert.Greater(t, len(model.renderFooter(10)), 10)
+	assert.Contains(t, model.renderFooter(10), "6/6")
 }
diff --git a/table/view_test.go b/table/view_test.go
index f5425bd..d969b63 100644
--- a/table/view_test.go
+++ b/table/view_test.go
@@ -671,6 +671,45 @@ func TestMaxWidthHasNoEffectForExactFit(t *testing.T) {
 	assert.Equal(t, expectedTableFooter, rendered)
 }
 
+func TestMaxWidthHasNoEffectForSmaller(t *testing.T) {
+	model := New([]Column{
+		NewColumn("1", "1", 4),
+		NewColumn("2", "2", 4),
+		NewColumn("3", "3", 4),
+		NewColumn("4", "4", 4),
+	}).
+		WithRows([]Row{
+			NewRow(RowData{
+				"1": "x1",
+				"2": "x2",
+				"3": "x3",
+				"4": "x4",
+			}),
+		})
+
+	const expectedTable = `┏━━━━┳━━━━┳━━━━┳━━━━┓
+┃   1┃   2┃   3┃   4┃
+┣━━━━╋━━━━╋━━━━╋━━━━┫
+┃  x1┃  x2┃  x3┃  x4┃
+┗━━━━┻━━━━┻━━━━┻━━━━┛`
+
+	const expectedTableFooter = `┏━━━━┳━━━━┳━━━━┳━━━━┓
+┃   1┃   2┃   3┃   4┃
+┣━━━━╋━━━━╋━━━━╋━━━━┫
+┃  x1┃  x2┃  x3┃  x4┃
+┣━━━━┻━━━━┻━━━━┻━━━━┫
+┃             Footer┃
+┗━━━━━━━━━━━━━━━━━━━┛`
+
+	model = model.WithMaxTotalWidth(lipgloss.Width(expectedTable) + 5)
+	rendered := model.View()
+	assert.Equal(t, expectedTable, rendered)
+
+	model = model.WithStaticFooter("Footer")
+	rendered = model.View()
+	assert.Equal(t, expectedTableFooter, rendered)
+}
+
 func TestMaxWidthHidesOverflowWithSingleCharExtra(t *testing.T) {
 	model := New([]Column{
 		NewColumn("1", "1", 4),
@@ -742,3 +781,34 @@ func TestMaxWidthHidesOverflowWithTwoCharExtra(t *testing.T) {
 	rendered = model.View()
 	assert.Equal(t, expectedTableFooter, rendered)
 }
+
+func TestScrolledTableSizesFooterCorrectly(t *testing.T) {
+	model := New([]Column{
+		NewColumn("1", "1", 4),
+		NewColumn("2", "2", 4),
+		NewColumn("3", "3", 4),
+		NewColumn("4", "4", 4),
+	}).
+		WithRows([]Row{
+			NewRow(RowData{
+				"1": "x1",
+				"2": "x2",
+				"3": "x3",
+				"4": "x4",
+			}),
+		}).
+		WithMaxTotalWidth(19).
+		WithStaticFooter("Footer").
+		ScrollRight()
+
+	const expectedTable = `┏━┳━━━━┳━━━━┳━━━━┓
+┃<┃   2┃   3┃   4┃
+┣━╋━━━━╋━━━━╋━━━━┫
+┃<┃  x2┃  x3┃  x4┃
+┣━┻━━━━┻━━━━┻━━━━┫
+┃          Footer┃
+┗━━━━━━━━━━━━━━━━┛`
+
+	rendered := model.View()
+	assert.Equal(t, expectedTable, rendered)
+}