use super::*;
#[component]
pub fn euv_splitter(node: VirtualNode<EuvSplitterProps>) -> VirtualNode {
let EuvSplitterProps { size, min, max }: EuvSplitterProps =
node.try_get_props().unwrap_or_default();
let children: Vec<VirtualNode> = node.get_children().to_vec();
let first: VirtualNode = children.first().cloned().unwrap_or(VirtualNode::Empty);
let rest: Vec<VirtualNode> = children.into_iter().skip(1).collect();
let container_ref: NodeRef<Element> = App::use_node_ref();
let session: Rc<RefCell<Option<DragSession>>> =
HookContext::use_hook(|| Rc::new(RefCell::new(None)));
let current: f64 = size.get().clamp(min, max);
let pane_style: String = format!("flex: 0 0 {current}%;");
let pane_ref: &str = pane_style.as_str();
let measured_ref: NodeRef<Element> = container_ref.clone();
App::use_cleanup({
let session: Rc<RefCell<Option<DragSession>>> = session.clone();
move || {
session.borrow_mut().take();
}
});
html! {
div {
class: c_euv_splitter()
ref: container_ref
div {
class: c_euv_splitter_pane()
style: pane_ref
first
}
div {
class: c_euv_splitter_bar()
onmousedown: on_bar_mousedown(
size,
min,
max,
measured_ref,
session.clone()
)
}
div {
class: c_euv_splitter_pane()
rest
}
}
}
}
fn on_bar_mousedown(
size: Signal<f64>,
min: f64,
max: f64,
container: NodeRef<Element>,
session: Rc<RefCell<Option<DragSession>>>,
) -> Option<Rc<dyn Fn(Event)>> {
#[cfg(target_arch = "wasm32")]
{
Some(Rc::new(move |event: Event| {
let Ok(mouse) = event.dyn_into::<MouseEvent>() else {
return;
};
let Some(document) = browser_document() else {
return;
};
let Some(element) = container.get_cloned() else {
return;
};
let width: f64 = element.get_bounding_client_rect().width();
if width <= 0.0 {
return;
}
let start_x: f64 = mouse.client_x() as f64;
let start_size: f64 = size.get();
let move_size: Signal<f64> = size;
let on_move: Closure<dyn FnMut(Event)> =
Closure::wrap(Box::new(move |event: Event| {
let Ok(mouse) = event.dyn_into::<MouseEvent>() else {
return;
};
let delta: f64 = mouse.client_x() as f64 - start_x;
let next: f64 = start_size + (delta / width) * 100.0;
move_size.set(next.clamp(min, max));
}));
let weak_session: Weak<RefCell<Option<DragSession>>> = Rc::downgrade(&session);
let closing_document: Document = document.clone();
let on_up: Closure<dyn FnMut(Event)> = Closure::wrap(Box::new(move |_event: Event| {
let Some(slot) = weak_session.upgrade() else {
return;
};
let taken: Option<DragSession> = slot.borrow_mut().take();
let Some(drag) = taken else {
return;
};
let _: Result<(), JsValue> = closing_document.remove_event_listener_with_callback(
EVENT_MOUSEMOVE,
drag.on_move.as_ref().unchecked_ref(),
);
let _: Result<(), JsValue> = closing_document.remove_event_listener_with_callback(
EVENT_MOUSEUP,
drag.on_up.as_ref().unchecked_ref(),
);
}));
if document
.add_event_listener_with_callback(EVENT_MOUSEMOVE, on_move.as_ref().unchecked_ref())
.is_err()
{
return;
}
if document
.add_event_listener_with_callback(EVENT_MOUSEUP, on_up.as_ref().unchecked_ref())
.is_err()
{
return;
}
*session.borrow_mut() = Some(DragSession { on_move, on_up });
}))
}
#[cfg(not(target_arch = "wasm32"))]
{
let _: (Signal<f64>, f64, f64, NodeRef<_>, _) = (size, min, max, container, session);
None
}
}