From 31e01292f9d976cb1a4c6731c5e514283f56151d00fc12a61841a70201c9eed6 Mon Sep 17 00:00:00 2001 From: Evan Carroll Date: Wed, 21 Jan 2026 00:09:30 -0600 Subject: [PATCH] fix: scroll wheel event warning --- .../src/components/scene_viewer.rs | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/crates/chattyness-user-ui/src/components/scene_viewer.rs b/crates/chattyness-user-ui/src/components/scene_viewer.rs index 23dff40..8b30d46 100644 --- a/crates/chattyness-user-ui/src/components/scene_viewer.rs +++ b/crates/chattyness-user-ui/src/components/scene_viewer.rs @@ -733,25 +733,61 @@ pub fn RealmSceneViewer( }); } - // Create wheel handler closure for use in view - let handle_wheel = move |ev: leptos::web_sys::WheelEvent| { - #[cfg(feature = "hydrate")] - { - // Only zoom in pan mode and without Ctrl key - if is_pan_mode.get() && !ev.ctrl_key() { - if let Some(zoom_callback) = on_zoom_change { - let delta_y = ev.delta_y(); - // Normalize: scroll up (negative deltaY) = zoom in (positive delta) - // Scroll down (positive deltaY) = zoom out (negative delta) - let zoom_delta = if delta_y < 0.0 { 0.1 } else { -0.1 }; - zoom_callback.run(zoom_delta); - ev.prevent_default(); + // Dynamically add/remove wheel listener based on pan mode + // This avoids Chrome's "non-passive wheel listener" warning when not in pan mode + #[cfg(feature = "hydrate")] + { + use std::cell::RefCell; + use std::rc::Rc; + use wasm_bindgen::{closure::Closure, JsCast}; + + let wheel_closure: Rc>>> = + Rc::new(RefCell::new(None)); + let wheel_closure_clone = wheel_closure.clone(); + + Effect::new(move |_| { + let pan_mode = is_pan_mode.get(); + + if let Some(container) = outer_container_ref.get() { + let element: &web_sys::Element = &container; + + // Remove existing listener if any + if let Some(closure) = wheel_closure_clone.borrow().as_ref() { + let _ = element.remove_event_listener_with_callback( + "wheel", + closure.as_ref().unchecked_ref(), + ); + } + + if pan_mode { + // Add non-passive wheel listener for zoom + let closure = Closure::new(move |ev: web_sys::WheelEvent| { + if !ev.ctrl_key() { + if let Some(zoom_callback) = on_zoom_change { + let delta_y = ev.delta_y(); + let zoom_delta = if delta_y < 0.0 { 0.1 } else { -0.1 }; + zoom_callback.run(zoom_delta); + ev.prevent_default(); + } + } + }); + + let options = web_sys::AddEventListenerOptions::new(); + options.set_passive(false); + + let _ = element.add_event_listener_with_callback_and_add_event_listener_options( + "wheel", + closure.as_ref().unchecked_ref(), + &options, + ); + + *wheel_closure_clone.borrow_mut() = Some(closure); + } else { + *wheel_closure_clone.borrow_mut() = None; } } - } - #[cfg(not(feature = "hydrate"))] - let _ = ev; - }; + }); + } let aspect_ratio = scene_width as f64 / scene_height as f64; @@ -899,7 +935,7 @@ pub fn RealmSceneViewer( let scene_name = scene.name.clone(); view! { -
+