From 071bbd6d06b82b79b50d4c4572ca6bebbc444106 Mon Sep 17 00:00:00 2001 From: amos Date: Wed, 5 Apr 2023 15:16:33 +0200 Subject: [PATCH] Capture pointer synchronously (#169) This was an attempt at addressing: https://github.com/yewprint/yewprint/pull/168#issuecomment-1496578935 but it doesn't fully work around what I think is a Firefox bug (until proven innocent). Anyway it does simplify some bits of the code and it probably seems wise to react to the DOM event before returning from the event listener (I'm not sure how yew event dispatching works internally). --- src/slider.rs | 59 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/slider.rs b/src/slider.rs index b5bc3da..e6c6eac 100644 --- a/src/slider.rs +++ b/src/slider.rs @@ -36,7 +36,7 @@ pub struct SliderProps { #[derive(Debug)] pub enum Msg { // started a gesture, either via mouse ("desktop") or touch ("mobile") - PointerDown { pointer_id: Option }, + PointerDown, // pointer moved, we only track X for now (vertical isn't supported for now) PointerMove { client_x: i32 }, // gesture cancelled: turns out we were scrolling or something @@ -65,13 +65,7 @@ impl Component for Slider { fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { match msg { - Msg::PointerDown { pointer_id } if ctx.props().values.len() > 1 => { - if let Some(pointer_id) = pointer_id { - if let Some(slider) = self.slider_ref.cast::() { - slider.set_pointer_capture(pointer_id).unwrap(); - } - } - + Msg::PointerDown if ctx.props().values.len() > 1 => { self.is_moving = true; if let Some(selected) = ctx.props().selected.as_ref() { // save the current value in case we need to restore it @@ -80,7 +74,7 @@ impl Component for Slider { true } - Msg::PointerDown { .. } => false, + Msg::PointerDown => false, Msg::PointerMove { client_x } if ctx.props().values.len() > 1 => { if !self.is_moving { return false; @@ -223,30 +217,35 @@ impl Component for Slider { )} ref={self.slider_ref.clone()} style={"touch-action: pan-y pinch-zoom; -webkit-touch-callout: none;"} - onpointerdown={(ctx.props().values.len() > 1).then( - || ctx.link().batch_callback( - |event: PointerEvent| { - if event.is_primary() { - let down = Msg::PointerDown { - pointer_id: Some(event.pointer_id()) - }; - if event.pointer_type() == "touch" { - // for touch devices, wait for some dragging - // to occur to know if we're dragging the - // slider or scrolling the page. this avoids - // some jumps on pointercancel, in most - // cases. it also doesn't affect "clicks" - // which do one-time adjustments. - vec![down] + onpointerdown={{ + let slider_ref = self.slider_ref.clone(); + (ctx.props().values.len() > 1).then( + move || ctx.link().batch_callback( + move |event: PointerEvent| { + if event.is_primary() { + if let Some(slider) = slider_ref.cast::() { + slider.set_pointer_capture(event.pointer_id()).unwrap(); + } + + let down = Msg::PointerDown; + if event.pointer_type() == "touch" { + // for touch devices, wait for some dragging + // to occur to know if we're dragging the + // slider or scrolling the page. this avoids + // some jumps on pointercancel, in most + // cases. it also doesn't affect "clicks" + // which do one-time adjustments. + vec![down] + } else { + vec![down, Msg::PointerMove { client_x: event.client_x() }] + } } else { - vec![down, Msg::PointerMove { client_x: event.client_x() }] + vec![] } - } else { - vec![] } - } + ) ) - )} + }} onpointermove={(ctx.props().values.len() > 1).then( || ctx.link().batch_callback( |event: PointerEvent| { @@ -281,7 +280,7 @@ impl Component for Slider { || ctx.link().batch_callback( |event: MouseEvent| { vec![ - Msg::PointerDown { pointer_id: None }, + Msg::PointerDown, Msg::PointerMove { client_x: event.client_x() }, Msg::PointerUp ]