fix: message bug and context menu bugs
This commit is contained in:
parent
15cc1f708f
commit
84cb4e5e78
3 changed files with 76 additions and 19 deletions
|
|
@ -24,6 +24,7 @@ pub struct ContextMenuItem {
|
|||
/// Props:
|
||||
/// - `open`: Whether the menu is currently visible
|
||||
/// - `position`: The (x, y) position in client coordinates where the menu should appear
|
||||
/// - `header`: Optional header text displayed at the top (e.g., username)
|
||||
/// - `items`: The menu items to display
|
||||
/// - `on_select`: Callback when a menu item is selected, receives the action string
|
||||
/// - `on_close`: Callback when the menu should close (click outside, escape, etc.)
|
||||
|
|
@ -35,6 +36,9 @@ pub fn ContextMenu(
|
|||
/// Position (x, y) in client coordinates.
|
||||
#[prop(into)]
|
||||
position: Signal<(f64, f64)>,
|
||||
/// Optional header text (e.g., username) displayed above the menu items.
|
||||
#[prop(optional, into)]
|
||||
header: Option<Signal<Option<String>>>,
|
||||
/// Menu items to display.
|
||||
#[prop(into)]
|
||||
items: Signal<Vec<ContextMenuItem>>,
|
||||
|
|
@ -82,12 +86,40 @@ pub fn ContextMenu(
|
|||
)
|
||||
};
|
||||
|
||||
// Click outside handler
|
||||
// Click outside handler - use Effect with cleanup to properly remove handlers
|
||||
#[cfg(feature = "hydrate")]
|
||||
{
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen::{JsCast, closure::Closure};
|
||||
|
||||
// Store closures so we can remove them on cleanup
|
||||
let mousedown_closure: Rc<RefCell<Option<Closure<dyn Fn(web_sys::MouseEvent)>>>> =
|
||||
Rc::new(RefCell::new(None));
|
||||
let keydown_closure: Rc<RefCell<Option<Closure<dyn Fn(web_sys::KeyboardEvent)>>>> =
|
||||
Rc::new(RefCell::new(None));
|
||||
|
||||
let mousedown_closure_clone = mousedown_closure.clone();
|
||||
let keydown_closure_clone = keydown_closure.clone();
|
||||
|
||||
Effect::new(move |_| {
|
||||
let window = web_sys::window().unwrap();
|
||||
|
||||
// Clean up previous handlers first
|
||||
if let Some(old_handler) = mousedown_closure_clone.borrow_mut().take() {
|
||||
let _ = window.remove_event_listener_with_callback(
|
||||
"mousedown",
|
||||
old_handler.as_ref().unchecked_ref(),
|
||||
);
|
||||
}
|
||||
if let Some(old_handler) = keydown_closure_clone.borrow_mut().take() {
|
||||
let _ = window.remove_event_listener_with_callback(
|
||||
"keydown",
|
||||
old_handler.as_ref().unchecked_ref(),
|
||||
);
|
||||
}
|
||||
|
||||
// Only add handlers when menu is open
|
||||
if !open.get() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -100,6 +132,7 @@ pub fn ContextMenu(
|
|||
let menu_el: web_sys::HtmlElement = menu_el.into();
|
||||
let menu_el_clone = menu_el.clone();
|
||||
|
||||
// Mousedown handler for click-outside detection
|
||||
let handler =
|
||||
Closure::<dyn Fn(web_sys::MouseEvent)>::new(move |ev: web_sys::MouseEvent| {
|
||||
if let Some(target) = ev.target() {
|
||||
|
|
@ -111,9 +144,9 @@ pub fn ContextMenu(
|
|||
}
|
||||
});
|
||||
|
||||
let window = web_sys::window().unwrap();
|
||||
let _ = window
|
||||
.add_event_listener_with_callback("mousedown", handler.as_ref().unchecked_ref());
|
||||
*mousedown_closure_clone.borrow_mut() = Some(handler);
|
||||
|
||||
// Escape key handler
|
||||
let on_close_esc = on_close.clone();
|
||||
|
|
@ -129,10 +162,7 @@ pub fn ContextMenu(
|
|||
"keydown",
|
||||
keydown_handler.as_ref().unchecked_ref(),
|
||||
);
|
||||
|
||||
// Store handlers to clean up (they get cleaned up when Effect reruns)
|
||||
handler.forget();
|
||||
keydown_handler.forget();
|
||||
*keydown_closure_clone.borrow_mut() = Some(keydown_handler);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -145,6 +175,17 @@ pub fn ContextMenu(
|
|||
role="menu"
|
||||
aria-label="Context menu"
|
||||
>
|
||||
// Header with username and divider
|
||||
{move || {
|
||||
header.and_then(|h| h.get()).map(|header_text| {
|
||||
view! {
|
||||
<div class="px-4 py-2 text-center">
|
||||
<div class="text-sm font-semibold text-white">{header_text}</div>
|
||||
</div>
|
||||
<hr class="border-gray-600 mx-2" />
|
||||
}
|
||||
})
|
||||
}}
|
||||
<For
|
||||
each=move || items.get()
|
||||
key=|item| item.action.clone()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue