Skip to content
Open
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
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ These attributes can be applied to the struct itself.
- **`impl_vec_data_provider`** - If given, then [`TableDataProvider`] is automatically implemented for `Vec<ThisStruct>` to allow
for easy local data use. See the [simple example](https://github.com/synphonyte/leptos-struct-table/blob/master/examples/simple/src/main.rs) for more information.
- **`row_type`** - Specifies the type of the rows in the table. Defaults to the struct that this is applied to. See the [custom_type example](https://github.com/synphonyte/leptos-struct-table/blob/master/examples/custom_type/src/main.rs) for more information.
- **`column_index_type`** - A type by which the columns are indexed, "usize" is the default. "enum" will generate an enum with the row-struct's field names as variants. See the [column_index_type example](https://github.com/synphonyte/leptos-struct-table/blob/master/examples/column_index_type/src/main.rs) for more information.

- **`i18n`** - Allows to specify the i18n scope for all fields of the struct as well as the `i18n` module path which defaults to `crate::i18n`. See [I18n](#i18n) for more information.

### Field attributes
Expand Down Expand Up @@ -341,6 +343,57 @@ pub fn App() -> impl IntoView {

Please have a look at the [editable example](https://github.com/Synphonyte/leptos-struct-table/tree/master/examples/editable/src/main.rs) for a fully working example.


# Column index type
Configured via the table annotation on a TableRow struct.

```rust
#[table(columne_index_type = value)]
```

Current supported column index type **values**: `"usize"` or `"Enum"`.\
The column type is used to refer to columns in various places, some of which listed below:
- Custom cell renderers via [`DefaultTableCellRendererProps#index`]
- Custom header cell renderers via [`DefaultTableHeaderCellRendererProps#index`]
- Head events via [`TableHeadEvent#index`]
- In [`TableRow#col_name`] as `col_index` parameter type.
- In [`get_sorting_for_column`] in both parameters.

## usize column index type
This is the default index type.

It can be set explicitely:
```rust
#[derive(TableRow, Clone, Default, Debug)]
#[table(impl_vec_data_provider, column_index_type = "usize")]
pub struct Book {
id: u32, // index = 0
#[table(skip)]
content: String, // no index (skipped)
title: String, // index = 1
}
```
Usize indexes start at 0 at the first relevant struct field. Fields marked `skip` do not have an index.

## Enum column index type

Used as follows:
```rust
#[derive(TableRow, Clone, Default, Debug)]
#[table(impl_vec_data_provider, column_index_type = "Enum")]
// Proc-macro `table` generates enum "{struct_name}Column", in this case: BookColumn
pub struct Book {
id: u32, // index = BookColumn::Id
#[table(skip)]
content: String, // no index (skipped)
title: String, // index = BookColumn::Title
}
```

Fields are converted to UpperCammelCase for their generated enum variant.
See the [column_index_type example](./examples/column_index_type/src/main.rs) for more information.


## Pagination / Virtualization / InfiniteScroll

This table component supports different display acceleration strategies. You can set them through the `display_strategy` prop of
Expand Down
18 changes: 18 additions & 0 deletions examples/column_index_type/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "column_index_type"
version = "0.1.0"
edition = "2021"

[dependencies]
leptos = { version = "0.8", features = ["csr"] }
leptos-struct-table = { path = "../..", features = ["chrono"] }
chrono = { version = "0.4" }
console_error_panic_hook = "0.1"
console_log = "1"
log = "0.4"
derive_more = { version = "0.99" }

[dev-dependencies]
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3.0"
web-sys = "0.3"
18 changes: 18 additions & 0 deletions examples/column_index_type/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### A table example with a generated enum as column index type.
Two custom renders are also used to show where the generated enum type needs to fill in and how it can be used.

To make this example work, you must download / fork the whole repo because this is in the Cargo.toml: `leptos-struct-table = { path = "../.." }`.

If you don't have it installed already, install [Trunk](https://trunkrs.dev/)
as well as the wasm32-unknown-unknown target:

```bash
cargo install trunk
rustup target add wasm32-unknown-unknown
```

Then, to run this example, execute in a terminal:

```bash
trunk serve --open
```
5 changes: 5 additions & 0 deletions examples/column_index_type/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!DOCTYPE html>
<html>
<head></head>
<body></body>
</html>
121 changes: 121 additions & 0 deletions examples/column_index_type/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#![deny(missing_docs)]
//! Column index showcase example.

use ::chrono::NaiveDate;
use derive_more::{Deref, DerefMut};
use leptos::prelude::*;
use leptos_struct_table::*;
use std::sync::Arc;
use leptos::web_sys;
use std::marker::PhantomData;

/// Custom row renderer that adds a link to the end of the row
#[allow(unused_variables, non_snake_case)]
pub fn CustomTableRowRenderer(
// The class attribute for the row element. Generated by the classes provider.
class: Signal<String>,
// The row to render.
row: RwSignal<Book>,
// The index of the row. Starts at 0 for the first body row.
index: usize,
// The selected state of the row. True, when the row is selected.
selected: Signal<bool>,
// Event handler callback when this row is selected
on_select: EventHandler<web_sys::MouseEvent>,
// Phantom data needs the column index type (a generated enum in this example)
_phantom: PhantomData<BookColumn>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the component isn't generic, this shouldn't be necessary.

I think instead of adding the PhantomData to the renderer function's signature we should add it as a field to the generated struct in the macro renderer_fn!.

) -> impl IntoView {

view! {
<tr class=class on:click=move |mouse_event| on_select.run(mouse_event)>
{TableRow::render_row(row, index)}
<td>
<a href=move || format!("/some-path/{}", row.read().title)>"Some link"</a>
</td>
</tr>
}
}


#[component]
#[allow(unused_variables)]
pub fn ColorCellRenderer(
/// Base cell rendere classes
#[prop(into)] class: String,
/// Value of this cell
value: Signal<String>,
/// Row containing this cell
row: RwSignal<Book>,
/// Column Index of the cell. (variant of a generated enum in this example)
index: BookColumn,
) -> impl IntoView {
match index {
BookColumn::Title => view! { <span style="color: blue;">{ value }</span> },
BookColumn::Author => view! { <span style="color: red;">{ value }</span> },
BookColumn::PublishDate => view! { <span style="color: green;">{ value }</span> },
BookColumn::Description => view! { <span style="color: yellow;">{ value }</span> }
}
}


/// This generates the component BookTable
#[derive(TableRow, Clone)]
#[table(sortable, impl_vec_data_provider, column_index_type = "Enum")]
pub struct Book {
/// Title of the book.
pub title: String,
/// Author of the book.
#[table(renderer = "ColorCellRenderer")]
pub author: String,
/// Date when book has been published.
pub publish_date: Option<NaiveDate>,
/// Description of the book. Optional.
#[table(none_value = "-")]
pub description: Option<String>,
}

/// New-type pattern because otherwise the impl TableRow doesn't work because of orphan rules.
#[derive(Deref, DerefMut, Clone)]
pub struct ArcBook(Arc<Book>);

fn main() {
_ = console_log::init_with_level(log::Level::Debug);
console_error_panic_hook::set_once();

mount_to_body(|| {
let rows = vec![
Book {
title: "The Great Gatsby".to_string(),
author: "F. Scott Fitzgerald".to_string(),
publish_date: Some(NaiveDate::from_ymd_opt(1925, 4, 10).unwrap()),
description: Some(
"A story of wealth, love, and the American Dream in the 1920s.".to_string(),
),
},
Book {
title: "The Grapes of Wrath".to_string(),
author: "John Steinbeck".to_string(),
publish_date: Some(NaiveDate::from_ymd_opt(1939, 4, 14).unwrap()),
description: None,
},
Book {
title: "Nineteen Eighty-Four".to_string(),
author: "George Orwell".to_string(),
publish_date: Some(NaiveDate::from_ymd_opt(1949, 6, 8).unwrap()),
description: None,
},
Book {
title: "Ulysses".to_string(),
author: "James Joyce".to_string(),
publish_date: Some(NaiveDate::from_ymd_opt(1922, 2, 2).unwrap()),
description: None,
},
];

view! {
<table>
<TableContent rows scroll_container="html" />
</table>
}
})
}
5 changes: 4 additions & 1 deletion examples/custom_renderers_svg/src/renderers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use crate::Form;
use leptos::prelude::*;
use leptos::web_sys;
use leptos_struct_table::*;
use std::marker::PhantomData;


const ROW_HEIGHT: usize = 30;
const ROW_HEIGHT_HALF: usize = ROW_HEIGHT / 2;
Expand All @@ -28,6 +30,7 @@ pub fn SvgRowRenderer(
index: usize,
selected: Signal<bool>,
on_select: EventHandler<web_sys::MouseEvent>,
_phantom: PhantomData<usize>
) -> impl IntoView {
let transform = y_transform_from_index(index);

Expand Down Expand Up @@ -108,7 +111,7 @@ pub fn SvgHeadCellRenderer<F>(
children: Children,
) -> impl IntoView
where
F: Fn(TableHeadEvent) + 'static,
F: Fn(TableHeadEvent<usize>) + 'static,
{
let style = default_th_sorting_style(sort_priority, sort_direction);

Expand Down
3 changes: 3 additions & 0 deletions examples/custom_row_renderer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use ::uuid::Uuid;
use leptos::prelude::*;
use leptos::web_sys;
use leptos_struct_table::*;
use std::marker::PhantomData;


/// Custom row renderer that adds a link to the end of the row
#[allow(unused_variables, non_snake_case)]
Expand All @@ -20,6 +22,7 @@ pub fn CustomTableRowRenderer(
selected: Signal<bool>,
// Event handler callback when this row is selected
on_select: EventHandler<web_sys::MouseEvent>,
_phantom: PhantomData<usize>
) -> impl IntoView {

view! {
Expand Down
2 changes: 1 addition & 1 deletion examples/editable/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct Book {
pub publish_date: NaiveDate,
}

impl TableDataProvider<Book> for RwSignal<Vec<Book>> {
impl TableDataProvider<Book, usize> for RwSignal<Vec<Book>> {
async fn get_rows(&self, _: Range<usize>) -> Result<(Vec<Book>, Range<usize>), String> {
let books = self.get_untracked().to_vec();
let len = books.len();
Expand Down
2 changes: 1 addition & 1 deletion examples/paginated_rest_datasource/src/data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl BreweryDataProvider {
}
}

impl PaginatedTableDataProvider<Brewery> for BreweryDataProvider {
impl PaginatedTableDataProvider<Brewery, usize> for BreweryDataProvider {
const PAGE_ROW_COUNT: usize = 200;

async fn get_page(&self, page_index: usize) -> Result<Vec<Brewery>, String> {
Expand Down
2 changes: 1 addition & 1 deletion examples/pagination/src/data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl BreweryDataProvider {
}
}

impl PaginatedTableDataProvider<Brewery> for BreweryDataProvider {
impl PaginatedTableDataProvider<Brewery, usize> for BreweryDataProvider {
const PAGE_ROW_COUNT: usize = 200;

async fn get_page(&self, page_index: usize) -> Result<Vec<Brewery>, String> {
Expand Down
2 changes: 1 addition & 1 deletion examples/serverfn_sqlx/src/data_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub struct CustomerTableDataProvider {
pub name: RwSignal<String>,
}

impl TableDataProvider<Customer> for CustomerTableDataProvider {
impl TableDataProvider<Customer, usize> for CustomerTableDataProvider {
async fn get_rows(&self, range: Range<usize>) -> Result<(Vec<Customer>, Range<usize>), String> {
list_customers(CustomerQuery {
name: self.name.get_untracked().trim().to_string(),
Expand Down
3 changes: 2 additions & 1 deletion examples/tailwind/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use tailwind::TailwindClassesPreset;
#[table(
sortable,
classes_provider = "TailwindClassesPreset",
impl_vec_data_provider
impl_vec_data_provider,
column_index_type = "Enum"
)]
pub struct Book {
pub id: u32,
Expand Down
6 changes: 3 additions & 3 deletions src/components/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ use leptos::prelude::*;

/// The default cell renderer. Uses the `<td>` element.
#[component]
pub fn DefaultTableCellRenderer<Row, T, M>(
pub fn DefaultTableCellRenderer<Row, Column, T, M>(
/// The class attribute for the cell element. Generated by the classes provider.
class: String,
/// The value to display.
value: Signal<T>,
/// Event handler called when the cell is changed. In this default renderer this will never happen.
row: RwSignal<Row>,
/// The index of the column. Starts at 0.
index: usize,
/// The index of the column.
index: Column,
options: T::RenderOptions,
#[prop(optional)] _marker: PhantomData<M>,
) -> impl IntoView
Expand Down
8 changes: 6 additions & 2 deletions src/components/row.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::marker::PhantomData;

use crate::EventHandler;
use crate::table_row::TableRow;
use leptos::prelude::*;

/// The default table row renderer. Uses the `<tr>` element. Please note that this
/// is **NOT** a `#[component]`.
#[allow(unused_variables)]
pub fn DefaultTableRowRenderer<Row>(
pub fn DefaultTableRowRenderer<Row, Column>(
// The class attribute for the row element. Generated by the classes provider.
class: Signal<String>,
// The row to render.
Expand All @@ -16,9 +18,11 @@ pub fn DefaultTableRowRenderer<Row>(
selected: Signal<bool>,
// Event handler callback when this row is selected
on_select: EventHandler<web_sys::MouseEvent>,
_phantom: PhantomData<Column>,
) -> impl IntoView
where
Row: TableRow + 'static,
Row: TableRow<Column> + 'static,
Column: Copy + Send + Sync + 'static,
{
view! {
<tr class=class on:click=move |mouse_event| on_select.run(mouse_event)>
Expand Down
Loading