Skip to content

Instantly share code, notes, and snippets.

@freedomtowin
Created September 27, 2025 23:15
Show Gist options
  • Select an option

  • Save freedomtowin/581691a076a582ce143ecd6015d2c999 to your computer and use it in GitHub Desktop.

Select an option

Save freedomtowin/581691a076a582ce143ecd6015d2c999 to your computer and use it in GitHub Desktop.
use dioxus::prelude::*;
#[derive(Props, Debug, PartialEq, Clone)]
pub struct MovableDivProps {
pub element_size: Signal<f64>,
pub is_dragging_div: Signal<bool>,
pub orientation: DividerOrientation,
pub min_size: Option<f64>,
pub max_size: Option<f64>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum DividerOrientation {
Horizontal,
Vertical,
}
#[component]
pub fn MovableDiv(mut props: MovableDivProps) -> Element {
let is_dragging_div = props.is_dragging_div;
let mut is_hovering = use_signal(|| false);
let mut start_pos = use_signal(|| 0.0);
let mut start_size = use_signal(|| 0.0);
let is_horizontal = props.orientation == DividerOrientation::Horizontal;
let min_size = props.min_size.unwrap_or(175.0);
let max_size = props.max_size.unwrap_or(550.0);
let resizer_size = use_memo(move || {
if *props.is_dragging_div.read() {
150.0
} else {
20.0
}
});
let cursor_style = if is_horizontal {
"row-resize"
} else {
"col-resize"
};
let divider_style = if is_horizontal {
"height: 1px; width: 100%;"
} else {
"width: 1px; height: 100%;"
};
let handle_style = if is_horizontal {
format!("height: {}px; width: 100%;", resizer_size())
} else {
format!("width: {}px; height: 100%;", resizer_size())
};
rsx! {
div {
position: "relative",
style: "{divider_style}",
display: "flex",
justify_content: "center",
align_items: "center",
border: "1px solid",
onmousedown: move |evt| {
let coords = evt.data.client_coordinates();
let mouse_pos = if is_horizontal {
coords.y as f64
} else {
coords.x as f64
};
let current_size = *props.element_size.read();
if *is_hovering.read() {
props.is_dragging_div.set(true);
start_pos.set(mouse_pos);
start_size.set(current_size);
}
},
onmousemove: move |evt| {
if *is_dragging_div.read() {
let coords = evt.data.client_coordinates();
let current_pos = if is_horizontal {
coords.y as f64
} else {
coords.x as f64
};
// Calculate the offset from the starting position
// This is the key fix to prevent jumping
let offset = current_pos - start_pos.read().clone();
let new_size = start_size.read().clone() + offset;
props.element_size.set(new_size.clamp(min_size, max_size));
}
},
div {
style: "{handle_style}",
cursor: "{cursor_style}",
position: "absolute",
user_select: "none",
background_color: "rgba(0, 0, 0, 0.0)",
display: "flex",
justify_content: "center",
align_items: "center",
z_index: "1000",
onmouseover: move |_| {
is_hovering.set(true);
},
onmouseout: move |_| {
is_hovering.set(false);
},
onmouseup: move |_| {
props.is_dragging_div.set(false);
},
onmouseleave: move |_| {
if *is_dragging_div.read() {
props.is_dragging_div.set(false);
}
is_hovering.set(false);
},
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment