orbital_base_components/navigation/carousel/
state.rs1use leptos::prelude::*;
2
3#[derive(Clone, Copy)]
5pub struct CarouselState {
6 pub(crate) active_index: RwSignal<i32>,
7 wrap: Signal<bool>,
8 slide_count: RwSignal<i32>,
9 next_index: RwSignal<i32>,
10 on_active_index_change: Option<Callback<i32>>,
11}
12
13impl CarouselState {
14 pub fn new(
15 default_active_index: i32,
16 wrap: Signal<bool>,
17 on_active_index_change: Option<Callback<i32>>,
18 ) -> Self {
19 Self {
20 active_index: RwSignal::new(default_active_index),
21 wrap,
22 slide_count: RwSignal::new(0),
23 next_index: RwSignal::new(0),
24 on_active_index_change,
25 }
26 }
27
28 pub fn active_index(&self) -> i32 {
29 self.active_index.get()
30 }
31
32 pub fn active_index_signal(&self) -> ReadSignal<i32> {
33 self.active_index.read_only()
34 }
35
36 pub fn wrap(&self) -> bool {
37 self.wrap.get()
38 }
39
40 pub fn slide_count(&self) -> i32 {
41 self.slide_count.get()
42 }
43
44 pub fn slide_count_signal(&self) -> ReadSignal<i32> {
45 self.slide_count.read_only()
46 }
47
48 pub fn next_index(&self) -> i32 {
49 self.next_index.get()
50 }
51
52 pub fn set_active_index(&self, index: i32) {
53 self.active_index.set(index);
54 }
55
56 pub fn register_slide(&self) -> i32 {
57 let index = self.next_index.get();
58 self.next_index.update(|value| *value += 1);
59 self.slide_count.update(|count| *count += 1);
60 index
61 }
62
63 pub fn go_to(&self, index: i32) {
64 let count = self.slide_count.get();
65 if count == 0 {
66 return;
67 }
68 let target = if self.wrap.get() {
69 let count = count as i64;
70 let normalized = index as i64 % count;
71 (if normalized < 0 {
72 normalized + count
73 } else {
74 normalized
75 }) as i32
76 } else {
77 index.clamp(0, count - 1)
78 };
79 if self.active_index.get_untracked() != target {
80 self.active_index.set(target);
81 if let Some(callback) = self.on_active_index_change {
82 callback.run(target);
83 }
84 }
85 }
86
87 pub fn next(&self) {
88 let count = self.slide_count.get();
89 if count == 0 {
90 return;
91 }
92 let current = self.active_index.get();
93 let next = if current >= count - 1 {
94 if self.wrap.get() {
95 0
96 } else {
97 current
98 }
99 } else {
100 current + 1
101 };
102 self.go_to(next);
103 }
104
105 pub fn prev(&self) {
106 let count = self.slide_count.get();
107 if count == 0 {
108 return;
109 }
110 let current = self.active_index.get();
111 let previous = if current <= 0 {
112 if self.wrap.get() {
113 count - 1
114 } else {
115 current
116 }
117 } else {
118 current - 1
119 };
120 self.go_to(previous);
121 }
122}
123
124#[derive(Clone, Copy)]
125pub struct CarouselStateInjection(pub CarouselState);
126
127impl CarouselStateInjection {
128 pub fn expect_context() -> CarouselState {
129 expect_context::<Self>().0
130 }
131
132 pub fn use_context() -> Option<CarouselState> {
133 use_context::<Self>().map(|injection| injection.0)
134 }
135}