fix(table)!: Add widths parameter to new() (#664)

This prevents creating a table that doesn't actually render anything.

Fixes: https://github.com/ratatui-org/ratatui/issues/537

BREAKING CHANGE: Table::new() now takes an additional widths parameter.
This commit is contained in:
Josh McKinney 2023-12-04 15:22:52 -08:00 committed by GitHub
parent 91c67eb100
commit 37c70dbb8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 306 additions and 226 deletions

View file

@ -11,7 +11,8 @@ github with a [breaking change] label.
This is a quick summary of the sections below:
- Unreleased (0.24.1)
- `Table::widths()` now accepts `AsRef<[Constraint]>`
- `Table::new()` now requires specifying the widths
-`Table::widths()` now accepts `IntoIterator<Item = AsRef<Constraint>>`
- Layout::new() now accepts direction and constraint parameters
- The default `Tabs::highlight_style` is now `Style::new().reversed()`
@ -46,9 +47,39 @@ widget in the default configuration would not show any indication of the selecte
[#635]: https://github.com/ratatui-org/ratatui/pull/635
### `Table::widths()` now accepts `AsRef<[Constraint]>` ([#628])
### The default `Tabs::highlight_style` is now `Style::new().reversed()` ([#635])
[#628]: https://github.com/ratatui-org/ratatui/pull/628
Previously the default highlight style for tabs was `Style::default()`, which meant that a `Tabs`
widget in the default configuration would not show any indication of the selected tab.
### `Table::new()` now requires specifying the widths of the columrs (#664)
Previously `Table`s could be constructed without widths. In almost all cases this is an error.
A new widths parameter is now manadatory on `Table::new()`. Existing code of the form:
```rust
Table::new(rows).widths(widths)
```
Should be updated to:
```rust
Table::new(rows, widths)
```
For ease of automated replacement in cases where the amount of code broken by this change is large
or complex, it may be convenient to replace `Table::new` with `Table::default().rows`.
```rust
Table::new(rows).block(block).widths(widths);
// becomes
Table::default().rows(rows).widths(widths)
```
### `Table::widths()` now accepts `IntoIterator<Item = AsRef<Constraint>>` ([#663])
[#663]: https://github.com/ratatui-org/ratatui/pull/663
Previously `Table::widths()` took a slice (`&'a [Constraint]`). This change will introduce clippy
`needless_borrow` warnings for places where slices are passed to this method. To fix these, remove

View file

@ -289,18 +289,20 @@ fn draw_second_tab(f: &mut Frame, app: &mut App, area: Rect) {
};
Row::new(vec![s.name, s.location, s.status]).style(style)
});
let table = Table::new(rows)
let table = Table::new(
rows,
[
Constraint::Length(15),
Constraint::Length(15),
Constraint::Length(10),
],
)
.header(
Row::new(vec!["Server", "Location", "Status"])
.style(Style::default().fg(Color::Yellow))
.bottom_margin(1),
)
.block(Block::default().title("Servers").borders(Borders::ALL))
.widths([
Constraint::Length(15),
Constraint::Length(15),
Constraint::Length(10),
]);
.block(Block::default().title("Servers").borders(Borders::ALL));
f.render_widget(table, chunks[0]);
let map = Canvas::default()
@ -393,12 +395,14 @@ fn draw_third_tab(f: &mut Frame, _app: &mut App, area: Rect) {
Row::new(cells)
})
.collect();
let table = Table::new(items)
.block(Block::default().title("Colors").borders(Borders::ALL))
.widths([
let table = Table::new(
items,
[
Constraint::Ratio(1, 3),
Constraint::Ratio(1, 3),
Constraint::Ratio(1, 3),
]);
],
)
.block(Block::default().title("Colors").borders(Borders::ALL));
f.render_widget(table, chunks[0]);
}

View file

