leptos_pagination/hooks/
controls.rs1use default_struct_builder::DefaultBuilder;
2use leptos::prelude::*;
3use leptos_use::math::{use_not, use_or};
4use reactive_stores::Store;
5
6use crate::{PaginationState, PaginationStateStoreFields};
7
8#[must_use]
15pub fn use_pagination_controls(
16 state: Store<PaginationState>,
17 options: UsePaginationControlsOptions,
18) -> PaginationControls {
19 let UsePaginationControlsOptions {
20 display_page_count,
21 margin_page_count,
22 } = options;
23
24 let page_count = Signal::derive(move || state.page_count().get().unwrap_or_default());
25
26 let additional_page_count = display_page_count / 2;
27
28 let current_page: Signal<usize> = state.current_page().into();
29 let current_range_start =
30 Signal::derive(move || current_page.get().saturating_sub(additional_page_count));
31 let current_range_end =
32 Signal::derive(move || current_page.get().saturating_add(additional_page_count));
33
34 let merge_current_with_start =
35 Memo::new(move |_| current_range_start.get() <= margin_page_count);
36 let merge_current_with_end = Memo::new(move |_| {
37 current_range_end.get() + 1 >= page_count.get().saturating_sub(margin_page_count)
38 });
39
40 let start_range_end = Signal::derive(move || {
41 if merge_current_with_start.get() {
42 current_range_end.get()
43 } else {
44 margin_page_count + 1
45 }
46 });
47
48 let end_range_start = Signal::derive(move || {
49 if merge_current_with_end.get() {
50 current_range_start.get() + 1
51 } else {
52 page_count.get().saturating_sub(margin_page_count + 1)
53 }
54 });
55
56 let merge_all = Signal::derive(move || start_range_end.get() + 1 >= end_range_start.get());
57
58 PaginationControls {
59 current_page,
60 start_range: Memo::new(move |_| {
61 let end = if merge_all.get() {
62 page_count.get()
63 } else {
64 start_range_end.get()
65 };
66
67 (0..end).collect()
68 })
69 .into(),
70 end_range: Memo::new(move |_| {
71 if merge_all.get() {
72 vec![]
73 } else {
74 let start = end_range_start.get();
75 let end = page_count.get();
76 (start..end).collect()
77 }
78 })
79 .into(),
80 current_range: Memo::new(move |_| {
81 if merge_current_with_start.get() || merge_current_with_end.get() || merge_all.get() {
82 vec![]
83 } else {
84 let start = current_page.get() - margin_page_count;
85 let end = current_page.get() + margin_page_count;
86 (start..=end).collect()
87 }
88 })
89 .into(),
90 show_separator_before: use_not(use_or(merge_current_with_start, merge_all)),
91 show_separator_after: use_not(use_or(merge_current_with_end, merge_all)),
92 page_count_error: state.page_count_error().into(),
93 }
94}
95
96#[derive(Debug, Copy, Clone)]
101pub struct PaginationControls {
102 pub page_count_error: Signal<Option<String>>,
104
105 pub current_page: Signal<usize>,
106
107 pub start_range: Signal<Vec<usize>>,
117
118 pub end_range: Signal<Vec<usize>>,
128
129 pub current_range: Signal<Vec<usize>>,
132
133 pub show_separator_before: Signal<bool>,
135
136 pub show_separator_after: Signal<bool>,
138}
139
140#[derive(Debug, Clone, DefaultBuilder)]
142pub struct UsePaginationControlsOptions {
143 display_page_count: usize,
150
151 margin_page_count: usize,
155}
156
157impl Default for UsePaginationControlsOptions {
158 fn default() -> Self {
159 Self {
160 display_page_count: 5,
161 margin_page_count: 1,
162 }
163 }
164}