wip: more work on web
this commit adds complete event support for web-sys but with a few hole
This commit is contained in:
1 parent
59219b9ef2
commit
3bf19d8106
13 files changed
+709
-355
No files matched your search
+31
-233
@@ -1,7 +1,7 @@
|
||||
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
||||
use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
|
||||
|
||||
use dioxus_core::{
|
||||
events::{EventTrigger, VirtualEvent},
|
||||
events::{on::GenericEventInner, EventTrigger, VirtualEvent},
|
||||
mutations::NodeRefMutation,
|
||||
DomEdit, ElementId, ScopeId,
|
||||
};
|
||||
@@ -9,7 +9,7 @@ use fxhash::FxHashMap;
|
||||
use wasm_bindgen::{closure::Closure, JsCast};
|
||||
use web_sys::{
|
||||
window, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
|
||||
HtmlOptionElement, Node, NodeList,
|
||||
HtmlOptionElement, Node, NodeList, UiEvent,
|
||||
};
|
||||
|
||||
use crate::{nodeslab::NodeSlab, WebConfig};
|
||||
@@ -436,284 +436,82 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
|
||||
fn virtual_event_from_websys_event(event: web_sys::Event) -> VirtualEvent {
|
||||
use crate::events::*;
|
||||
use dioxus_core::events::on::*;
|
||||
match event.type_().as_str() {
|
||||
"copy" | "cut" | "paste" => {
|
||||
struct WebsysClipboardEvent();
|
||||
impl ClipboardEventInner for WebsysClipboardEvent {}
|
||||
VirtualEvent::ClipboardEvent(ClipboardEvent(Rc::new(WebsysClipboardEvent())))
|
||||
VirtualEvent::ClipboardEvent(ClipboardEvent(Rc::new(WebsysClipboardEvent(event))))
|
||||
}
|
||||
|
||||
"compositionend" | "compositionstart" | "compositionupdate" => {
|
||||
let evt: web_sys::CompositionEvent = event.clone().dyn_into().unwrap();
|
||||
struct WebsysCompositionEvent(web_sys::CompositionEvent);
|
||||
impl CompositionEventInner for WebsysCompositionEvent {
|
||||
fn data(&self) -> String {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
VirtualEvent::CompositionEvent(CompositionEvent(Rc::new(WebsysCompositionEvent(evt))))
|
||||
}
|
||||
|
||||
"keydown" | "keypress" | "keyup" => {
|
||||
struct Event(web_sys::KeyboardEvent);
|
||||
impl KeyboardEventInner for Event {
|
||||
fn alt_key(&self) -> bool {
|
||||
self.0.alt_key()
|
||||
}
|
||||
fn char_code(&self) -> u32 {
|
||||
self.0.char_code()
|
||||
}
|
||||
fn key(&self) -> String {
|
||||
self.0.key()
|
||||
}
|
||||
|
||||
fn key_code(&self) -> KeyCode {
|
||||
KeyCode::from_raw_code(self.0.key_code() as u8)
|
||||
}
|
||||
|
||||
fn ctrl_key(&self) -> bool {
|
||||
self.0.ctrl_key()
|
||||
}
|
||||
|
||||
fn get_modifier_state(&self, key_code: &str) -> bool {
|
||||
self.0.get_modifier_state(key_code)
|
||||
}
|
||||
|
||||
fn locale(&self) -> String {
|
||||
todo!("Locale is currently not supported. :(")
|
||||
}
|
||||
|
||||
fn location(&self) -> usize {
|
||||
self.0.location() as usize
|
||||
}
|
||||
|
||||
fn meta_key(&self) -> bool {
|
||||
self.0.meta_key()
|
||||
}
|
||||
|
||||
fn repeat(&self) -> bool {
|
||||
self.0.repeat()
|
||||
}
|
||||
|
||||
fn shift_key(&self) -> bool {
|
||||
self.0.shift_key()
|
||||
}
|
||||
|
||||
fn which(&self) -> usize {
|
||||
self.0.which() as usize
|
||||
}
|
||||
}
|
||||
let evt: web_sys::KeyboardEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::KeyboardEvent(KeyboardEvent(Rc::new(Event(evt))))
|
||||
let evt: web_sys::KeyboardEvent = event.dyn_into().unwrap();
|
||||
VirtualEvent::KeyboardEvent(KeyboardEvent(Rc::new(WebsysKeyboardEvent(evt))))
|
||||
}
|
||||
|
||||
"focus" | "blur" => {
|
||||
struct Event(web_sys::FocusEvent);
|
||||
impl FocusEventInner for Event {}
|
||||
let evt: web_sys::FocusEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::FocusEvent(FocusEvent(Rc::new(Event(evt))))
|
||||
let evt: web_sys::FocusEvent = event.dyn_into().unwrap();
|
||||
VirtualEvent::FocusEvent(FocusEvent(Rc::new(WebsysFocusEvent(evt))))
|
||||
}
|
||||
|
||||
"change" => {
|
||||
// struct Event(web_sys::Event);
|
||||
// impl GenericEventInner for Event {
|
||||
// fn bubbles(&self) -> bool {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn cancel_bubble(&self) {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn cancelable(&self) -> bool {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn composed(&self) -> bool {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn composed_path(&self) -> String {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn current_target(&self) {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn default_prevented(&self) -> bool {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn event_phase(&self) -> usize {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn is_trusted(&self) -> bool {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn prevent_default(&self) {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn stop_immediate_propagation(&self) {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn stop_propagation(&self) {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn target(&self) {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// fn time_stamp(&self) -> usize {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
// let evt: web_sys::Event = event.clone().dyn_into().expect("wrong error typ");
|
||||
// VirtualEvent::Event(GenericEvent(Rc::new(Event(evt))))
|
||||
todo!()
|
||||
let evt = event.dyn_into().unwrap();
|
||||
VirtualEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt))))
|
||||
}
|
||||
|
||||
"input" | "invalid" | "reset" | "submit" => {
|
||||
// is a special react events
|
||||
let evt: web_sys::InputEvent = event.clone().dyn_into().expect("wrong event type");
|
||||
let this: web_sys::EventTarget = evt.target().unwrap();
|
||||
|
||||
let value = (&this)
|
||||
.dyn_ref()
|
||||
.map(|input: &web_sys::HtmlInputElement| input.value())
|
||||
.or_else(|| {
|
||||
(&this)
|
||||
.dyn_ref()
|
||||
.map(|input: &web_sys::HtmlTextAreaElement| input.value())
|
||||
})
|
||||
.or_else(|| {
|
||||
(&this)
|
||||
.dyn_ref::<web_sys::HtmlElement>()
|
||||
.unwrap()
|
||||
.text_content()
|
||||
})
|
||||
.expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
|
||||
|
||||
todo!()
|
||||
// VirtualEvent::FormEvent(FormEvent { value })
|
||||
let evt: web_sys::InputEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::FormEvent(FormEvent(Rc::new(WebsysFormEvent(evt))))
|
||||
}
|
||||
|
||||
"click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
|
||||
| "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
|
||||
| "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => {
|
||||
let evt: web_sys::MouseEvent = event.clone().dyn_into().unwrap();
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CustomMouseEvent(web_sys::MouseEvent);
|
||||
impl dioxus_core::events::on::MouseEventInner for CustomMouseEvent {
|
||||
fn alt_key(&self) -> bool {
|
||||
self.0.alt_key()
|
||||
}
|
||||
fn button(&self) -> i16 {
|
||||
self.0.button()
|
||||
}
|
||||
fn buttons(&self) -> u16 {
|
||||
self.0.buttons()
|
||||
}
|
||||
fn client_x(&self) -> i32 {
|
||||
self.0.client_x()
|
||||
}
|
||||
fn client_y(&self) -> i32 {
|
||||
self.0.client_y()
|
||||
}
|
||||
fn ctrl_key(&self) -> bool {
|
||||
self.0.ctrl_key()
|
||||
}
|
||||
fn meta_key(&self) -> bool {
|
||||
self.0.meta_key()
|
||||
}
|
||||
fn page_x(&self) -> i32 {
|
||||
self.0.page_x()
|
||||
}
|
||||
fn page_y(&self) -> i32 {
|
||||
self.0.page_y()
|
||||
}
|
||||
fn screen_x(&self) -> i32 {
|
||||
self.0.screen_x()
|
||||
}
|
||||
fn screen_y(&self) -> i32 {
|
||||
self.0.screen_y()
|
||||
}
|
||||
fn shift_key(&self) -> bool {
|
||||
self.0.shift_key()
|
||||
}
|
||||
|
||||
// yikes
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
|
||||
fn get_modifier_state(&self, key_code: &str) -> bool {
|
||||
self.0.get_modifier_state(key_code)
|
||||
}
|
||||
}
|
||||
VirtualEvent::MouseEvent(MouseEvent(Rc::new(CustomMouseEvent(evt))))
|
||||
VirtualEvent::MouseEvent(MouseEvent(Rc::new(WebsysMouseEvent(evt))))
|
||||
}
|
||||
|
||||
"pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
|
||||
| "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
|
||||
let evt: web_sys::PointerEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
VirtualEvent::PointerEvent(PointerEvent(Rc::new(WebsysPointerEvent(evt))))
|
||||
}
|
||||
|
||||
"select" => {
|
||||
// let evt: web_sys::SelectionEvent = event.clone().dyn_into().unwrap();
|
||||
// not required to construct anything special beyond standard event stuff
|
||||
todo!()
|
||||
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::SelectionEvent(SelectionEvent(Rc::new(WebsysGenericUiEvent(evt))))
|
||||
}
|
||||
|
||||
"touchcancel" | "touchend" | "touchmove" | "touchstart" => {
|
||||
let evt: web_sys::TouchEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
VirtualEvent::TouchEvent(TouchEvent(Rc::new(WebsysTouchEvent(evt))))
|
||||
}
|
||||
|
||||
"scroll" => {
|
||||
// let evt: web_sys::UIEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt))))
|
||||
}
|
||||
|
||||
"wheel" => {
|
||||
let evt: web_sys::WheelEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
VirtualEvent::WheelEvent(WheelEvent(Rc::new(WebsysWheelEvent(evt))))
|
||||
}
|
||||
"animationstart" | "animationend" | "animationiteration" => {
|
||||
let evt: web_sys::AnimationEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
VirtualEvent::AnimationEvent(AnimationEvent(Rc::new(WebsysAnimationEvent(evt))))
|
||||
}
|
||||
|
||||
"transitionend" => {
|
||||
let evt: web_sys::TransitionEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
VirtualEvent::TransitionEvent(TransitionEvent(Rc::new(WebsysTransitionEvent(evt))))
|
||||
}
|
||||
|
||||
"abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
|
||||
| "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
|
||||
| "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
|
||||
| "timeupdate" | "volumechange" | "waiting" => {
|
||||
// not required to construct anything special beyond standard event stuff
|
||||
|
||||
// let evt: web_sys::MediaEvent = event.clone().dyn_into().unwrap();
|
||||
// let evt: web_sys::MediaEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::MediaEvent(MediaEvent(Rc::new(WebsysMediaEvent(evt))))
|
||||
}
|
||||
|
||||
"toggle" => {
|
||||
// not required to construct anything special beyond standard event stuff (target)
|
||||
|
||||
// let evt: web_sys::ToggleEvent = event.clone().dyn_into().unwrap();
|
||||
todo!()
|
||||
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::ToggleEvent(ToggleEvent(Rc::new(WebsysToggleEvent(evt))))
|
||||
}
|
||||
_ => {
|
||||
todo!()
|
||||
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
|
||||
VirtualEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt))))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -763,7 +561,7 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<EventTrigger> {
|
||||
// let triggered_scope: ScopeId = KeyData::from_ffi(gi_id).into();
|
||||
log::debug!("Triggered scope is {:#?}", triggered_scope);
|
||||
Ok(EventTrigger::new(
|
||||
virtual_event_from_websys_event(event),
|
||||
virtual_event_from_websys_event(event.clone()),
|
||||
ScopeId(triggered_scope as usize),
|
||||
Some(ElementId(real_id as usize)),
|
||||
dioxus_core::events::EventPriority::High,
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
//! Ported events into Dioxus Synthetic Event system
|
||||
//!
|
||||
//! event porting is pretty boring, sorry.
|
||||
|
||||
use dioxus_core::events::on::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{Event, UiEvent};
|
||||
|
||||
/// All events implement the generic event type - they're all UI events
|
||||
trait WebsysGenericEvent {
|
||||
fn as_ui_event(&self) -> &UiEvent;
|
||||
}
|
||||
|
||||
impl GenericEventInner for &dyn WebsysGenericEvent {
|
||||
/// On WebSys, this returns an &UiEvent which can be casted via dyn_ref into the correct sub type.
|
||||
fn raw_event(&self) -> &dyn std::any::Any {
|
||||
self.as_ui_event()
|
||||
}
|
||||
|
||||
fn bubbles(&self) -> bool {
|
||||
self.as_ui_event().bubbles()
|
||||
}
|
||||
|
||||
fn cancel_bubble(&self) {
|
||||
self.as_ui_event().cancel_bubble();
|
||||
}
|
||||
|
||||
fn cancelable(&self) -> bool {
|
||||
self.as_ui_event().cancelable()
|
||||
}
|
||||
|
||||
fn composed(&self) -> bool {
|
||||
self.as_ui_event().composed()
|
||||
}
|
||||
|
||||
fn current_target(&self) {
|
||||
if cfg!(debug_assertions) {
|
||||
todo!("Current target does not return anything useful.\nPlease try casting the event directly.");
|
||||
}
|
||||
// self.as_ui_event().current_target();
|
||||
}
|
||||
|
||||
fn default_prevented(&self) -> bool {
|
||||
self.as_ui_event().default_prevented()
|
||||
}
|
||||
|
||||
fn event_phase(&self) -> u16 {
|
||||
self.as_ui_event().event_phase()
|
||||
}
|
||||
|
||||
fn is_trusted(&self) -> bool {
|
||||
self.as_ui_event().is_trusted()
|
||||
}
|
||||
|
||||
fn prevent_default(&self) {
|
||||
self.as_ui_event().prevent_default()
|
||||
}
|
||||
|
||||
fn stop_immediate_propagation(&self) {
|
||||
self.as_ui_event().stop_immediate_propagation()
|
||||
}
|
||||
|
||||
fn stop_propagation(&self) {
|
||||
self.as_ui_event().stop_propagation()
|
||||
}
|
||||
|
||||
fn target(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn time_stamp(&self) -> f64 {
|
||||
self.as_ui_event().time_stamp()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! implement_generic_event {
|
||||
(
|
||||
$($event:ident),*
|
||||
) => {
|
||||
$(
|
||||
impl WebsysGenericEvent for $event {
|
||||
fn as_ui_event(&self) -> &UiEvent {
|
||||
self.0.dyn_ref().unwrap()
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
implement_generic_event! {
|
||||
WebsysClipboardEvent,
|
||||
WebsysCompositionEvent,
|
||||
WebsysKeyboardEvent,
|
||||
WebsysGenericUiEvent,
|
||||
WebsysFocusEvent,
|
||||
WebsysFormEvent,
|
||||
WebsysMouseEvent,
|
||||
WebsysPointerEvent,
|
||||
WebsysWheelEvent,
|
||||
WebsysAnimationEvent,
|
||||
WebsysTransitionEvent,
|
||||
WebsysTouchEvent,
|
||||
WebsysMediaEvent,
|
||||
WebsysToggleEvent
|
||||
}
|
||||
|
||||
// unfortunately, currently experimental, and web_sys needs to be configured to use it :>(
|
||||
pub struct WebsysClipboardEvent(pub Event);
|
||||
|
||||
impl ClipboardEventInner for WebsysClipboardEvent {}
|
||||
|
||||
pub struct WebsysCompositionEvent(pub web_sys::CompositionEvent);
|
||||
|
||||
impl CompositionEventInner for WebsysCompositionEvent {
|
||||
fn data(&self) -> String {
|
||||
self.0.data().unwrap_or_else(|| String::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysKeyboardEvent(pub web_sys::KeyboardEvent);
|
||||
impl KeyboardEventInner for WebsysKeyboardEvent {
|
||||
fn alt_key(&self) -> bool {
|
||||
self.0.alt_key()
|
||||
}
|
||||
fn char_code(&self) -> u32 {
|
||||
self.0.char_code()
|
||||
}
|
||||
fn key(&self) -> String {
|
||||
self.0.key()
|
||||
}
|
||||
|
||||
fn key_code(&self) -> KeyCode {
|
||||
KeyCode::from_raw_code(self.0.key_code() as u8)
|
||||
}
|
||||
|
||||
fn ctrl_key(&self) -> bool {
|
||||
self.0.ctrl_key()
|
||||
}
|
||||
|
||||
fn get_modifier_state(&self, key_code: &str) -> bool {
|
||||
self.0.get_modifier_state(key_code)
|
||||
}
|
||||
|
||||
fn locale(&self) -> String {
|
||||
if cfg!(debug_assertions) {
|
||||
todo!("Locale is currently not supported. :(")
|
||||
} else {
|
||||
String::from("en-US")
|
||||
}
|
||||
}
|
||||
|
||||
fn location(&self) -> usize {
|
||||
self.0.location() as usize
|
||||
}
|
||||
|
||||
fn meta_key(&self) -> bool {
|
||||
self.0.meta_key()
|
||||
}
|
||||
|
||||
fn repeat(&self) -> bool {
|
||||
self.0.repeat()
|
||||
}
|
||||
|
||||
fn shift_key(&self) -> bool {
|
||||
self.0.shift_key()
|
||||
}
|
||||
|
||||
fn which(&self) -> usize {
|
||||
self.0.which() as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysGenericUiEvent(pub UiEvent);
|
||||
impl UIEventInner for WebsysGenericUiEvent {
|
||||
fn detail(&self) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl SelectionEventInner for WebsysGenericUiEvent {}
|
||||
|
||||
pub struct WebsysFocusEvent(pub web_sys::FocusEvent);
|
||||
impl FocusEventInner for WebsysFocusEvent {}
|
||||
|
||||
pub struct WebsysFormEvent(pub web_sys::InputEvent);
|
||||
impl FormEventInner for WebsysFormEvent {
|
||||
// technically a controlled component, so we need to manually grab out the target data
|
||||
fn value(&self) -> String {
|
||||
let this: web_sys::EventTarget = self.0.target().unwrap();
|
||||
(&this)
|
||||
.dyn_ref()
|
||||
.map(|input: &web_sys::HtmlInputElement| input.value())
|
||||
.or_else(|| {
|
||||
this
|
||||
.dyn_ref()
|
||||
.map(|input: &web_sys::HtmlTextAreaElement| input.value())
|
||||
})
|
||||
.or_else(|| {
|
||||
this
|
||||
.dyn_ref::<web_sys::HtmlElement>()
|
||||
.unwrap()
|
||||
.text_content()
|
||||
})
|
||||
.expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysMouseEvent(pub web_sys::MouseEvent);
|
||||
impl MouseEventInner for WebsysMouseEvent {
|
||||
fn alt_key(&self) -> bool {
|
||||
self.0.alt_key()
|
||||
}
|
||||
fn button(&self) -> i16 {
|
||||
self.0.button()
|
||||
}
|
||||
fn buttons(&self) -> u16 {
|
||||
self.0.buttons()
|
||||
}
|
||||
fn client_x(&self) -> i32 {
|
||||
self.0.client_x()
|
||||
}
|
||||
fn client_y(&self) -> i32 {
|
||||
self.0.client_y()
|
||||
}
|
||||
fn ctrl_key(&self) -> bool {
|
||||
self.0.ctrl_key()
|
||||
}
|
||||
fn meta_key(&self) -> bool {
|
||||
self.0.meta_key()
|
||||
}
|
||||
fn page_x(&self) -> i32 {
|
||||
self.0.page_x()
|
||||
}
|
||||
fn page_y(&self) -> i32 {
|
||||
self.0.page_y()
|
||||
}
|
||||
fn screen_x(&self) -> i32 {
|
||||
self.0.screen_x()
|
||||
}
|
||||
fn screen_y(&self) -> i32 {
|
||||
self.0.screen_y()
|
||||
}
|
||||
fn shift_key(&self) -> bool {
|
||||
self.0.shift_key()
|
||||
}
|
||||
|
||||
// yikes
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
|
||||
fn get_modifier_state(&self, key_code: &str) -> bool {
|
||||
self.0.get_modifier_state(key_code)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysPointerEvent(pub web_sys::PointerEvent);
|
||||
impl PointerEventInner for WebsysPointerEvent {
|
||||
fn alt_key(&self) -> bool {
|
||||
self.0.alt_key()
|
||||
}
|
||||
fn button(&self) -> i16 {
|
||||
self.0.button()
|
||||
}
|
||||
fn buttons(&self) -> u16 {
|
||||
self.0.buttons()
|
||||
}
|
||||
fn client_x(&self) -> i32 {
|
||||
self.0.client_x()
|
||||
}
|
||||
fn client_y(&self) -> i32 {
|
||||
self.0.client_y()
|
||||
}
|
||||
fn ctrl_key(&self) -> bool {
|
||||
self.0.ctrl_key()
|
||||
}
|
||||
fn meta_key(&self) -> bool {
|
||||
self.0.meta_key()
|
||||
}
|
||||
fn page_x(&self) -> i32 {
|
||||
self.0.page_x()
|
||||
}
|
||||
fn page_y(&self) -> i32 {
|
||||
self.0.page_y()
|
||||
}
|
||||
fn screen_x(&self) -> i32 {
|
||||
self.0.screen_x()
|
||||
}
|
||||
fn screen_y(&self) -> i32 {
|
||||
self.0.screen_y()
|
||||
}
|
||||
fn shift_key(&self) -> bool {
|
||||
self.0.shift_key()
|
||||
}
|
||||
|
||||
// yikes
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
|
||||
fn get_modifier_state(&self, key_code: &str) -> bool {
|
||||
self.0.get_modifier_state(key_code)
|
||||
}
|
||||
|
||||
fn pointer_id(&self) -> i32 {
|
||||
self.0.pointer_id()
|
||||
}
|
||||
|
||||
fn width(&self) -> i32 {
|
||||
self.0.width()
|
||||
}
|
||||
|
||||
fn height(&self) -> i32 {
|
||||
self.0.height()
|
||||
}
|
||||
|
||||
fn pressure(&self) -> f32 {
|
||||
self.0.pressure()
|
||||
}
|
||||
|
||||
fn tangential_pressure(&self) -> f32 {
|
||||
self.0.tangential_pressure()
|
||||
}
|
||||
|
||||
fn tilt_x(&self) -> i32 {
|
||||
self.0.tilt_x()
|
||||
}
|
||||
|
||||
fn tilt_y(&self) -> i32 {
|
||||
self.0.tilt_y()
|
||||
}
|
||||
|
||||
fn twist(&self) -> i32 {
|
||||
self.0.twist()
|
||||
}
|
||||
|
||||
fn pointer_type(&self) -> String {
|
||||
self.0.pointer_type()
|
||||
}
|
||||
|
||||
fn is_primary(&self) -> bool {
|
||||
self.0.is_primary()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysWheelEvent(pub web_sys::WheelEvent);
|
||||
impl WheelEventInner for WebsysWheelEvent {
|
||||
fn delta_mode(&self) -> u32 {
|
||||
self.0.delta_mode()
|
||||
}
|
||||
|
||||
fn delta_x(&self) -> f64 {
|
||||
self.0.delta_x()
|
||||
}
|
||||
|
||||
fn delta_y(&self) -> f64 {
|
||||
self.0.delta_y()
|
||||
}
|
||||
|
||||
fn delta_z(&self) -> f64 {
|
||||
self.0.delta_z()
|
||||
}
|
||||
}
|
||||
pub struct WebsysAnimationEvent(pub web_sys::AnimationEvent);
|
||||
impl AnimationEventInner for WebsysAnimationEvent {
|
||||
fn animation_name(&self) -> String {
|
||||
self.0.animation_name()
|
||||
}
|
||||
|
||||
fn pseudo_element(&self) -> String {
|
||||
self.0.pseudo_element()
|
||||
}
|
||||
|
||||
fn elapsed_time(&self) -> f32 {
|
||||
self.0.elapsed_time()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysTransitionEvent(pub web_sys::TransitionEvent);
|
||||
impl TransitionEventInner for WebsysTransitionEvent {
|
||||
fn property_name(&self) -> String {
|
||||
self.0.property_name()
|
||||
}
|
||||
|
||||
fn pseudo_element(&self) -> String {
|
||||
self.0.pseudo_element()
|
||||
}
|
||||
|
||||
fn elapsed_time(&self) -> f32 {
|
||||
self.0.elapsed_time()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysTouchEvent(pub web_sys::TouchEvent);
|
||||
impl TouchEventInner for WebsysTouchEvent {
|
||||
fn alt_key(&self) -> bool {
|
||||
self.0.alt_key()
|
||||
}
|
||||
|
||||
fn ctrl_key(&self) -> bool {
|
||||
self.0.ctrl_key()
|
||||
}
|
||||
|
||||
fn meta_key(&self) -> bool {
|
||||
self.0.meta_key()
|
||||
}
|
||||
|
||||
fn shift_key(&self) -> bool {
|
||||
self.0.shift_key()
|
||||
}
|
||||
|
||||
fn get_modifier_state(&self, key_code: &str) -> bool {
|
||||
if cfg!(debug_assertions) {
|
||||
todo!("get_modifier_state is not currently supported for touch events");
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebsysMediaEvent(pub web_sys::UiEvent);
|
||||
impl MediaEventInner for WebsysMediaEvent {}
|
||||
|
||||
pub struct WebsysToggleEvent(pub web_sys::UiEvent);
|
||||
impl ToggleEventInner for WebsysToggleEvent {}
|
||||
@@ -56,6 +56,7 @@ use std::rc::Rc;
|
||||
|
||||
pub use crate::cfg::WebConfig;
|
||||
use crate::dom::load_document;
|
||||
use cache::intern_cache;
|
||||
use dioxus::prelude::Properties;
|
||||
use dioxus::virtual_dom::VirtualDom;
|
||||
pub use dioxus_core as dioxus;
|
||||
@@ -64,6 +65,7 @@ use dioxus_core::prelude::FC;
|
||||
mod cache;
|
||||
mod cfg;
|
||||
mod dom;
|
||||
mod events;
|
||||
mod nodeslab;
|
||||
mod ric_raf;
|
||||
|
||||
@@ -114,6 +116,8 @@ where
|
||||
pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T, cfg: WebConfig) {
|
||||
let mut dom = VirtualDom::new_with_props(root, root_props);
|
||||
|
||||
intern_cache();
|
||||
|
||||
let hydrating = cfg.hydrate;
|
||||
|
||||
let root_el = load_document().get_element_by_id(&cfg.rootname).unwrap();
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
//! RequestAnimationFrame and RequestIdleCallback port and polyfill.
|
||||
|
||||
use std::{cell::RefCell, fmt, rc::Rc};
|
||||
|
||||
use gloo_timers::future::TimeoutFuture;
|
||||
use js_sys::Function;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen::{prelude::Closure, JsValue};
|
||||
use web_sys::Window;
|
||||
@@ -21,13 +18,15 @@ impl RafLoop {
|
||||
pub fn new() -> Self {
|
||||
let (raf_sender, raf_receiver) = async_channel::unbounded();
|
||||
|
||||
let raf_closure: Closure<dyn Fn(JsValue)> =
|
||||
Closure::wrap(Box::new(move |v: JsValue| raf_sender.try_send(()).unwrap()));
|
||||
let raf_closure: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new(move |_v: JsValue| {
|
||||
raf_sender.try_send(()).unwrap()
|
||||
}));
|
||||
|
||||
let (ric_sender, ric_receiver) = async_channel::unbounded();
|
||||
|
||||
let ric_closure: Closure<dyn Fn(JsValue)> =
|
||||
Closure::wrap(Box::new(move |v: JsValue| ric_sender.try_send(()).unwrap()));
|
||||
let ric_closure: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new(move |_v: JsValue| {
|
||||
ric_sender.try_send(()).unwrap()
|
||||
}));
|
||||
|
||||
// execute the polyfill for safari
|
||||
Function::new_no_args(include_str!("./ricpolyfill.js"))
|
||||
@@ -44,45 +43,16 @@ impl RafLoop {
|
||||
}
|
||||
/// waits for some idle time and returns a timeout future that expires after the idle time has passed
|
||||
pub async fn wait_for_idle_time(&self) -> TimeoutFuture {
|
||||
// comes with its own safari polyfill :)
|
||||
|
||||
let ric_fn = self.ric_closure.as_ref().dyn_ref::<Function>().unwrap();
|
||||
let deadline: u32 = self.window.request_idle_callback(ric_fn).unwrap();
|
||||
|
||||
self.ric_receiver.recv().await.unwrap();
|
||||
|
||||
let deadline = TimeoutFuture::new(deadline);
|
||||
deadline
|
||||
}
|
||||
|
||||
pub async fn wait_for_raf(&self) {
|
||||
let raf_fn = self.raf_closure.as_ref().dyn_ref::<Function>().unwrap();
|
||||
let id: i32 = self.window.request_animation_frame(raf_fn).unwrap();
|
||||
let _id: i32 = self.window.request_animation_frame(raf_fn).unwrap();
|
||||
self.raf_receiver.recv().await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AnimationFrame {
|
||||
render_id: i32,
|
||||
closure: Closure<dyn Fn(JsValue)>,
|
||||
callback_wrapper: Rc<RefCell<Option<CallbackWrapper>>>,
|
||||
}
|
||||
|
||||
struct CallbackWrapper(Box<dyn FnOnce(f64) + 'static>);
|
||||
impl fmt::Debug for CallbackWrapper {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("CallbackWrapper")
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AnimationFrame {
|
||||
fn drop(&mut self) {
|
||||
if self.callback_wrapper.borrow_mut().is_some() {
|
||||
web_sys::window()
|
||||
.unwrap_throw()
|
||||
.cancel_animation_frame(self.render_id)
|
||||
.unwrap_throw()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user