@ -146,10 +146,9 @@ fn render_ingredients(selected_row: usize, area: Rect, buf: &mut Buffer) {
let rows = INGREDIENTS.iter().map(|&i| i.into()).collect_vec();
let theme = THEME.recipe;
StatefulWidget::render(
Table::new(rows)
Table::new(rows, [Constraint::Length(7), Constraint::Length(30)])
.block(Block::new().style(theme.ingredients))
.header(Row::new(vec!["Qty", "Ingredient"]).style(theme.ingredients_header))
.widths([Constraint::Length(7), Constraint::Length(30)])
.highlight_style(Style::new().light_yellow()),
area,
buf,

View file

@ -50,9 +50,8 @@ fn render_hops(selected_row: usize, area: Rect, buf: &mut Buffer) {
.title_alignment(Alignment::Center)
.padding(Padding::new(1, 1, 1, 1));
StatefulWidget::render(
Table::new(rows)
Table::new(rows, [Constraint::Max(100), Constraint::Length(15)])
.header(Row::new(vec!["Host", "Address"]).set_style(THEME.traceroute.header))
.widths([Constraint::Max(100), Constraint::Length(15)])
.highlight_style(THEME.traceroute.selected)
.block(block),
area,

View file

@ -137,15 +137,17 @@ fn ui(f: &mut Frame, app: &mut App) {
let cells = item.iter().map(|c| Cell::from(*c));
Row::new(cells).height(height as u16).bottom_margin(1)
});
let t = Table::new(rows)
.header(header)
.block(Block::default().borders(Borders::ALL).title("Table"))
.highlight_style(selected_style)
.highlight_symbol(">> ")
.widths([
let t = Table::new(
rows,
[
Constraint::Percentage(50),
Constraint::Max(30),
Constraint::Min(10),
]);
],
)
.header(header)
.block(Block::default().borders(Borders::ALL).title("Table"))
.highlight_style(selected_style)
.highlight_symbol(">> ");
f.render_stateful_widget(t, rects[0], &mut app.state);
}

View file

@ -204,7 +204,8 @@ impl HighlightSpacing {
/// ```rust
/// use ratatui::{prelude::*, widgets::*};
///
/// Table::new(vec![
/// Table::new(
/// vec![
/// // Row can be created from simple strings.
/// Row::new(vec!["Row11", "Row12", "Row13"]),
/// // You can style the entire row.
@ -225,7 +226,11 @@ impl HighlightSpacing {
/// Cell::from("Row\n42"),
/// Cell::from("Row\n43"),
/// ]).height(2),
/// ])
/// ],
/// // Columns widths are constrained in the same way as Layout...
/// [Constraint::Length(5), Constraint::Length(5), Constraint::Length(10)])
/// // ...and they can be separated by a fixed spacing.
/// .column_spacing(1)
/// // You can set the style of the entire Table.
/// .style(Style::default().fg(Color::White))
/// // It has an optional header, which is simply a Row always visible at the top.
@ -238,10 +243,6 @@ impl HighlightSpacing {
/// )
/// // As any other widget, a Table can be wrapped in a Block.
/// .block(Block::default().title("Table"))
/// // Columns widths are constrained in the same way as Layout...
/// .widths(&[Constraint::Length(5), Constraint::Length(5), Constraint::Length(10)])
/// // ...and they can be separated by a fixed spacing.
/// .column_spacing(1)
/// // If you wish to highlight a row in any specific way when it is selected...
/// .highlight_style(Style::default().add_modifier(Modifier::BOLD))
/// // ...and potentially show a symbol in front of the selection.
@ -275,13 +276,17 @@ impl<'a> Table<'a> {
/// Creates a new [`Table`] widget with the given rows.
///
/// The `rows` parameter is a Vector of [`Row`], this holds the data to be displayed by the
/// table
/// table.
///
/// The `widths` parameter is an array (or any other type that implements IntoIterator) of
/// [`Constraint`]s, this holds the widths of each column. This parameter was added in 0.25.0.
///
/// # Examples
///
/// ```rust
/// # use ratatui::{prelude::*, widgets::*};
/// let table = Table::new(vec![
/// let table = Table::new(
/// vec![
/// Row::new(vec![
/// Cell::from("Cell1"),
/// Cell::from("Cell2")
@ -290,16 +295,22 @@ impl<'a> Table<'a> {
/// Cell::from("Cell3"),
/// Cell::from("Cell4")
/// ]),
/// ]);
/// ],
/// [Constraint::Length(5), Constraint::Length(5)]
/// );
/// ```
pub fn new<T>(rows: T) -> Self
pub fn new<R, C>(rows: R, widths: C) -> Self
where
T: IntoIterator<Item = Row<'a>>,
R: IntoIterator<Item = Row<'a>>,
C: IntoIterator,
C::Item: AsRef<Constraint>,
{
let widths = widths.into_iter().map(|c| *c.as_ref()).collect_vec();
ensure_percentages_less_than_100(&widths);
Self {
block: None,
style: Style::default(),
widths: vec![],
widths,
column_spacing: 1,
highlight_style: Style::default(),
highlight_symbol: None,
@ -319,7 +330,8 @@ impl<'a> Table<'a> {
///
/// ```rust
/// # use ratatui::{prelude::*, widgets::*};
/// let table = Table::new(vec![
/// let table = Table::new(
/// vec![
/// Row::new(vec![
/// Cell::from("Cell1"),
/// Cell::from("Cell2")
@ -328,7 +340,10 @@ impl<'a> Table<'a> {
/// Cell::from("Cell3"),
/// Cell::from("Cell4")
/// ]),
/// ]).block(Block::default().title("Table"));
/// ],
/// [Constraint::Length(5), Constraint::Length(5)]
/// )
/// .block(Block::default().title("Table"));
/// ```
pub fn block(mut self, block: Block<'a>) -> Self {
self.block = Some(block);
@ -344,12 +359,13 @@ impl<'a> Table<'a> {
///
/// ```rust
/// # use ratatui::{prelude::*, widgets::*};
/// let table = Table::new(vec![
/// Row::new(vec![
/// Cell::from("Cell1"),
/// Cell::from("Cell2")
/// ])
/// ]).header(
/// let table = Table::new(
/// vec![
/// Row::new(vec![Cell::from("Cell1"), Cell::from("Cell2")])
/// ],
/// [Constraint::Length(20), Constraint::Length(20)]
/// )
/// .header(
/// Row::new(vec![
/// Cell::from("Header Cell 1"),
/// Cell::from("Header Cell 2")
@ -370,13 +386,13 @@ impl<'a> Table<'a> {
///
/// ```rust
/// # use ratatui::{prelude::*, widgets::*};
/// let table = Table::new(vec![]).widths([Constraint::Length(5), Constraint::Length(5)]);
/// let table = Table::new(vec![]).widths(&[Constraint::Length(5), Constraint::Length(5)]);
/// let table = Table::default().widths([Constraint::Length(5), Constraint::Length(5)]);
/// let table = Table::default().widths(&[Constraint::Length(5), Constraint::Length(5)]);
///
/// // widths could also be computed at runtime
/// let widths = vec![Constraint::Length(5), Constraint::Length(5)];
/// let table = Table::new(vec![]).widths(widths.clone());
/// let table = Table::new(vec![]).widths(&widths);
/// let table = Table::default().widths(widths.clone());
/// let table = Table::default().widths(&widths);
/// ```
pub fn widths<I, C>(mut self, widths: I) -> Self
where
@ -384,14 +400,7 @@ impl<'a> Table<'a> {
C: AsRef<Constraint>,
{
let widths = widths.into_iter().map(|c| *c.as_ref()).collect_vec();
let between_0_and_100 = |&w| match w {
Constraint::Percentage(p) => p <= 100,
_ => true,
};
assert!(
widths.iter().all(between_0_and_100),
"Percentages should be between 0 and 100 inclusively."
);
ensure_percentages_less_than_100(&widths);
self.widths = widths;
self
}
@ -491,6 +500,7 @@ impl<'a> Table<'a> {
/// space to the last column or to distribute it equally.
///
/// # Examples
///
/// Create a table that needs at least 30 columns to display. Any extra space will be assigned
/// to the last column.
#[cfg_attr(feature = "unstable", doc = " ```")]
@ -499,8 +509,7 @@ impl<'a> Table<'a> {
/// # use ratatui::layout::SegmentSize;
/// # use ratatui::widgets::Table;
/// let widths = [Constraint::Min(10), Constraint::Min(10), Constraint::Min(10)];
/// let table = Table::new([])
/// .widths(widths)
/// let table = Table::new([], widths)
/// .segment_size(SegmentSize::LastTakesRemainder);
/// ```
#[stability::unstable(
@ -514,6 +523,17 @@ impl<'a> Table<'a> {
}
}
fn ensure_percentages_less_than_100(widths: &[Constraint]) {
let between_0_and_100 = |&w| match w {
Constraint::Percentage(p) => p <= 100,
_ => true,
};
assert!(
widths.iter().all(between_0_and_100),
"Percentages should be between 0 and 100 inclusively."
);
}
impl<'a> Styled for Table<'a> {
type Item = Table<'a>;
@ -710,30 +730,30 @@ mod tests {
#[test]
#[should_panic]
fn table_invalid_percentages() {
Table::new(vec![]).widths([Constraint::Percentage(110)]);
Table::new(vec![], [Constraint::Percentage(110)]);
}
#[test]
fn widths_conversions() {
let array = [Constraint::Percentage(100)];
let table = Table::new(vec![]).widths(array);
let table = Table::new(vec![], array);
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "array");
let array_ref = &[Constraint::Percentage(100)];
let table = Table::new(vec![]).widths(array_ref);
let table = Table::new(vec![], array_ref);
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "array ref");
let vec = vec![Constraint::Percentage(100)];
let slice = vec.as_slice();
let table = Table::new(vec![]).widths(slice);
let table = Table::new(vec![], slice);
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "slice");
let vec = vec![Constraint::Percentage(100)];
let table = Table::new(vec![]).widths(vec);
let table = Table::new(vec![], vec);
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "vec");
let vec_ref = &vec![Constraint::Percentage(100)];
let table = Table::new(vec![]).widths(vec_ref);
let table = Table::new(vec![], vec_ref);
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "vec ref");
}
@ -751,9 +771,7 @@ mod tests {
selection_width: u16,
expected: &[(u16, u16)],
) {
let table = Table::new(vec![])
.segment_size(segment_size)
.widths(constraints);
let table = Table::new(vec![], constraints).segment_size(segment_size);
let widths = table.get_columns_widths(available_width, selection_width);
assert_eq!(widths, expected);
@ -997,12 +1015,14 @@ mod tests {
#[test]
fn test_render_table_with_alignment() {
let mut buf = Buffer::empty(Rect::new(0, 0, 20, 3));
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec![Line::from("Left").alignment(Alignment::Left)]),
Row::new(vec![Line::from("Center").alignment(Alignment::Center)]),
Row::new(vec![Line::from("Right").alignment(Alignment::Right)]),
])
.widths([Percentage(100)]);
],
[Percentage(100)],
);
Widget::render(table, Rect::new(0, 0, 20, 3), &mut buf);
@ -1047,7 +1067,7 @@ mod tests {
#[test]
fn table_can_be_stylized() {
assert_eq!(
Table::new(vec![Row::new(vec![Cell::from("")])])
Table::new(vec![Row::new(vec![Cell::from("")])], [Percentage(100)])
.black()
.on_white()
.bold()

View file

@ -19,19 +19,21 @@ fn widgets_table_column_spacing_can_be_changed() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]),
])
],
[
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
],
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.widths([
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
])
.column_spacing(column_spacing);
f.render_widget(table, size);
})
@ -117,15 +119,17 @@ fn widgets_table_columns_widths_can_use_fixed_length_constraints() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]),
])
],
widths,
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.widths(widths);
.block(Block::default().borders(Borders::ALL));
f.render_widget(table, size);
})
.unwrap();
@ -206,15 +210,17 @@ fn widgets_table_columns_widths_can_use_percentage_constraints() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]),
])
],
widths,
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.widths(widths)
.column_spacing(0);
f.render_widget(table, size);
})
@ -313,15 +319,17 @@ fn widgets_table_columns_widths_can_use_mixed_constraints() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]),
])
],
widths,
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.widths(widths);
.block(Block::default().borders(Borders::ALL));
f.render_widget(table, size);
})
.unwrap();
@ -423,15 +431,17 @@ fn widgets_table_columns_widths_can_use_ratio_constraints() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]),
])
],
widths,
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.widths(widths)
.column_spacing(0);
f.render_widget(table, size);
})
@ -528,20 +538,22 @@ fn widgets_table_can_have_rows_with_multi_lines() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]).height(2),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]).height(2),
])
],
[
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
],
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.highlight_symbol(">> ")
.widths([
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
])
.column_spacing(1);
f.render_stateful_widget(table, size, state);
})
@ -622,21 +634,23 @@ fn widgets_table_enable_always_highlight_spacing() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]).height(2),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]).height(2),
])
],
[
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
],
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.highlight_symbol(">> ")
.highlight_spacing(space)
.widths([
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
])
.column_spacing(1);
f.render_stateful_widget(table, size, state);
})
@ -756,8 +770,10 @@ fn widgets_table_can_have_elements_styled_individually() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
Row::new(vec!["Row11", "Row12", "Row13"]).style(Style::default().fg(Color::Green)),
let table = Table::new(
vec![
Row::new(vec!["Row11", "Row12", "Row13"])
.style(Style::default().fg(Color::Green)),
Row::new(vec![
Cell::from("Row21"),
Cell::from("Row22").style(Style::default().fg(Color::Yellow)),
@ -768,16 +784,17 @@ fn widgets_table_can_have_elements_styled_individually() {
.style(Style::default().fg(Color::Red)),
])
.style(Style::default().fg(Color::LightGreen)),
])
],
[
Constraint::Length(6),
Constraint::Length(6),
Constraint::Length(6),
],
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
.highlight_symbol(">> ")
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
.widths([
Constraint::Length(6),
Constraint::Length(6),
Constraint::Length(6),
])
.column_spacing(1);
f.render_stateful_widget(table, size, &mut state);
})
@ -831,14 +848,16 @@ fn widgets_table_should_render_even_if_empty() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![])
let table = Table::new(
vec![],
[
Constraint::Length(6),
Constraint::Length(6),
Constraint::Length(6),
],
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]))
.block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
.widths([
Constraint::Length(6),
Constraint::Length(6),
Constraint::Length(6),
])
.column_spacing(1);
f.render_widget(table, size);
})
@ -869,17 +888,19 @@ fn widgets_table_columns_dont_panic() {
// based on https://github.com/fdehau/tui-rs/issues/470#issuecomment-852562848
let table1_width = 98;
let table1 = Table::new(vec![Row::new(vec!["r1", "r2", "r3", "r4"])])
.header(Row::new(vec!["h1", "h2", "h3", "h4"]))
.block(Block::default().borders(Borders::ALL))
.highlight_symbol(">> ")
.column_spacing(1)
.widths([
let table1 = Table::new(
vec![Row::new(vec!["r1", "r2", "r3", "r4"])],
[
Constraint::Percentage(15),
Constraint::Percentage(15),
Constraint::Percentage(25),
Constraint::Percentage(45),
]);
],
)
.header(Row::new(vec!["h1", "h2", "h3", "h4"]))
.block(Block::default().borders(Borders::ALL))
.highlight_symbol(">> ")
.column_spacing(1);
let mut state = TableState::default();
@ -899,21 +920,23 @@ fn widgets_table_should_clamp_offset_if_rows_are_removed() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![
let table = Table::new(
vec![
Row::new(vec!["Row01", "Row02", "Row03"]),
Row::new(vec!["Row11", "Row12", "Row13"]),
Row::new(vec!["Row21", "Row22", "Row23"]),
Row::new(vec!["Row31", "Row32", "Row33"]),
Row::new(vec!["Row41", "Row42", "Row43"]),
Row::new(vec!["Row51", "Row52", "Row53"]),
])
],
[
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
],
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.widths([
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
])
.column_spacing(1);
f.render_stateful_widget(table, size, &mut state);
})
@ -935,14 +958,16 @@ fn widgets_table_should_clamp_offset_if_rows_are_removed() {
terminal
.draw(|f| {
let size = f.size();
let table = Table::new(vec![Row::new(vec!["Row31", "Row32", "Row33"])])
let table = Table::new(
vec![Row::new(vec!["Row31", "Row32", "Row33"])],
[
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
],
)
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
.block(Block::default().borders(Borders::ALL))
.widths([
Constraint::Length(5),
Constraint::Length(5),
Constraint::Length(5),
])
.column_spacing(1);
f.render_stateful_widget(table, size, &mut state);
})