Merge branch 'master' into add-file-data-drag-event
This commit is contained in:
commit
7577019946
374 files changed
+28686
-1919
No files matched your search
@@ -31,16 +31,16 @@ macro_rules! impl_attribute {
|
||||
|
||||
(
|
||||
$(#[$attr_method:meta])*
|
||||
$fil:ident: $vil:ident (in $ns:ident),
|
||||
$fil:ident: $vil:ident (in $ns:literal),
|
||||
) => {
|
||||
pub const $fil: AttributeDiscription = (stringify!($fil), Some(stringify!($ns)), false)
|
||||
pub const $fil: AttributeDiscription = (stringify!($fil), Some($ns), false)
|
||||
};
|
||||
|
||||
(
|
||||
$(#[$attr_method:meta])*
|
||||
$fil:ident: $vil:ident (in $ns:ident : volatile),
|
||||
$fil:ident: $vil:ident (in $ns:literal : volatile),
|
||||
) => {
|
||||
pub const $fil: AttributeDiscription = (stringify!($fil), Some(stringify!($ns)), true)
|
||||
pub const $fil: AttributeDiscription = (stringify!($fil), Some($ns), true)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -71,10 +71,10 @@ macro_rules! impl_attribute_match {
|
||||
};
|
||||
|
||||
(
|
||||
$attr:ident $fil:ident: $vil:ident (in $ns:ident),
|
||||
$attr:ident $fil:ident: $vil:ident (in $ns:literal),
|
||||
) => {
|
||||
if $attr == stringify!($fil) {
|
||||
return Some((stringify!(fil), Some(stringify!(ns))));
|
||||
return Some((stringify!(fil), Some(ns)));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -110,7 +110,7 @@ macro_rules! impl_element {
|
||||
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
$name:ident $namespace:tt {
|
||||
$name:ident $namespace:literal {
|
||||
$(
|
||||
$(#[$attr_method:meta])*
|
||||
$fil:ident: $vil:ident $extra:tt,
|
||||
@@ -130,7 +130,35 @@ macro_rules! impl_element {
|
||||
$(
|
||||
impl_attribute!(
|
||||
$(#[$attr_method])*
|
||||
$fil: $vil in $namespace $extra
|
||||
$fil: $vil ($extra),
|
||||
);
|
||||
)*
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
$element:ident [$name:literal, $namespace:tt] {
|
||||
$(
|
||||
$(#[$attr_method:meta])*
|
||||
$fil:ident: $vil:ident $extra:tt,
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
#[allow(non_camel_case_types)]
|
||||
$(#[$attr])*
|
||||
pub struct $element;
|
||||
|
||||
impl SvgAttributes for $element {}
|
||||
|
||||
impl $element {
|
||||
pub const TAG_NAME: &'static str = $name;
|
||||
pub const NAME_SPACE: Option<&'static str> = Some($namespace);
|
||||
|
||||
$(
|
||||
impl_attribute!(
|
||||
$(#[$attr_method])*
|
||||
$fil: $vil ($extra),
|
||||
);
|
||||
)*
|
||||
}
|
||||
@@ -192,7 +220,7 @@ macro_rules! impl_element_match_attributes {
|
||||
if $el == stringify!($name) {
|
||||
$(
|
||||
impl_attribute_match!(
|
||||
$attr $fil: $vil in $namespace $extra
|
||||
$attr $fil: $vil ($extra),
|
||||
);
|
||||
)*
|
||||
}
|
||||
@@ -359,6 +387,11 @@ builder_constructors! {
|
||||
/// element.
|
||||
header None {};
|
||||
|
||||
/// Build a
|
||||
/// [`<hgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hgroup)
|
||||
/// element.
|
||||
hgroup None {};
|
||||
|
||||
/// Build a
|
||||
/// [`<h1>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1)
|
||||
/// element.
|
||||
@@ -1121,6 +1154,7 @@ builder_constructors! {
|
||||
r#type: InputType "type",
|
||||
// value: String,
|
||||
value: String volatile,
|
||||
initial_value: String DEFAULT,
|
||||
};
|
||||
|
||||
/// Build a
|
||||
@@ -1594,7 +1628,7 @@ builder_constructors! {
|
||||
// /// Build a
|
||||
// /// [`<use>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use)
|
||||
// /// element.
|
||||
// use "http://www.w3.org/2000/svg" {};
|
||||
|
||||
|
||||
r#use ["use", "http://www.w3.org/2000/svg"] {
|
||||
href: String DEFAULT,
|
||||
};
|
||||
}
|
||||
@@ -33,6 +33,7 @@ mod form;
|
||||
mod image;
|
||||
mod keyboard;
|
||||
mod media;
|
||||
mod mounted;
|
||||
mod mouse;
|
||||
mod pointer;
|
||||
mod scroll;
|
||||
@@ -51,6 +52,7 @@ pub use form::*;
|
||||
pub use image::*;
|
||||
pub use keyboard::*;
|
||||
pub use media::*;
|
||||
pub use mounted::*;
|
||||
pub use mouse::*;
|
||||
pub use pointer::*;
|
||||
pub use scroll::*;
|
||||
@@ -127,6 +129,7 @@ pub fn event_bubbles(evt: &str) -> bool {
|
||||
"loadeddata" => false,
|
||||
"loadedmetadata" => false,
|
||||
"loadstart" => false,
|
||||
"load" => false,
|
||||
"pause" => false,
|
||||
"play" => false,
|
||||
"playing" => false,
|
||||
@@ -144,6 +147,7 @@ pub fn event_bubbles(evt: &str) -> bool {
|
||||
"animationiteration" => true,
|
||||
"transitionend" => true,
|
||||
"toggle" => true,
|
||||
"mounted" => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ pub type ImageEvent = Event<ImageData>;
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ImageData {
|
||||
#[cfg_attr(feature = "serialize", serde(default))]
|
||||
pub load_error: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
//! Handles quering data from the renderer
|
||||
|
||||
use euclid::Rect;
|
||||
|
||||
use std::{
|
||||
any::Any,
|
||||
fmt::{Display, Formatter},
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
/// An Element that has been rendered and allows reading and modifying information about it.
|
||||
///
|
||||
/// Different platforms will have different implementations and different levels of support for this trait. Renderers that do not support specific features will return `None` for those queries.
|
||||
// we can not use async_trait here because it does not create a trait that is object safe
|
||||
pub trait RenderedElementBacking {
|
||||
/// Get the renderer specific element for the given id
|
||||
fn get_raw_element(&self) -> MountedResult<&dyn Any> {
|
||||
Err(MountedError::NotSupported)
|
||||
}
|
||||
|
||||
/// Get the bounding rectangle of the element relative to the viewport (this does not include the scroll position)
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn get_client_rect(&self) -> Pin<Box<dyn Future<Output = MountedResult<Rect<f64, f64>>>>> {
|
||||
Box::pin(async { Err(MountedError::NotSupported) })
|
||||
}
|
||||
|
||||
/// Scroll to make the element visible
|
||||
fn scroll_to(
|
||||
&self,
|
||||
_behavior: ScrollBehavior,
|
||||
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
Box::pin(async { Err(MountedError::NotSupported) })
|
||||
}
|
||||
|
||||
/// Set the focus on the element
|
||||
fn set_focus(&self, _focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
Box::pin(async { Err(MountedError::NotSupported) })
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderedElementBacking for () {}
|
||||
|
||||
/// The way that scrolling should be performed
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum ScrollBehavior {
|
||||
/// Scroll to the element immediately
|
||||
#[cfg_attr(feature = "serialize", serde(rename = "instant"))]
|
||||
Instant,
|
||||
/// Scroll to the element smoothly
|
||||
#[cfg_attr(feature = "serialize", serde(rename = "smooth"))]
|
||||
Smooth,
|
||||
}
|
||||
|
||||
/// An Element that has been rendered and allows reading and modifying information about it.
|
||||
///
|
||||
/// Different platforms will have different implementations and different levels of support for this trait. Renderers that do not support specific features will return `None` for those queries.
|
||||
pub struct MountedData {
|
||||
inner: Rc<dyn RenderedElementBacking>,
|
||||
}
|
||||
|
||||
impl MountedData {
|
||||
/// Create a new MountedData
|
||||
pub fn new(registry: impl RenderedElementBacking + 'static) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(registry),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the renderer specific element for the given id
|
||||
pub fn get_raw_element(&self) -> MountedResult<&dyn Any> {
|
||||
self.inner.get_raw_element()
|
||||
}
|
||||
|
||||
/// Get the bounding rectangle of the element relative to the viewport (this does not include the scroll position)
|
||||
pub async fn get_client_rect(&self) -> MountedResult<Rect<f64, f64>> {
|
||||
self.inner.get_client_rect().await
|
||||
}
|
||||
|
||||
/// Scroll to make the element visible
|
||||
pub fn scroll_to(
|
||||
&self,
|
||||
behavior: ScrollBehavior,
|
||||
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
self.inner.scroll_to(behavior)
|
||||
}
|
||||
|
||||
/// Set the focus on the element
|
||||
pub fn set_focus(&self, focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
self.inner.set_focus(focus)
|
||||
}
|
||||
}
|
||||
|
||||
use dioxus_core::Event;
|
||||
|
||||
pub type MountedEvent = Event<MountedData>;
|
||||
|
||||
impl_event! [
|
||||
MountedData;
|
||||
|
||||
/// mounted
|
||||
onmounted
|
||||
];
|
||||
|
||||
/// The MountedResult type for the MountedData
|
||||
pub type MountedResult<T> = Result<T, MountedError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// The error type for the MountedData
|
||||
pub enum MountedError {
|
||||
/// The renderer does not support the requested operation
|
||||
NotSupported,
|
||||
/// The element was not found
|
||||
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 {}
|
||||
@@ -7,6 +7,7 @@ use keyboard_types::Location;
|
||||
|
||||
/// A mouse button type (such as Primary/Secondary)
|
||||
// note: EnumSetType also derives Copy and Clone for some reason
|
||||
#[allow(clippy::unused_unit)]
|
||||
#[derive(EnumSetType, Debug)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum MouseButton {
|
||||
|
||||
@@ -91,7 +91,7 @@ fn fun_name(
|
||||
// Touch
|
||||
"touchcancel" | "touchend" | "touchmove" | "touchstart" => Touch(de(data)?),
|
||||
|
||||
// Srcoll
|
||||
// Scroll
|
||||
"scroll" => Scroll(de(data)?),
|
||||
|
||||
// Wheel
|
||||
@@ -102,7 +102,7 @@ fn fun_name(
|
||||
| "ended" | "interruptbegin" | "interruptend" | "loadeddata" | "loadedmetadata"
|
||||
| "loadstart" | "pause" | "play" | "playing" | "progress" | "ratechange" | "seeked"
|
||||
| "seeking" | "stalled" | "suspend" | "timeupdate" | "volumechange" | "waiting"
|
||||
| "error" | "load" | "loadend" | "timeout" => Media(de(data)?),
|
||||
| "loadend" | "timeout" => Media(de(data)?),
|
||||
|
||||
// Animation
|
||||
"animationstart" | "animationend" | "animationiteration" => Animation(de(data)?),
|
||||
@@ -113,7 +113,11 @@ fn fun_name(
|
||||
// Toggle
|
||||
"toggle" => Toggle(de(data)?),
|
||||
|
||||
// ImageData => "load" | "error";
|
||||
"load" | "error" => Image(de(data)?),
|
||||
|
||||
// Mounted
|
||||
"mounted" => Mounted,
|
||||
|
||||
// OtherData => "abort" | "afterprint" | "beforeprint" | "beforeunload" | "hashchange" | "languagechange" | "message" | "offline" | "online" | "pagehide" | "pageshow" | "popstate" | "rejectionhandled" | "storage" | "unhandledrejection" | "unload" | "userproximity" | "vrdisplayactivate" | "vrdisplayblur" | "vrdisplayconnect" | "vrdisplaydeactivate" | "vrdisplaydisconnect" | "vrdisplayfocus" | "vrdisplaypointerrestricted" | "vrdisplaypointerunrestricted" | "vrdisplaypresentchange";
|
||||
other => {
|
||||
return Err(serde_value::DeserializerError::UnknownVariant(
|
||||
@@ -134,6 +138,7 @@ impl HtmlEvent {
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
#[non_exhaustive]
|
||||
pub enum EventData {
|
||||
Mouse(MouseData),
|
||||
Clipboard(ClipboardData),
|
||||
@@ -151,6 +156,8 @@ pub enum EventData {
|
||||
Animation(AnimationData),
|
||||
Transition(TransitionData),
|
||||
Toggle(ToggleData),
|
||||
Image(ImageData),
|
||||
Mounted,
|
||||
}
|
||||
|
||||
impl EventData {
|
||||
@@ -172,6 +179,8 @@ impl EventData {
|
||||
EventData::Animation(data) => Rc::new(data) as Rc<dyn Any>,
|
||||
EventData::Transition(data) => Rc::new(data) as Rc<dyn Any>,
|
||||
EventData::Toggle(data) => Rc::new(data) as Rc<dyn Any>,
|
||||
EventData::Image(data) => Rc::new(data) as Rc<dyn Any>,
|
||||
EventData::Mounted => Rc::new(MountedData::new(())) as Rc<dyn Any>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,18 @@ use crate::events::{
|
||||
};
|
||||
use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
|
||||
use crate::input_data::{decode_key_location, decode_mouse_button_set, MouseButton};
|
||||
use crate::DragData;
|
||||
use crate::{
|
||||
DragData, MountedData, MountedError, MountedResult, RenderedElementBacking, ScrollBehavior,
|
||||
};
|
||||
use keyboard_types::{Code, Key, Modifiers};
|
||||
use std::convert::TryInto;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{
|
||||
AnimationEvent, CompositionEvent, Event, KeyboardEvent, MouseEvent, PointerEvent, TouchEvent,
|
||||
TransitionEvent, WheelEvent,
|
||||
AnimationEvent, CompositionEvent, Event, KeyboardEvent, MouseEvent, PointerEvent,
|
||||
ScrollIntoViewOptions, TouchEvent, TransitionEvent, WheelEvent,
|
||||
};
|
||||
|
||||
macro_rules! uncheck_convert {
|
||||
@@ -194,3 +198,64 @@ impl From<&TransitionEvent> for TransitionData {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&web_sys::Element> for MountedData {
|
||||
fn from(e: &web_sys::Element) -> Self {
|
||||
MountedData::new(e.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderedElementBacking for web_sys::Element {
|
||||
fn get_client_rect(
|
||||
&self,
|
||||
) -> Pin<Box<dyn Future<Output = MountedResult<euclid::Rect<f64, f64>>>>> {
|
||||
let rect = self.get_bounding_client_rect();
|
||||
let result = Ok(euclid::Rect::new(
|
||||
euclid::Point2D::new(rect.left(), rect.top()),
|
||||
euclid::Size2D::new(rect.width(), rect.height()),
|
||||
));
|
||||
Box::pin(async { result })
|
||||
}
|
||||
|
||||
fn get_raw_element(&self) -> MountedResult<&dyn std::any::Any> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn scroll_to(
|
||||
&self,
|
||||
behavior: ScrollBehavior,
|
||||
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
match behavior {
|
||||
ScrollBehavior::Instant => self.scroll_into_view_with_scroll_into_view_options(
|
||||
ScrollIntoViewOptions::new().behavior(web_sys::ScrollBehavior::Instant),
|
||||
),
|
||||
ScrollBehavior::Smooth => self.scroll_into_view_with_scroll_into_view_options(
|
||||
ScrollIntoViewOptions::new().behavior(web_sys::ScrollBehavior::Smooth),
|
||||
),
|
||||
}
|
||||
|
||||
Box::pin(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn set_focus(&self, focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||
let result = self
|
||||
.dyn_ref::<web_sys::HtmlElement>()
|
||||
.ok_or_else(|| MountedError::OperationFailed(Box::new(FocusError(self.into()))))
|
||||
.and_then(|e| {
|
||||
(if focus { e.focus() } else { e.blur() })
|
||||
.map_err(|err| MountedError::OperationFailed(Box::new(FocusError(err))))
|
||||
});
|
||||
Box::pin(async { result })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FocusError(JsValue);
|
||||
|
||||
impl std::fmt::Display for FocusError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "failed to focus element {:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for FocusError {}
|
||||
Reference in new issue
Block a user