use crate::*;
pub(crate) fn use_scroll_to_top(route_signal: Signal<String>) {
watch!(route_signal, |_route_value| {
let window_value: Window = window().expect("no global window exists");
let document_value: Document = window_value.document().expect("should have a document");
if let Some(main_element) = document_value.query_selector("main").ok().flatten() {
let html_element: HtmlElement = main_element.unchecked_into();
html_element.set_scroll_top(0);
}
});
}
pub(crate) fn use_hash_change(route_signal: Signal<String>) {
use_window_event("hashchange", move || {
let new_route: String = current_route();
route_signal.set(new_route);
});
}
pub(crate) fn push_state_on_open() {
let window: Window = window().expect("no global window exists");
let history: History = window.history().expect("no history object exists");
let _ = history.push_state(&JsValue::NULL, "");
}
pub(crate) fn back_on_close() {
let window: Window = window().expect("no global window exists");
let history: History = window.history().expect("no history object exists");
let _ = history.back();
}
pub(crate) fn use_pop_state(panel_open: Signal<bool>) {
use_window_event("popstate", move || {
let is_open: bool = panel_open.get();
if is_open {
panel_open.set(false);
}
});
}
pub(crate) fn use_scroll_drawer_to_active(drawer_open: Signal<bool>) {
watch!(drawer_open, |is_open| {
if !is_open {
return;
}
let outer_window: Window = window().expect("no global window exists");
let outer_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
let inner_window: Window = window().expect("no global window exists");
let inner_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
let window_value: Window = window().expect("no global window exists");
let document_value: Document =
window_value.document().expect("should have a document");
let Some(drawer_nav) = document_value
.query_selector(DRAWER_NAV_SELECTOR)
.ok()
.flatten()
else {
return;
};
let Some(active_element) = drawer_nav
.query_selector(ACTIVE_NAV_ITEM_SELECTOR)
.ok()
.flatten()
else {
return;
};
let active_html_element: HtmlElement = active_element.unchecked_into();
let Some(scroll_container) = drawer_nav
.query_selector(NAV_ITEMS_SCROLL_SELECTOR)
.ok()
.flatten()
else {
return;
};
let scroll_html_element: HtmlElement = scroll_container.unchecked_into();
let active_rect: DomRect = active_html_element.get_bounding_client_rect();
let container_rect: DomRect = scroll_html_element.get_bounding_client_rect();
let offset_from_container_top: f64 = active_rect.top() - container_rect.top();
let current_scroll_top: i32 = scroll_html_element.scroll_top();
let container_height: f64 = container_rect.height();
let active_height: f64 = active_rect.height();
let target_scroll_top: f64 = current_scroll_top as f64 + offset_from_container_top
- (container_height - active_height) / 2.0;
scroll_html_element.set_scroll_top(target_scroll_top.max(0.0) as i32);
}));
let _ = inner_window.request_animation_frame(inner_closure.as_ref().unchecked_ref());
inner_closure.forget();
}));
let _ = outer_window.request_animation_frame(outer_closure.as_ref().unchecked_ref());
outer_closure.forget();
});
}
pub(crate) fn use_resize() -> Signal<bool> {
let mobile_signal: Signal<bool> = use_signal(is_mobile);
let timer_signal: Signal<Option<i32>> = use_signal(|| None);
let debounce_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
let mobile: bool = is_mobile();
mobile_signal.set(mobile);
}));
let debounce_callback: Function = debounce_closure
.as_ref()
.unchecked_ref::<Function>()
.clone();
debounce_closure.forget();
let timeout_window: Window = window().expect("no global window exists");
use_window_event("resize", move || {
let old_timer: Option<i32> = timer_signal.get();
if let Some(timer_id) = old_timer {
timeout_window.clear_timeout_with_handle(timer_id);
}
let new_timer: i32 = timeout_window
.set_timeout_with_callback_and_timeout_and_arguments_0(
&debounce_callback,
RESIZE_DEBOUNCE_MILLIS,
)
.unwrap_or_default();
timer_signal.set(Some(new_timer));
});
mobile_signal
}