Add the onvisible event handler to Element (#2911)
* Add the `onvisible` event using the IntersectionObserver * Add a visible example This example is based on https://codepen.io/ryanfinni/pen/VwZeGxN * Remove web-sys CustomEvent feature for html package * update js bindings and hash * Use dioxus doc instead of lorem ipsum * Fix clippy warning * Add get_target method to the event data * Make `get_time` return an Instant instead of a f64 * fix merge conflicts, compilinga * remove target * small nits * serialzie as time_ms * fix timing, works on desktop * remove latent nits, fix hash * box size clippy * fix browserlist cargo.lock --------- Co-authored-by: Evan Almloff <evanalmloff@gmail.com> Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
20 files changed
+961
-289
No files matched your search
@@ -63,6 +63,7 @@ features = [
|
||||
"HtmlInputElement",
|
||||
"HtmlSelectElement",
|
||||
"HtmlTextAreaElement",
|
||||
"IntersectionObserverEntry",
|
||||
"InputEvent",
|
||||
"KeyboardEvent",
|
||||
"MouseEvent",
|
||||
|
||||
@@ -25,6 +25,7 @@ mod selection;
|
||||
mod toggle;
|
||||
mod touch;
|
||||
mod transition;
|
||||
mod visible;
|
||||
mod wheel;
|
||||
|
||||
/// A wrapper for the websys event that allows us to give it the impls from dioxus-html
|
||||
@@ -190,6 +191,15 @@ impl HtmlEventConverter for WebEventConverter {
|
||||
Synthetic::<web_sys::TransitionEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_visible_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::VisibleData {
|
||||
Synthetic::<web_sys::IntersectionObserverEntry>::from(downcast_event(event).raw.clone())
|
||||
.into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_wheel_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::WheelData {
|
||||
Synthetic::<web_sys::WheelEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
use std::time::SystemTime;
|
||||
|
||||
use dioxus_html::{
|
||||
geometry::{
|
||||
euclid::{Point2D, Size2D},
|
||||
PixelsRect,
|
||||
},
|
||||
HasVisibleData, VisibleData, VisibleError, VisibleResult,
|
||||
};
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{CustomEvent, DomRectReadOnly, Event, IntersectionObserverEntry};
|
||||
|
||||
use super::{Synthetic, WebEventExt};
|
||||
|
||||
impl From<Event> for Synthetic<IntersectionObserverEntry> {
|
||||
#[inline]
|
||||
fn from(e: Event) -> Self {
|
||||
<Synthetic<IntersectionObserverEntry> as From<&Event>>::from(&e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Event> for Synthetic<IntersectionObserverEntry> {
|
||||
#[inline]
|
||||
fn from(e: &Event) -> Self {
|
||||
let e: &CustomEvent = e.unchecked_ref();
|
||||
let value = e.detail();
|
||||
Self::new(value.unchecked_into::<IntersectionObserverEntry>())
|
||||
}
|
||||
}
|
||||
fn dom_rect_ro_to_pixel_rect(dom_rect: &DomRectReadOnly) -> PixelsRect {
|
||||
PixelsRect::new(
|
||||
Point2D::new(dom_rect.x(), dom_rect.y()),
|
||||
Size2D::new(dom_rect.width(), dom_rect.height()),
|
||||
)
|
||||
}
|
||||
|
||||
impl HasVisibleData for Synthetic<IntersectionObserverEntry> {
|
||||
/// Get the bounds rectangle of the target element
|
||||
fn get_bounding_client_rect(&self) -> VisibleResult<PixelsRect> {
|
||||
Ok(dom_rect_ro_to_pixel_rect(
|
||||
&self.event.bounding_client_rect(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Get the ratio of the intersectionRect to the boundingClientRect
|
||||
fn get_intersection_ratio(&self) -> VisibleResult<f64> {
|
||||
Ok(self.event.intersection_ratio())
|
||||
}
|
||||
|
||||
/// Get the rect representing the target's visible area
|
||||
fn get_intersection_rect(&self) -> VisibleResult<PixelsRect> {
|
||||
Ok(dom_rect_ro_to_pixel_rect(&self.event.intersection_rect()))
|
||||
}
|
||||
|
||||
/// Get if the target element intersects with the intersection observer's root
|
||||
fn is_intersecting(&self) -> VisibleResult<bool> {
|
||||
Ok(self.event.is_intersecting())
|
||||
}
|
||||
|
||||
/// Get the rect for the intersection observer's root
|
||||
fn get_root_bounds(&self) -> VisibleResult<PixelsRect> {
|
||||
match self.event.root_bounds() {
|
||||
Some(root_bounds) => Ok(dom_rect_ro_to_pixel_rect(&root_bounds)),
|
||||
None => Err(VisibleError::NotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a timestamp indicating the time at which the intersection was recorded
|
||||
fn get_time(&self) -> VisibleResult<SystemTime> {
|
||||
let ms_since_epoch = self.event.time();
|
||||
let rounded = ms_since_epoch.round() as u64;
|
||||
let duration = std::time::Duration::from_millis(rounded);
|
||||
Ok(SystemTime::UNIX_EPOCH + duration)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl WebEventExt for VisibleData {
|
||||
type WebEvent = IntersectionObserverEntry;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_as_web_event(&self) -> Option<IntersectionObserverEntry> {
|
||||
self.downcast::<CustomEvent>()
|
||||
.and_then(|e| e.detail().dyn_into::<IntersectionObserverEntry>().ok())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user