Skip to content

Commit 66ef68a

Browse files
committed
updated svg example
1 parent 89bdc40 commit 66ef68a

10 files changed

Lines changed: 129 additions & 103 deletions

File tree

examples/custom_renderers_svg/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ chrono = { version = "0.4", features=["serde"] }
1010
console_error_panic_hook = "0.1"
1111
console_log = "1"
1212
log = "0.4"
13-
serde = "1"
1413
async-trait = "0.1"
1514

1615
[dev-dependencies]

examples/custom_renderers_svg/src/main.rs

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,13 @@ mod renderers;
22

33
use renderers::*;
44

5-
use async_trait::async_trait;
65
use leptos::*;
76
use leptos_struct_table::*;
8-
use serde::{Deserialize, Serialize};
97

108
// This generates the component BookTable
11-
#[derive(TableComponent, Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
12-
#[table(
13-
row_renderer = "SvgRowRenderer",
14-
head_row_renderer = "g",
15-
head_cell_renderer = "SvgHeadCellRenderer",
16-
thead_renderer = "g",
17-
tbody_renderer = "g",
18-
tag = "g"
19-
)]
9+
#[derive(TableRow, Clone)]
10+
#[table(head_cell_renderer = "SvgHeadCellRenderer", impl_vec_data_provider)]
2011
pub struct Form {
21-
#[table(key, skip)]
22-
pub id: u32,
2312
#[table(renderer = "SvgTextCellRenderer")]
2413
pub name: String,
2514
#[table(renderer = "SvgPathCellRenderer")]
@@ -31,30 +20,32 @@ fn main() {
3120
console_error_panic_hook::set_once();
3221

3322
mount_to_body(|| {
34-
let items = create_rw_signal(
35-
36-
vec![
23+
let rows = vec![
3724
Form {
38-
id: 1,
3925
name: "Heart".to_string(),
4026
path: "M12.82 5.58l-.82.822l-.824-.824a5.375 5.375 0 1 0-7.601 7.602l7.895 7.895a.75.75 0 0 0 1.06 0l7.902-7.897a5.376 5.376 0 0 0-.001-7.599a5.38 5.38 0 0 0-7.611 0zm6.548 6.54L12 19.485L4.635 12.12a3.875 3.875 0 1 1 5.48-5.48l1.358 1.357a.75.75 0 0 0 1.073-.012L13.88 6.64a3.88 3.88 0 0 1 5.487 5.48z".to_string(),
4127
},
4228
Form {
43-
id: 2,
4429
name: "Bell".to_string(),
4530
path: "M12 1.996a7.49 7.49 0 0 1 7.496 7.25l.004.25v4.097l1.38 3.156a1.249 1.249 0 0 1-1.145 1.75L15 18.502a3 3 0 0 1-5.995.177L9 18.499H4.275a1.251 1.251 0 0 1-1.147-1.747L4.5 13.594V9.496c0-4.155 3.352-7.5 7.5-7.5zM13.5 18.5l-3 .002a1.5 1.5 0 0 0 2.993.145l.007-.147zM12 3.496c-3.32 0-6 2.674-6 6v4.41L4.656 17h14.697L18 13.907V9.509l-.003-.225A5.988 5.988 0 0 0 12 3.496z".to_string(),
4631
},
4732
Form {
48-
id: 3,
4933
name: "Star".to_string(),
5034
path: "M10.788 3.102c.495-1.003 1.926-1.003 2.421 0l2.358 4.778l5.273.766c1.107.16 1.549 1.522.748 2.303l-3.816 3.719l.901 5.25c.19 1.104-.968 1.945-1.959 1.424l-4.716-2.48l-4.715 2.48c-.99.52-2.148-.32-1.96-1.423l.901-5.251l-3.815-3.72c-.801-.78-.359-2.141.748-2.302L8.43 7.88l2.358-4.778zm1.21.937L9.74 8.614a1.35 1.35 0 0 1-1.016.739l-5.05.734l3.654 3.562c.318.31.463.757.388 1.195l-.862 5.029l4.516-2.375a1.35 1.35 0 0 1 1.257 0l4.516 2.375l-.862-5.03a1.35 1.35 0 0 1 .388-1.194l3.654-3.562l-5.05-.734a1.35 1.35 0 0 1-1.016-.739L11.998 4.04z".to_string(),
5135
}
52-
],
53-
);
36+
];
5437

5538
view! {
5639
<svg style="font-family: sans-serif;">
57-
<FormTable items=items/>
40+
<TableContent
41+
rows
42+
row_renderer=SvgRowRenderer
43+
loading_row_renderer=SvgLoadingRowRenderer
44+
error_row_renderer=SvgErrorRowRenderer
45+
thead_row_renderer=GRenderer
46+
thead_renderer=GRenderer
47+
tbody_renderer=GRenderer
48+
/>
5849
</svg>
5950
}
6051
})

examples/custom_renderers_svg/src/renderers.rs

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,79 @@ use leptos_struct_table::*;
44
const ROW_HEIGHT: usize = 30;
55
const ROW_HEIGHT_HALF: usize = ROW_HEIGHT / 2;
66

7-
#[allow(unused_variables)]
8-
#[component]
9-
pub fn SvgRowRenderer<F, K>(
10-
#[prop(into)] class: MaybeSignal<String>,
11-
#[prop(into)] key: K,
7+
wrapper_render_fn!(
8+
/// g
9+
GRenderer,
10+
g,
11+
);
12+
13+
#[allow(unused_variables, non_snake_case)]
14+
pub fn SvgRowRenderer<Row>(
15+
class: Signal<String>,
16+
row: Row,
1217
index: usize,
13-
#[prop(into)] selected: Signal<bool>,
14-
on_click: F,
15-
children: Children,
18+
selected: Signal<bool>,
19+
on_select: EventHandler<web_sys::MouseEvent>,
20+
on_change: EventHandler<ChangeEvent<Row>>,
1621
) -> impl IntoView
1722
where
18-
F: Fn(TableRowEvent<K>) + 'static,
19-
K: Clone + 'static,
23+
Row: RowRenderer + Clone + 'static,
2024
{
2125
let transform = format!("translate(0, {})", (index + 1) * ROW_HEIGHT);
2226

2327
view! {
24-
<g class=class
28+
<g
29+
class=class
2530
transform=transform
26-
on:click=move |mouse_event| on_click(TableRowEvent {
27-
key: key.clone(),
28-
index,
29-
mouse_event,
30-
})
31+
on:click=move |mouse_event| on_select.run(mouse_event)
3132
>
32-
<line x1="5" y1="0" x2="150" y2="0" stroke-width="1px" stroke="black" opacity="0.1" />
33-
{children()}
33+
<line
34+
x1="5"
35+
y1="0"
36+
x2="150"
37+
y2="0"
38+
stroke-width="1px"
39+
stroke="black"
40+
opacity="0.1"
41+
></line>
42+
{row.render_row(index, on_change)}
43+
</g>
44+
}
45+
}
46+
47+
#[allow(non_snake_case)]
48+
pub fn SvgErrorRowRenderer(err: String, index: usize, _col_count: usize) -> impl IntoView {
49+
let transform = transform_from_index(index, 0);
50+
51+
view! {
52+
<g transform=transform>
53+
<text x="0" y=ROW_HEIGHT_HALF dominant-baseline="central">
54+
{err}
55+
</text>
56+
</g>
57+
}
58+
}
59+
60+
#[allow(non_snake_case)]
61+
pub fn SvgLoadingRowRenderer(
62+
class: Signal<String>,
63+
inner_class: Signal<String>,
64+
index: usize,
65+
_col_count: usize,
66+
) -> impl IntoView {
67+
let transform = transform_from_index(index, 0);
68+
69+
view! {
70+
<g class=class transform=transform>
71+
<text x="0" y=ROW_HEIGHT_HALF class=inner_class dominant-baseline="central">
72+
Loading...
73+
</text>
3474
</g>
3575
}
3676
}
3777

3878
#[component]
39-
pub fn SvgHeadCellRenderer<C, F>(
79+
pub fn SvgHeadCellRenderer<F>(
4080
/// The class attribute for the head element. Generated by the classes provider.
4181
#[prop(into)]
4282
class: Signal<String>,
@@ -45,8 +85,6 @@ pub fn SvgHeadCellRenderer<C, F>(
4585
inner_class: String,
4686
/// The index of the column. Starts at 0 for the first column. The order of the columns is the same as the order of the fields in the struct.
4787
index: usize,
48-
/// The column enum variant. It is auto generated from the struct.
49-
column: C,
5088
/// The sort priority of the column. `None` if the column is not sorted. `0` means the column is the primary sort column.
5189
#[prop(into)]
5290
sort_priority: Signal<Option<usize>>,
@@ -58,8 +96,7 @@ pub fn SvgHeadCellRenderer<C, F>(
5896
children: Children,
5997
) -> impl IntoView
6098
where
61-
F: Fn(TableHeadEvent<C>) + 'static,
62-
C: 'static + Copy,
99+
F: Fn(TableHeadEvent) + 'static,
63100
{
64101
let style = move || {
65102
let sort = match sort_direction() {
@@ -79,13 +116,14 @@ where
79116
let transform = transform_from_index(index, 0);
80117

81118
view! {
82-
<g class=class
119+
<g
120+
class=class
83121
transform=transform
84122
on:click=move |mouse_event| on_click(TableHeadEvent {
85123
index,
86-
column,
87124
mouse_event,
88125
})
126+
89127
style=style
90128
>
91129
<text x="0" y=ROW_HEIGHT_HALF class=inner_class dominant-baseline="central">
@@ -98,26 +136,28 @@ where
98136
#[component]
99137
#[allow(unused_variables)]
100138
pub fn SvgTextCellRenderer<T, F>(
101-
#[prop(into)] class: MaybeSignal<String>,
139+
class: String,
102140
#[prop(into)] value: MaybeSignal<T>,
103141
on_change: F,
104142
index: usize,
105143
) -> impl IntoView
106144
where
107145
T: IntoView + Clone + 'static,
108-
F: Fn(String) + 'static,
146+
F: Fn(T) + 'static,
109147
{
110148
let x = x_from_index(index);
111149

112150
view! {
113-
<text x=x y=ROW_HEIGHT_HALF class=class dominant-baseline="central">{value}</text>
151+
<text x=x y=ROW_HEIGHT_HALF class=class dominant-baseline="central">
152+
{value}
153+
</text>
114154
}
115155
}
116156

117157
#[component]
118158
#[allow(unused_variables)]
119159
pub fn SvgPathCellRenderer<F>(
120-
#[prop(into)] class: MaybeSignal<String>,
160+
#[prop(into)] class: String,
121161
#[prop(into)] value: MaybeSignal<String>,
122162
on_change: F,
123163
index: usize,
@@ -127,9 +167,7 @@ where
127167
{
128168
let transform = transform_from_index(index, 3);
129169

130-
view! {
131-
<path transform=transform class=class d=value />
132-
}
170+
view! { <path transform=transform class=class d=value></path> }
133171
}
134172

135173
fn transform_from_index(index: usize, y: usize) -> String {

examples/editable/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ chrono = { version = "0.4", features=["serde"] }
1010
console_error_panic_hook = "0.1"
1111
console_log = "1"
1212
log = "0.4"
13-
serde = "1"
1413
async-trait = "0.1"
1514

1615
[dev-dependencies]

examples/editable/src/main.rs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,40 @@ mod tailwind;
44
use crate::renderer::*;
55
use async_trait::async_trait;
66
use chrono::NaiveDate;
7-
use leptos::logging::log;
87
use leptos::*;
98
use leptos_struct_table::*;
10-
use serde::{Deserialize, Serialize};
9+
use std::ops::Range;
1110
use tailwind::TailwindClassesPreset;
1211

1312
// This generates the component BookTable
14-
#[derive(TableComponent, Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
13+
#[derive(TableRow, Clone, Debug)]
1514
#[table(classes_provider = "TailwindClassesPreset")]
1615
pub struct Book {
17-
#[table(key)]
1816
pub id: u32,
1917
#[table(renderer = "InputCellRenderer")]
2018
pub title: String,
2119
#[table(renderer = "InputCellRenderer")]
2220
pub author: String,
23-
#[table(
24-
cell_class = "text-red-600 dark:text-red-400",
25-
head_class = "text-red-700 dark:text-red-300"
26-
)]
2721
pub publish_date: NaiveDate,
2822
}
2923

24+
#[async_trait(?Send)]
25+
impl TableDataProvider<Book> for RwSignal<Vec<Book>> {
26+
async fn get_rows(&self, range: Range<usize>) -> Result<(Vec<Book>, Range<usize>), String> {
27+
Ok((self.get_untracked()[range.clone()].to_vec(), range))
28+
}
29+
30+
async fn row_count(&self) -> Option<usize> {
31+
Some(self.get_untracked().len())
32+
}
33+
}
34+
3035
fn main() {
3136
_ = console_log::init_with_level(log::Level::Debug);
3237
console_error_panic_hook::set_once();
3338

3439
mount_to_body(|| {
35-
let items = create_rw_signal(vec![
40+
let rows = create_rw_signal(vec![
3641
Book {
3742
id: 1,
3843
title: "The Great Gatsby".to_string(),
@@ -59,28 +64,20 @@ fn main() {
5964
},
6065
]);
6166

62-
let on_change = move |evt: TableChangeEvent<Book, BookColumnName, BookColumnValue>| {
63-
items.update(|items| {
64-
items[evt.row_index] = match evt.new_value {
65-
BookColumnValue::Author(author) => Book {
66-
author,
67-
..evt.old_row
68-
},
69-
BookColumnValue::Title(title) => Book {
70-
title,
71-
..evt.old_row
72-
},
73-
_ => unreachable!(),
74-
};
67+
let on_change = move |evt: ChangeEvent<Book>| {
68+
rows.update(|rows| {
69+
rows[evt.row_index] = evt.changed_row;
7570
});
7671
};
7772

7873
view! {
7974
<div class="rounded-md overflow-clip m-10 border dark:border-gray-700 w-[50%]".to_string()>
80-
<BookTable class="mb-[-1px]".to_string() items=items on_change=on_change/>
75+
<table class="text-sm text-left text-gray-500 dark:text-gray-400 mb-[-1px]">
76+
<TableContent rows on_change/>
77+
</table>
8178
</div>
8279

83-
<pre>{move || format!("{:#?}", items())}</pre>
80+
<pre>{move || format!("{:#?}", rows())}</pre>
8481
}
8582
})
8683
}

examples/editable/src/renderer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use leptos::*;
22

33
/// A renderer that shows an <input> tag and emits the `on_change` event when the <input> is changed.
44
#[component]
5+
#[allow(unused_variables)]
56
pub fn InputCellRenderer<F>(
67
/// The class attribute for the cell element. Generated by the classes provider.
7-
#[prop(into)]
8-
class: MaybeSignal<String>,
8+
class: String,
99
/// The value to display.
1010
#[prop(into)]
1111
value: MaybeSignal<String>,

0 commit comments

Comments
 (0)