use std::rc::Rc;
use dioxus::{html::geometry::PixelsVector2D, prelude::*};
use crate::ScrollState;
#[component]
pub fn ScrollableView(
#[props(default)] id: Option<String>,
#[props(default)] class: String,
#[props(default)] style: String,
#[props(into)] on_mouse_move: Option<EventHandler<MouseEvent>>,
#[props(into)] on_mouse_up: Option<EventHandler<MouseEvent>>,
#[props(into)] on_mouse_down: Option<EventHandler<MouseEvent>>,
#[props(into)] on_scroll: Option<EventHandler<ScrollState>>,
children: Element,
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
) -> Element {
let floating = crate::use_floating();
let mut scrollable_ref = use_signal(|| Option::<Rc<MountedData>>::None);
let mut scroll_state = use_signal(|| Option::<ScrollState>::None);
use_context_provider(move || ScrollableContext {
scrollable_ref,
scroll_state,
});
rsx! {
div { id: id, class: class, style: style,
onmounted: move |evt: MountedEvent| {
scrollable_ref.set(Some(evt.data.clone()));
let mounted_data = evt.data.clone();
spawn(async move {
let state = floating.generate_scroll_state_from_mounted(mounted_data).await;
scroll_state.set(Some(state));
});
},
onresize: move |evt: ResizeEvent| {
scroll_state.with_mut(move |sstate| {
if let Some(state) = sstate {
if let Ok(size) = evt.get_border_box_size() {
state.bounds = size;
}
*sstate = Some(state.to_owned());
}
});
if let Some(scrollable) = scrollable_ref() {
spawn(async move {
if let Ok(size) = scrollable.get_scroll_size().await {
scroll_state.with_mut(move |sstate| {
if let Some(state) = sstate {
state.size = size;
*sstate = Some(state.to_owned());
}
});
}
});
}
},
onscroll: move |evt: ScrollEvent| {
let new_state = floating.generate_scroll_state(evt);
scroll_state.set(Some(new_state));
if let Some(cb) = on_scroll { cb.call(new_state); }
},
onmousemove: move |evt: MouseEvent| {
if let Some(cb) = on_mouse_move { cb.call(evt); }
},
onmouseup: move |evt: MouseEvent| {
if let Some(cb) = on_mouse_up { cb.call(evt); }
},
onmousedown: move |evt: MouseEvent| {
if let Some(cb) = on_mouse_down { cb.call(evt); }
},
..attributes,
{children}
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ScrollableContext {
pub scrollable_ref: Signal<Option<Rc<MountedData>>>,
pub scroll_state: Signal<Option<ScrollState>>,
}
impl ScrollableContext {
pub async fn reload(&mut self) {
if let Some(data) = self.scrollable_ref.peek().as_ref() {
let floating = crate::Floating::default();
let new_state = floating
.generate_scroll_state_from_mounted(data.clone())
.await;
self.scroll_state.set(Some(new_state));
}
}
pub async fn scroll(&self, coordinates: PixelsVector2D, behavior: ScrollBehavior) {
if let Some(data) = self.scrollable_ref.peek().as_ref() {
let _ = data.scroll(coordinates, behavior).await;
}
}
pub async fn scroll_to(&self, behavior: ScrollBehavior) {
if let Some(data) = self.scrollable_ref.peek().as_ref() {
let _ = data.scroll_to(behavior).await;
}
}
pub async fn scroll_to_with_options(&self, options: ScrollToOptions) {
if let Some(data) = self.scrollable_ref.peek().as_ref() {
let _ = data.scroll_to_with_options(options).await;
}
}
}