use std::{
fmt::{Debug, Display, Formatter},
future::Future,
pin::Pin,
};
pub trait RenderedElementBacking: std::any::Any {
fn as_any(&self) -> &dyn std::any::Any;
fn get_scroll_offset(&self) -> Pin<Box<dyn Future<Output = MountedResult<PixelsVector2D>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
#[allow(clippy::type_complexity)]
fn get_scroll_size(&self) -> Pin<Box<dyn Future<Output = MountedResult<PixelsSize>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
#[allow(clippy::type_complexity)]
fn get_client_rect(&self) -> Pin<Box<dyn Future<Output = MountedResult<PixelsRect>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
fn scroll_to(
&self,
_behavior: ScrollBehavior,
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
fn set_focus(&self, _focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
}
impl RenderedElementBacking for () {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[doc(alias = "ScrollIntoViewOptions")]
pub enum ScrollBehavior {
#[cfg_attr(feature = "serialize", serde(rename = "instant"))]
Instant,
#[cfg_attr(feature = "serialize", serde(rename = "smooth"))]
Smooth,
}
pub struct MountedData {
inner: Box<dyn RenderedElementBacking>,
}
impl Debug for MountedData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MountedData").finish()
}
}
impl<E: RenderedElementBacking> From<E> for MountedData {
fn from(e: E) -> Self {
Self { inner: Box::new(e) }
}
}
impl MountedData {
pub fn new(registry: impl RenderedElementBacking + 'static) -> Self {
Self {
inner: Box::new(registry),
}
}
#[doc(alias = "scrollTop")]
#[doc(alias = "scrollLeft")]
pub async fn get_scroll_offset(&self) -> MountedResult<PixelsVector2D> {
self.inner.get_scroll_offset().await
}
#[doc(alias = "scrollWidth")]
#[doc(alias = "scrollHeight")]
pub async fn get_scroll_size(&self) -> MountedResult<PixelsSize> {
self.inner.get_scroll_size().await
}
#[doc(alias = "getBoundingClientRect")]
pub async fn get_client_rect(&self) -> MountedResult<PixelsRect> {
self.inner.get_client_rect().await
}
#[doc(alias = "scrollIntoView")]
pub fn scroll_to(
&self,
behavior: ScrollBehavior,
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
self.inner.scroll_to(behavior)
}
#[doc(alias = "focus")]
#[doc(alias = "blur")]
pub fn set_focus(&self, focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
self.inner.set_focus(focus)
}
#[inline(always)]
pub fn downcast<T: 'static>(&self) -> Option<&T> {
self.inner.as_any().downcast_ref::<T>()
}
}
use dioxus_core::Event;
use crate::geometry::{PixelsRect, PixelsSize, PixelsVector2D};
pub type MountedEvent = Event<MountedData>;
impl_event! [
MountedData;
#[doc(alias = "ref")]
#[doc(alias = "createRef")]
#[doc(alias = "useRef")]
onmounted
];
pub type MountedResult<T> = Result<T, MountedError>;
#[derive(Debug)]
#[non_exhaustive]
pub enum MountedError {
NotSupported,
OperationFailed(Box<dyn std::error::Error>),
}
impl Display for MountedError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
MountedError::NotSupported => {
write!(f, "The renderer does not support the requested operation")
}
MountedError::OperationFailed(e) => {
write!(f, "The operation failed: {}", e)
}
}
}
}
impl std::error::Error for MountedError {}