TableState, ListState, and ScrollbarState can now be serialized and deserialized
using serde.
```rust
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct AppState {
list_state: ListState,
table_state: TableState,
scrollbar_state: ScrollbarState,
}
let app_state = AppState::default();
let serialized = serde_json::to_string(app_state);
let app_state = serde_json::from_str(serialized);
```
The `ratatui::style::palette::tailwind` module contains the default
Tailwind color palette. This is useful for styling components with
colors that match the Tailwind color palette.
See https://tailwindcss.com/docs/customizing-colors for more information
on Tailwind.
```rust
use ratatui::style::palette::tailwind::SLATE;
Line::styled("Hello", SLATE.c500);
```
Any iterator whose item is convertible into `Row` can now be
collected into a `Table`.
Where previously, `Table::new` accepted `IntoIterator<Item = Row>`, it
now accepts `IntoIterator<Item: Into<Row>>`.
BREAKING CHANGE:
The compiler can no longer infer the element type of the container
passed to `Table::new()`. For example, `Table::new(vec![], widths)`
will no longer compile, as the type of `vec![]` can no longer be
inferred.
Any iterator whose item is convertible into `Line` can now be
collected into `Tabs`.
In addition, where previously `Tabs::new` required a `Vec`, it can now
accept any object that implements `IntoIterator` with an item type
implementing `Into<Line>`.
BREAKING CHANGE:
Calls to `Tabs::new()` whose argument is collected from an iterator
will no longer compile. For example,
`Tabs::new(["a","b"].into_iter().collect())` will no longer compile,
because the return type of `.collect()` can no longer be inferred to
be a `Vec<_>`.
In https://github.com/ratatui-org/ratatui/pull/660 we introduced the
segment_size field to the Table struct. However, we forgot to update
the default() implementation to match the new() implementation. This
meant that the default() implementation picked up SegmentSize::default()
instead of SegmentSize::None.
Additionally the introduction of Table::default() in an earlier PR,
https://github.com/ratatui-org/ratatui/pull/339, was also missing the
default for the column_spacing field (1).
This commit fixes the default() implementation to match the new()
implementation of these two fields by implementing the Default trait
manually.
BREAKING CHANGE: The default() implementation of Table now sets the
column_spacing field to 1 and the segment_size field to
SegmentSize::None. This will affect the rendering of a small amount of
apps.
This allows for multi-line symbols to be used as the highlight symbol.
```rust
let table = Table::new(rows, widths)
.highlight_symbol(Text::from(vec![
"".into(),
" █ ".into(),
" █ ".into(),
"".into(),
]));
```
Any iterator whose item is convertible into `ListItem` can now be
collected into a `List`.
```rust
let list: List = (0..3).map(|i| format!("Item{i}")).collect();
```
Link to the contributing, changelog, and breaking changes docs at the
top of the page instead of just in in the main part of the doc. This
makes it easier to find them.
Rearrange the links to be in a more logical order.
Use link refs for all the links
Fix up the CI link to point to the right workflow
Previously, `patch_style` and `reset_style` in `Text`, `Line` and `Span`
were using a mutable reference to `Self`. To be more consistent with
the rest of `ratatui`, which is using fluent setters, these now take
ownership of `Self` and return it.
The `Row::new` constructor accepts a single argument that implements
`IntoIterator`. This commit adds an implementation of `FromIterator`,
as a thin wrapper around `Row::new`. This allows `.collect::<Row>()`
to be used at the end of an iterator chain, rather than wrapping the
entire iterator chain in `Row::new`.
* feat(layout): add a Rect::clamp() method
This ensures a rectangle does not end up outside an area. This is useful
when you want to be able to dynamically move a rectangle around, but
keep it constrained to a certain area.
For example, this can be used to implement a draggable window that can
be moved around, but not outside the terminal window.
```rust
let window_area = Rect::new(state.x, state.y, 20, 20).clamp(area);
state.x = rect.x;
state.y = rect.y;
```
* refactor: use rstest to simplify clamp test
* fix: use rstest description instead of string
test layout::rect::tests:🗜️:case_01_inside ... ok
test layout::rect::tests:🗜️:case_02_up_left ... ok
test layout::rect::tests:🗜️:case_04_up_right ... ok
test layout::rect::tests:🗜️:case_05_left ... ok
test layout::rect::tests:🗜️:case_03_up ... ok
test layout::rect::tests:🗜️:case_06_right ... ok
test layout::rect::tests:🗜️:case_07_down_left ... ok
test layout::rect::tests:🗜️:case_08_down ... ok
test layout::rect::tests:🗜️:case_09_down_right ... ok
test layout::rect::tests:🗜️:case_10_too_wide ... ok
test layout::rect::tests:🗜️:case_11_too_tall ... ok
test layout::rect::tests:🗜️:case_12_too_large ... ok
* fix: less ambiguous docs for this / other rect
* fix: move rstest to dev deps
This avoid creating a block with no borders and then settings Borders::ALL. i.e.
```diff
- Block::default().borders(Borders::ALL);
+ Block::bordered();
```
This method splits a Rect and returns a fixed-size array of the
resulting Rects. This allows the caller to use array destructuring
to get the individual Rects.
```rust
use Constraint::*;
let layout = &Layout::vertical([Length(1), Min(0)]);
let [top, main] = area.split(&layout);
```
This allows Table constructors to accept any type that implements
Into<Constraint> instead of just AsRef<Constraint>. This is useful when
you want to specify a fixed size for a table columns, but don't want to
explicitly create a Constraint::Length yourself.
```rust
Table::new(rows, [1,2,3])
Table::default().widths([1,2,3])
```
This allows Layout constructors to accept any type that implements
Into<Constraint> instead of just AsRef<Constraint>. This is useful when
you want to specify a fixed size for a layout, but don't want to
explicitly create a Constraint::Length yourself.
```rust
Layout::new(Direction::Vertical, [1, 2, 3]);
Layout::horizontal([1, 2, 3]);
Layout::vertical([1, 2, 3]);
Layout::default().constraints([1, 2, 3]);
```
* feat(layout): add vertical and horizontal constructors
This commit adds two new constructors to the `Layout` struct, which
allow the user to create a vertical or horizontal layout with default
values.
```rust
let layout = Layout::vertical([
Constraint::Length(10),
Constraint::Min(5),
Constraint::Length(10),
]);
let layout = Layout::horizontal([
Constraint::Length(10),
Constraint::Min(5),
Constraint::Length(10),
]);
```
Important note: this also fixes a wrong mapping between ratatui's gray
and termwiz's grey. `ratatui::Color::Gray` now maps to
`termwiz::color::AnsiColor::Silver`
* feat: accept Color and Modifier for all Styles
All style related methods now accept `S: Into<Style>` instead of
`Style`.
`Color` and `Modifier` implement `Into<Style>` so this is allows for
more ergonomic usage. E.g.:
```rust
Line::styled("hello", Style::new().red());
Line::styled("world", Style::new().bold());
// can now be simplified to
Line::styled("hello", Color::Red);
Line::styled("world", Modifier::BOLD);
```
Fixes https://github.com/ratatui-org/ratatui/issues/694
BREAKING CHANGE: All style related methods now accept `S: Into<Style>`
instead of `Style`. This means that if you are already passing an
ambiguous type that implements `Into<Style>` you will need to remove
the `.into()` call.
`Block` style methods can no longer be called from a const context as
trait functions cannot (yet) be const.
* feat: add tuple conversions to Style
Adds conversions for various Color and Modifier combinations
* chore: add unit tests
* feat(table): Add a Table::footer method
Signed-off-by: Antonio Yang <yanganto@gmail.com>
* feat(table): Add a Row::top_margin method
- add Row::top_margin
- update table example
Signed-off-by: Antonio Yang <yanganto@gmail.com>
---------
Signed-off-by: Antonio Yang <yanganto@gmail.com>
At close to 2000 lines of code, the table widget was getting a bit
unwieldy. This commit splits it into multiple files, one for each
struct, and one for the table itself.
Also refactors the table rendering code to be easier to maintain.
This allows us to use Line as a child of other widgets, and to use
Line::render() to render it rather than calling buffer.set_line().
```rust
frame.render_widget(Line::raw("Hello, world!"), area);
// or
Line::raw("Hello, world!").render(frame, area);
```