Skip to main content

dioxus_element_plug/components/
pagination.rs

1use dioxus::prelude::*;
2
3/// Pagination props
4#[derive(Props, Clone, PartialEq)]
5pub struct PaginationProps {
6    /// Total number of items
7    #[props(default = 0)]
8    pub total: u32,
9
10    /// Current page number
11    #[props(default = 1)]
12    pub current_page: u32,
13
14    /// Items per page
15    #[props(default = 10)]
16    pub page_size: u32,
17
18    /// Number of page buttons to show
19    #[props(default = 7)]
20    pub pager_count: u32,
21
22    /// Whether to show the total count
23    #[props(default = false)]
24    pub show_total: bool,
25
26    /// Whether to show the page size selector
27    #[props(default = false)]
28    pub show_size_picker: bool,
29
30    /// Whether to show the "Go to" input
31    #[props(default = false)]
32    pub show_jumper: bool,
33
34    /// Layout sections
35    #[props(default = "prev, pager, next".to_string())]
36    pub layout: String,
37
38    /// Whether the pagination is disabled
39    #[props(default = false)]
40    pub disabled: bool,
41
42    /// Whether to use small size
43    #[props(default = false)]
44    pub small: bool,
45
46    /// Page size options
47    #[props(default)]
48    pub page_sizes: Vec<u32>,
49
50    /// Change event handler (current page)
51    #[props(default)]
52    pub on_current_change: Option<EventHandler<u32>>,
53
54    /// Change event handler (page size)
55    #[props(default)]
56    pub on_size_change: Option<EventHandler<u32>>,
57
58    #[props(default)]
59    pub class: Option<String>,
60
61    #[props(default)]
62    pub style: Option<String>,
63}
64
65/// Pagination component for navigating paged data
66#[component]
67pub fn Pagination(props: PaginationProps) -> Element {
68    let mut class_names = vec!["el-pagination".to_string()];
69    if props.small { class_names.push("el-pagination--small".to_string()); }
70    if props.disabled { class_names.push("is-disabled".to_string()); }
71    if let Some(ref c) = props.class { class_names.push(c.clone()); }
72
73    let total_pages = if props.page_size > 0 {
74        (props.total + props.page_size - 1) / props.page_size
75    } else {
76        1
77    };
78    let total_pages = total_pages.max(1);
79
80    rsx! {
81        div {
82            class: "{class_names.join(\" \")}",
83            style: props.style.clone().unwrap_or_default(),
84            role: "pagination",
85
86            if props.show_total {
87                span {
88                    class: "el-pagination__total",
89                    "Total {props.total}"
90                }
91            }
92
93            // Previous button
94            button {
95                class: "btn-prev el-pagination__button",
96                disabled: props.disabled || props.current_page <= 1,
97                onclick: move |_| {
98                    if !props.disabled && props.current_page > 1 {
99                        if let Some(handler) = props.on_current_change {
100                            handler.call(props.current_page - 1);
101                        }
102                    }
103                },
104                "‹"
105            }
106
107            // Page numbers
108            span {
109                class: "el-pager",
110                for page in 1..=total_pages.min(props.pager_count) {
111                    button {
112                        class: {
113                            let mut cls = "el-pager__number".to_string();
114                            if page == props.current_page { cls.push_str(" is-active"); }
115                            cls
116                        },
117                        onclick: move |_| {
118                            if !props.disabled {
119                                if let Some(handler) = props.on_current_change {
120                                    handler.call(page);
121                                }
122                            }
123                        },
124                        "{page}"
125                    }
126                }
127                if total_pages > props.pager_count {
128                    span { class: "el-icon-more", "..." }
129                }
130            }
131
132            // Next button
133            button {
134                class: "btn-next el-pagination__button",
135                disabled: props.disabled || props.current_page >= total_pages,
136                onclick: move |_| {
137                    if !props.disabled && props.current_page < total_pages {
138                        if let Some(handler) = props.on_current_change {
139                            handler.call(props.current_page + 1);
140                        }
141                    }
142                },
143                "›"
144            }
145
146            if props.show_jumper {
147                span {
148                    class: "el-pagination__jump",
149                    "Go to"
150                    input {
151                        r#type: "number",
152                        class: "el-pagination__editor",
153                        value: "{props.current_page}",
154                        disabled: props.disabled,
155                    }
156                    "pages"
157                }
158            }
159        }
160    }
161}