mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-14 00:17:17 +00:00
Remove native and web features from dioxus-html (#3006)
* remove native and web features from dioxus-html * Fix downcasting web events * Fix desktop with tokio disabled
This commit is contained in:
parent
677e0e7f4f
commit
cda8bb24f1
54 changed files with 1768 additions and 1512 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -2592,6 +2592,7 @@ dependencies = [
|
||||||
"global-hotkey",
|
"global-hotkey",
|
||||||
"http-range",
|
"http-range",
|
||||||
"infer 0.11.0",
|
"infer 0.11.0",
|
||||||
|
"lazy-js-bundle",
|
||||||
"muda",
|
"muda",
|
||||||
"objc",
|
"objc",
|
||||||
"objc_id",
|
"objc_id",
|
||||||
|
@ -2763,9 +2764,6 @@ dependencies = [
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"wasm-bindgen",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
"web-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3069,6 +3067,7 @@ dependencies = [
|
||||||
name = "dioxus-web"
|
name = "dioxus-web"
|
||||||
version = "0.6.0-alpha.2"
|
version = "0.6.0-alpha.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
"ciborium",
|
"ciborium",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
|
@ -3086,6 +3085,7 @@ dependencies = [
|
||||||
"gloo-dialogs",
|
"gloo-dialogs",
|
||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
"lazy-js-bundle",
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen",
|
||||||
|
|
|
@ -13,8 +13,8 @@ keywords = ["dom", "ui", "gui", "react"]
|
||||||
dioxus-core = { workspace = true, features = ["serialize"] }
|
dioxus-core = { workspace = true, features = ["serialize"] }
|
||||||
dioxus-html = { workspace = true, features = [
|
dioxus-html = { workspace = true, features = [
|
||||||
"serialize",
|
"serialize",
|
||||||
"native-bind",
|
|
||||||
"mounted",
|
"mounted",
|
||||||
|
"file_engine",
|
||||||
"document",
|
"document",
|
||||||
] }
|
] }
|
||||||
dioxus-signals = { workspace = true, optional = true }
|
dioxus-signals = { workspace = true, optional = true }
|
||||||
|
@ -88,6 +88,9 @@ cocoa = "0.25"
|
||||||
core-foundation = "0.9.3"
|
core-foundation = "0.9.3"
|
||||||
objc = "0.2.7"
|
objc = "0.2.7"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
lazy-js-bundle = { workspace = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["tokio_runtime", "wry/objc-exception", "devtools"]
|
default = ["tokio_runtime", "wry/objc-exception", "devtools"]
|
||||||
tokio_runtime = ["dep:tokio"]
|
tokio_runtime = ["dep:tokio"]
|
||||||
|
|
|
@ -36,8 +36,17 @@ fn check_gnu() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_ts() {
|
||||||
|
// If any TS files change, re-run the build script
|
||||||
|
lazy_js_bundle::LazyTypeScriptBindings::new()
|
||||||
|
.with_watching("./src/ts")
|
||||||
|
.with_binding("./src/ts/native_eval.ts", "./src/js/native_eval.js")
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
check_gnu();
|
check_gnu();
|
||||||
|
compile_ts();
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXAMPLES_TOML: &str = r#"
|
const EXAMPLES_TOML: &str = r#"
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, WindowCloseBehaviour},
|
config::{Config, WindowCloseBehaviour},
|
||||||
event_handlers::WindowEventHandlers,
|
event_handlers::WindowEventHandlers,
|
||||||
file_upload::{DesktopFileUploadForm, FileDialogRequest},
|
file_upload::{DesktopFileUploadForm, FileDialogRequest, NativeFileEngine},
|
||||||
ipc::{IpcMessage, UserWindowEvent},
|
ipc::{IpcMessage, UserWindowEvent},
|
||||||
query::QueryResult,
|
query::QueryResult,
|
||||||
shortcut::ShortcutRegistry,
|
shortcut::ShortcutRegistry,
|
||||||
webview::WebviewInstance,
|
webview::WebviewInstance,
|
||||||
};
|
};
|
||||||
use dioxus_core::{ElementId, VirtualDom};
|
use dioxus_core::{ElementId, VirtualDom};
|
||||||
use dioxus_html::{native_bind::NativeFileEngine, PlatformEventData};
|
use dioxus_html::PlatformEventData;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
|
@ -3,6 +3,9 @@ use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
|
||||||
|
|
||||||
use crate::{query::Query, DesktopContext};
|
use crate::{query::Query, DesktopContext};
|
||||||
|
|
||||||
|
/// Code for the Dioxus channel used to communicate between the dioxus and javascript code
|
||||||
|
pub const NATIVE_EVAL_JS: &str = include_str!("./js/native_eval.js");
|
||||||
|
|
||||||
/// Represents the desktop-target's provider of evaluators.
|
/// Represents the desktop-target's provider of evaluators.
|
||||||
pub struct DesktopDocument {
|
pub struct DesktopDocument {
|
||||||
pub(crate) desktop_ctx: DesktopContext,
|
pub(crate) desktop_ctx: DesktopContext,
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
#[cfg(feature = "tokio_runtime")]
|
||||||
|
use tokio::{fs::File, io::AsyncReadExt};
|
||||||
|
|
||||||
use dioxus_html::{
|
use dioxus_html::{
|
||||||
geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint},
|
geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint},
|
||||||
input_data::{MouseButton, MouseButtonSet},
|
input_data::{MouseButton, MouseButtonSet},
|
||||||
native_bind::NativeFileEngine,
|
|
||||||
point_interaction::{
|
point_interaction::{
|
||||||
InteractionElementOffset, InteractionLocation, ModifiersInteraction, PointerInteraction,
|
InteractionElementOffset, InteractionLocation, ModifiersInteraction, PointerInteraction,
|
||||||
},
|
},
|
||||||
|
@ -237,3 +241,79 @@ impl PointerInteraction for DesktopFileDragEvent {
|
||||||
self.mouse.trigger_button()
|
self.mouse.trigger_button()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NativeFileEngine {
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NativeFileEngine {
|
||||||
|
pub fn new(files: Vec<PathBuf>) -> Self {
|
||||||
|
Self { files }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl FileEngine for NativeFileEngine {
|
||||||
|
fn files(&self) -> Vec<String> {
|
||||||
|
self.files
|
||||||
|
.iter()
|
||||||
|
.filter_map(|f| Some(f.to_str()?.to_string()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn file_size(&self, file: &str) -> Option<u64> {
|
||||||
|
#[cfg(feature = "tokio_runtime")]
|
||||||
|
{
|
||||||
|
let file = File::open(file).await.ok()?;
|
||||||
|
Some(file.metadata().await.ok()?.len())
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "tokio_runtime"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_file(&self, file: &str) -> Option<Vec<u8>> {
|
||||||
|
#[cfg(feature = "tokio_runtime")]
|
||||||
|
{
|
||||||
|
let mut file = File::open(file).await.ok()?;
|
||||||
|
|
||||||
|
let mut contents = Vec::new();
|
||||||
|
file.read_to_end(&mut contents).await.ok()?;
|
||||||
|
|
||||||
|
Some(contents)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "tokio_runtime"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_file_to_string(&self, file: &str) -> Option<String> {
|
||||||
|
#[cfg(feature = "tokio_runtime")]
|
||||||
|
{
|
||||||
|
let mut file = File::open(file).await.ok()?;
|
||||||
|
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents).await.ok()?;
|
||||||
|
|
||||||
|
Some(contents)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "tokio_runtime"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_native_file(&self, file: &str) -> Option<Box<dyn Any>> {
|
||||||
|
#[cfg(feature = "tokio_runtime")]
|
||||||
|
{
|
||||||
|
let file = File::open(file).await.ok()?;
|
||||||
|
Some(Box::new(file))
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "tokio_runtime"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1
packages/desktop/src/js/hash.txt
Normal file
1
packages/desktop/src/js/hash.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[11927251734412729446]
|
|
@ -63,18 +63,20 @@ pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, desktop_config: Conf
|
||||||
/// Launches the WebView and runs the event loop, with configuration and root props.
|
/// Launches the WebView and runs the event loop, with configuration and root props.
|
||||||
pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) -> ! {
|
pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) -> ! {
|
||||||
#[cfg(feature = "tokio_runtime")]
|
#[cfg(feature = "tokio_runtime")]
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
{
|
||||||
.enable_all()
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
.build()
|
.enable_all()
|
||||||
.unwrap()
|
.build()
|
||||||
.block_on(tokio::task::unconstrained(async move {
|
.unwrap()
|
||||||
launch_virtual_dom_blocking(virtual_dom, desktop_config)
|
.block_on(tokio::task::unconstrained(async move {
|
||||||
}));
|
launch_virtual_dom_blocking(virtual_dom, desktop_config)
|
||||||
|
}));
|
||||||
|
|
||||||
|
unreachable!("The desktop launch function will never exit")
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "tokio_runtime"))]
|
#[cfg(not(feature = "tokio_runtime"))]
|
||||||
launch_virtual_dom_blocking(virtual_dom, desktop_config);
|
launch_virtual_dom_blocking(virtual_dom, desktop_config);
|
||||||
|
|
||||||
unreachable!("The desktop launch function will never exit")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Launches the WebView and runs the event loop, with configuration and root props.
|
/// Launches the WebView and runs the event loop, with configuration and root props.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::document::NATIVE_EVAL_JS;
|
||||||
use crate::{assets::*, webview::WebviewEdits};
|
use crate::{assets::*, webview::WebviewEdits};
|
||||||
use dioxus_html::document::NATIVE_EVAL_JS;
|
|
||||||
use dioxus_interpreter_js::unified_bindings::SLEDGEHAMMER_JS;
|
use dioxus_interpreter_js::unified_bindings::SLEDGEHAMMER_JS;
|
||||||
use dioxus_interpreter_js::NATIVE_JS;
|
use dioxus_interpreter_js::NATIVE_JS;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
import { Channel, DioxusChannel, WeakDioxusChannel } from "./eval";
|
import {
|
||||||
|
Channel,
|
||||||
|
DioxusChannel,
|
||||||
|
WeakDioxusChannel,
|
||||||
|
} from "../../../html/src/ts/eval";
|
||||||
|
|
||||||
// In dioxus desktop, eval needs to use the window object to store global state because we evaluate separate snippets of javascript in the browser
|
// In dioxus desktop, eval needs to use the window object to store global state because we evaluate separate snippets of javascript in the browser
|
||||||
declare global {
|
declare global {
|
|
@ -3,15 +3,18 @@ use crate::element::DesktopElement;
|
||||||
use crate::file_upload::DesktopFileDragEvent;
|
use crate::file_upload::DesktopFileDragEvent;
|
||||||
use crate::menubar::DioxusMenu;
|
use crate::menubar::DioxusMenu;
|
||||||
use crate::{
|
use crate::{
|
||||||
app::SharedContext, assets::AssetHandlerRegistry, edits::WryQueue,
|
app::SharedContext,
|
||||||
file_upload::NativeFileHover, ipc::UserWindowEvent, protocol, waker::tao_waker, Config,
|
assets::AssetHandlerRegistry,
|
||||||
DesktopContext, DesktopService,
|
edits::WryQueue,
|
||||||
|
file_upload::{NativeFileEngine, NativeFileHover},
|
||||||
|
ipc::UserWindowEvent,
|
||||||
|
protocol,
|
||||||
|
waker::tao_waker,
|
||||||
|
Config, DesktopContext, DesktopService,
|
||||||
};
|
};
|
||||||
use dioxus_core::{Runtime, ScopeId, VirtualDom};
|
use dioxus_core::{Runtime, ScopeId, VirtualDom};
|
||||||
use dioxus_hooks::to_owned;
|
use dioxus_hooks::to_owned;
|
||||||
use dioxus_html::{
|
use dioxus_html::{prelude::Document, HasFileData, HtmlEvent, PlatformEventData};
|
||||||
native_bind::NativeFileEngine, prelude::Document, HasFileData, HtmlEvent, PlatformEventData,
|
|
||||||
};
|
|
||||||
use futures_util::{pin_mut, FutureExt};
|
use futures_util::{pin_mut, FutureExt};
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
18
packages/desktop/tsconfig.json
Normal file
18
packages/desktop/tsconfig.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"lib": [
|
||||||
|
"ES2015",
|
||||||
|
"DOM",
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"ESNext"
|
||||||
|
],
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
|
@ -19,8 +19,6 @@ dioxus-hooks = { workspace = true }
|
||||||
generational-box = { workspace = true }
|
generational-box = { workspace = true }
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
serde = { version = "1", features = ["derive"], optional = true }
|
||||||
serde_repr = { version = "0.1", optional = true }
|
serde_repr = { version = "0.1", optional = true }
|
||||||
wasm-bindgen = { workspace = true, optional = true }
|
|
||||||
wasm-bindgen-futures = { workspace = true, optional = true }
|
|
||||||
js-sys = { version = "0.3.56", optional = true }
|
js-sys = { version = "0.3.56", optional = true }
|
||||||
euclid = "0.22.7"
|
euclid = "0.22.7"
|
||||||
enumset = "1.1.2"
|
enumset = "1.1.2"
|
||||||
|
@ -32,30 +30,6 @@ serde_json = { version = "1", optional = true }
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
rustversion = "1.0.17"
|
rustversion = "1.0.17"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
|
||||||
optional = true
|
|
||||||
version = "0.3.56"
|
|
||||||
features = [
|
|
||||||
"Touch",
|
|
||||||
"TouchList",
|
|
||||||
"TouchEvent",
|
|
||||||
"MouseEvent",
|
|
||||||
"DragEvent",
|
|
||||||
"InputEvent",
|
|
||||||
"HtmlInputElement",
|
|
||||||
"ClipboardEvent",
|
|
||||||
"KeyboardEvent",
|
|
||||||
"WheelEvent",
|
|
||||||
"AnimationEvent",
|
|
||||||
"TransitionEvent",
|
|
||||||
"PointerEvent",
|
|
||||||
"FocusEvent",
|
|
||||||
"CompositionEvent",
|
|
||||||
"CustomEvent",
|
|
||||||
"ResizeObserverEntry",
|
|
||||||
"ResizeObserverSize"
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
lazy-js-bundle = { workspace = true }
|
lazy-js-bundle = { workspace = true }
|
||||||
|
|
||||||
|
@ -76,30 +50,17 @@ serialize = [
|
||||||
"keyboard-types/serde",
|
"keyboard-types/serde",
|
||||||
"dioxus-core/serialize"
|
"dioxus-core/serialize"
|
||||||
]
|
]
|
||||||
mounted = [
|
mounted = []
|
||||||
"web-sys?/Element",
|
|
||||||
"web-sys?/DomRect",
|
|
||||||
"web-sys?/ScrollIntoViewOptions",
|
|
||||||
"web-sys?/ScrollLogicalPosition",
|
|
||||||
"web-sys?/ScrollBehavior",
|
|
||||||
"web-sys?/HtmlElement",
|
|
||||||
]
|
|
||||||
document = [
|
document = [
|
||||||
"dep:serde",
|
"dep:serde",
|
||||||
"dep:serde_json"
|
"dep:serde_json"
|
||||||
]
|
]
|
||||||
file_engine = [
|
file_engine = [
|
||||||
"dep:async-trait",
|
"dep:async-trait",
|
||||||
"dep:js-sys",
|
|
||||||
"web-sys?/File",
|
|
||||||
"web-sys?/FileList",
|
|
||||||
"web-sys?/FileReader"
|
|
||||||
]
|
]
|
||||||
wasm-bind = ["dep:web-sys", "dep:wasm-bindgen", "dep:wasm-bindgen-futures"]
|
|
||||||
native-bind = ["dep:tokio", "file_engine"]
|
|
||||||
hot-reload-context = ["dep:dioxus-rsx"]
|
hot-reload-context = ["dep:dioxus-rsx"]
|
||||||
html-to-rsx = []
|
html-to-rsx = []
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
|
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
|
||||||
feature = ["html-to-rsx", "hot-reload-context", "html-to-rsx", "native-bind", "wasm-bind"]
|
feature = ["html-to-rsx", "hot-reload-context", "html-to-rsx"]
|
||||||
|
|
|
@ -2,8 +2,6 @@ fn main() {
|
||||||
// If any TS files change, re-run the build script
|
// If any TS files change, re-run the build script
|
||||||
lazy_js_bundle::LazyTypeScriptBindings::new()
|
lazy_js_bundle::LazyTypeScriptBindings::new()
|
||||||
.with_watching("./src/ts")
|
.with_watching("./src/ts")
|
||||||
.with_binding("./src/ts/eval.ts", "./src/js/eval.js")
|
|
||||||
.with_binding("./src/ts/native_eval.ts", "./src/js/native_eval.js")
|
|
||||||
.with_binding("./src/ts/head.ts", "./src/js/head.js")
|
.with_binding("./src/ts/head.ts", "./src/js/head.js")
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/// Code for the Dioxus channel used to communicate between the dioxus and javascript code
|
|
||||||
#[cfg(feature = "native-bind")]
|
|
||||||
pub const NATIVE_EVAL_JS: &str = include_str!("../js/native_eval.js");
|
|
||||||
|
|
||||||
#[cfg(feature = "wasm-bind")]
|
|
||||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
|
||||||
pub struct JSOwner {
|
|
||||||
_owner: Box<dyn std::any::Any>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "wasm-bind")]
|
|
||||||
impl JSOwner {
|
|
||||||
pub fn new(owner: impl std::any::Any) -> Self {
|
|
||||||
Self {
|
|
||||||
_owner: Box::new(owner),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "wasm-bind")]
|
|
||||||
#[wasm_bindgen::prelude::wasm_bindgen(module = "/src/js/eval.js")]
|
|
||||||
extern "C" {
|
|
||||||
pub type WebDioxusChannel;
|
|
||||||
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
pub fn new(owner: JSOwner) -> WebDioxusChannel;
|
|
||||||
|
|
||||||
#[wasm_bindgen(method, js_name = "rustSend")]
|
|
||||||
pub fn rust_send(this: &WebDioxusChannel, value: wasm_bindgen::JsValue);
|
|
||||||
|
|
||||||
#[wasm_bindgen(method, js_name = "rustRecv")]
|
|
||||||
pub async fn rust_recv(this: &WebDioxusChannel) -> wasm_bindgen::JsValue;
|
|
||||||
|
|
||||||
#[wasm_bindgen(method)]
|
|
||||||
pub fn send(this: &WebDioxusChannel, value: wasm_bindgen::JsValue);
|
|
||||||
|
|
||||||
#[wasm_bindgen(method)]
|
|
||||||
pub async fn recv(this: &WebDioxusChannel) -> wasm_bindgen::JsValue;
|
|
||||||
|
|
||||||
#[wasm_bindgen(method)]
|
|
||||||
pub fn weak(this: &WebDioxusChannel) -> WeakDioxusChannel;
|
|
||||||
|
|
||||||
pub type WeakDioxusChannel;
|
|
||||||
|
|
||||||
#[wasm_bindgen(method, js_name = "rustSend")]
|
|
||||||
pub fn rust_send(this: &WeakDioxusChannel, value: wasm_bindgen::JsValue);
|
|
||||||
|
|
||||||
#[wasm_bindgen(method, js_name = "rustRecv")]
|
|
||||||
pub async fn rust_recv(this: &WeakDioxusChannel) -> wasm_bindgen::JsValue;
|
|
||||||
}
|
|
|
@ -7,9 +7,7 @@ use std::{
|
||||||
|
|
||||||
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
|
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
|
||||||
|
|
||||||
mod bindings;
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub use bindings::*;
|
|
||||||
mod eval;
|
mod eval;
|
||||||
pub use eval::*;
|
pub use eval::*;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Handles querying data from the renderer
|
//! Handles querying data from the renderer
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Display, Formatter},
|
fmt::{Debug, Display, Formatter},
|
||||||
future::Future,
|
future::Future,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
};
|
};
|
||||||
|
@ -70,6 +70,12 @@ pub struct MountedData {
|
||||||
inner: Box<dyn RenderedElementBacking>,
|
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 {
|
impl<E: RenderedElementBacking> From<E> for MountedData {
|
||||||
fn from(e: E) -> Self {
|
fn from(e: E) -> Self {
|
||||||
Self { inner: Box::new(e) }
|
Self { inner: Box::new(e) }
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
[10372071913661173523, 8375185156499858125, 4813754958077120784]
|
[206827801705263822, 8375185156499858125]
|
|
@ -27,14 +27,8 @@ pub use file_data::*;
|
||||||
mod attribute_groups;
|
mod attribute_groups;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
pub mod input_data;
|
pub mod input_data;
|
||||||
#[cfg(feature = "native-bind")]
|
|
||||||
pub mod native_bind;
|
|
||||||
pub mod point_interaction;
|
pub mod point_interaction;
|
||||||
mod render_template;
|
mod render_template;
|
||||||
#[cfg(feature = "wasm-bind")]
|
|
||||||
mod web_sys_bind;
|
|
||||||
#[cfg(feature = "wasm-bind")]
|
|
||||||
pub use web_sys_bind::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
mod transit;
|
mod transit;
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
mod native_file_engine;
|
|
||||||
|
|
||||||
pub use native_file_engine::*;
|
|
|
@ -1,56 +0,0 @@
|
||||||
use std::any::Any;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use tokio::fs::File;
|
|
||||||
use tokio::io::AsyncReadExt;
|
|
||||||
|
|
||||||
use crate::file_data::FileEngine;
|
|
||||||
|
|
||||||
pub struct NativeFileEngine {
|
|
||||||
files: Vec<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NativeFileEngine {
|
|
||||||
pub fn new(files: Vec<PathBuf>) -> Self {
|
|
||||||
Self { files }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "file_engine")]
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl FileEngine for NativeFileEngine {
|
|
||||||
fn files(&self) -> Vec<String> {
|
|
||||||
self.files
|
|
||||||
.iter()
|
|
||||||
.filter_map(|f| Some(f.to_str()?.to_string()))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn file_size(&self, file: &str) -> Option<u64> {
|
|
||||||
let file = File::open(file).await.ok()?;
|
|
||||||
Some(file.metadata().await.ok()?.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_file(&self, file: &str) -> Option<Vec<u8>> {
|
|
||||||
let mut file = File::open(file).await.ok()?;
|
|
||||||
|
|
||||||
let mut contents = Vec::new();
|
|
||||||
file.read_to_end(&mut contents).await.ok()?;
|
|
||||||
|
|
||||||
Some(contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_file_to_string(&self, file: &str) -> Option<String> {
|
|
||||||
let mut file = File::open(file).await.ok()?;
|
|
||||||
|
|
||||||
let mut contents = String::new();
|
|
||||||
file.read_to_string(&mut contents).await.ok()?;
|
|
||||||
|
|
||||||
Some(contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_native_file(&self, file: &str) -> Option<Box<dyn Any>> {
|
|
||||||
let file = File::open(file).await.ok()?;
|
|
||||||
Some(Box::new(file))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -68,41 +68,3 @@ export abstract class DioxusChannel {
|
||||||
// Receive data sent from javascript in rust
|
// Receive data sent from javascript in rust
|
||||||
abstract rustRecv(): Promise<any>;
|
abstract rustRecv(): Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WebDioxusChannel extends DioxusChannel {
|
|
||||||
js_to_rust: Channel;
|
|
||||||
rust_to_js: Channel;
|
|
||||||
owner: any;
|
|
||||||
|
|
||||||
constructor(owner: any) {
|
|
||||||
super();
|
|
||||||
this.owner = owner;
|
|
||||||
this.js_to_rust = new Channel();
|
|
||||||
this.rust_to_js = new Channel();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a weak reference to this channel
|
|
||||||
weak(): WeakDioxusChannel {
|
|
||||||
return new WeakDioxusChannel(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive message from Rust
|
|
||||||
async recv() {
|
|
||||||
return await this.rust_to_js.recv();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send message to rust.
|
|
||||||
send(data: any) {
|
|
||||||
this.js_to_rust.send(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send data from rust to javascript
|
|
||||||
rustSend(data: any) {
|
|
||||||
this.rust_to_js.send(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive data sent from javascript in rust
|
|
||||||
async rustRecv(): Promise<any> {
|
|
||||||
return await this.js_to_rust.recv();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,675 +0,0 @@
|
||||||
use crate::events::HasKeyboardData;
|
|
||||||
use crate::events::{
|
|
||||||
AnimationData, CompositionData, KeyboardData, MouseData, PointerData, TouchData,
|
|
||||||
TransitionData, WheelData,
|
|
||||||
};
|
|
||||||
use crate::file_data::HasFileData;
|
|
||||||
use crate::geometry::PixelsSize;
|
|
||||||
use crate::geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint};
|
|
||||||
use crate::input_data::{decode_key_location, decode_mouse_button_set, MouseButton};
|
|
||||||
use crate::prelude::*;
|
|
||||||
use keyboard_types::{Code, Key, Modifiers};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
use web_sys::{js_sys, ResizeObserverEntry};
|
|
||||||
use web_sys::{
|
|
||||||
AnimationEvent, CompositionEvent, CustomEvent, Event, KeyboardEvent, MouseEvent, PointerEvent,
|
|
||||||
Touch, TouchEvent, TransitionEvent, WheelEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
macro_rules! uncheck_convert {
|
|
||||||
($t:ty, $d:ty) => {
|
|
||||||
impl From<Event> for $d {
|
|
||||||
#[inline]
|
|
||||||
fn from(e: Event) -> Self {
|
|
||||||
let e: $t = e.unchecked_into();
|
|
||||||
Self::from(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Event> for $d {
|
|
||||||
#[inline]
|
|
||||||
fn from(e: &Event) -> Self {
|
|
||||||
let e: &$t = e.unchecked_ref();
|
|
||||||
Self::from(e.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
($($t:ty => $d:ty),+ $(,)?) => {
|
|
||||||
$(uncheck_convert!($t, $d);)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
uncheck_convert![
|
|
||||||
web_sys::CompositionEvent => CompositionData,
|
|
||||||
web_sys::KeyboardEvent => KeyboardData,
|
|
||||||
web_sys::MouseEvent => MouseData,
|
|
||||||
web_sys::TouchEvent => TouchData,
|
|
||||||
web_sys::PointerEvent => PointerData,
|
|
||||||
web_sys::WheelEvent => WheelData,
|
|
||||||
web_sys::AnimationEvent => AnimationData,
|
|
||||||
web_sys::TransitionEvent => TransitionData,
|
|
||||||
web_sys::MouseEvent => DragData,
|
|
||||||
web_sys::FocusEvent => FocusData,
|
|
||||||
];
|
|
||||||
|
|
||||||
impl From<Event> for ResizeData {
|
|
||||||
#[inline]
|
|
||||||
fn from(e: Event) -> Self {
|
|
||||||
<ResizeData as From<&Event>>::from(&e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Event> for ResizeData {
|
|
||||||
#[inline]
|
|
||||||
fn from(e: &Event) -> Self {
|
|
||||||
let e: &CustomEvent = e.unchecked_ref();
|
|
||||||
let value = e.detail();
|
|
||||||
Self::from(value.unchecked_into::<ResizeObserverEntry>())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasCompositionData for CompositionEvent {
|
|
||||||
fn data(&self) -> std::string::String {
|
|
||||||
self.data().unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasKeyboardData for KeyboardEvent {
|
|
||||||
fn key(&self) -> Key {
|
|
||||||
Key::from_str(self.key().as_str()).unwrap_or(Key::Unidentified)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn code(&self) -> Code {
|
|
||||||
Code::from_str(self.code().as_str()).unwrap_or(Code::Unidentified)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn location(&self) -> keyboard_types::Location {
|
|
||||||
decode_key_location(self.location() as usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_auto_repeating(&self) -> bool {
|
|
||||||
self.repeat()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_composing(&self) -> bool {
|
|
||||||
self.is_composing()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModifiersInteraction for KeyboardEvent {
|
|
||||||
fn modifiers(&self) -> Modifiers {
|
|
||||||
let mut modifiers = Modifiers::empty();
|
|
||||||
|
|
||||||
if self.alt_key() {
|
|
||||||
modifiers.insert(Modifiers::ALT);
|
|
||||||
}
|
|
||||||
if self.ctrl_key() {
|
|
||||||
modifiers.insert(Modifiers::CONTROL);
|
|
||||||
}
|
|
||||||
if self.meta_key() {
|
|
||||||
modifiers.insert(Modifiers::META);
|
|
||||||
}
|
|
||||||
if self.shift_key() {
|
|
||||||
modifiers.insert(Modifiers::SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionLocation for MouseEvent {
|
|
||||||
fn client_coordinates(&self) -> ClientPoint {
|
|
||||||
ClientPoint::new(self.client_x().into(), self.client_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn page_coordinates(&self) -> PagePoint {
|
|
||||||
PagePoint::new(self.page_x().into(), self.page_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_coordinates(&self) -> ScreenPoint {
|
|
||||||
ScreenPoint::new(self.screen_x().into(), self.screen_y().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionElementOffset for MouseEvent {
|
|
||||||
fn element_coordinates(&self) -> ElementPoint {
|
|
||||||
ElementPoint::new(self.offset_x().into(), self.offset_y().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModifiersInteraction for MouseEvent {
|
|
||||||
fn modifiers(&self) -> Modifiers {
|
|
||||||
let mut modifiers = Modifiers::empty();
|
|
||||||
|
|
||||||
if self.alt_key() {
|
|
||||||
modifiers.insert(Modifiers::ALT);
|
|
||||||
}
|
|
||||||
if self.ctrl_key() {
|
|
||||||
modifiers.insert(Modifiers::CONTROL);
|
|
||||||
}
|
|
||||||
if self.meta_key() {
|
|
||||||
modifiers.insert(Modifiers::META);
|
|
||||||
}
|
|
||||||
if self.shift_key() {
|
|
||||||
modifiers.insert(Modifiers::SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PointerInteraction for MouseEvent {
|
|
||||||
fn held_buttons(&self) -> crate::input_data::MouseButtonSet {
|
|
||||||
decode_mouse_button_set(self.buttons())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trigger_button(&self) -> Option<MouseButton> {
|
|
||||||
Some(MouseButton::from_web_code(self.button()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasMouseData for MouseEvent {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasFileData for MouseEvent {}
|
|
||||||
|
|
||||||
impl HasDragData for MouseEvent {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModifiersInteraction for TouchEvent {
|
|
||||||
fn modifiers(&self) -> Modifiers {
|
|
||||||
let mut modifiers = Modifiers::empty();
|
|
||||||
|
|
||||||
if self.alt_key() {
|
|
||||||
modifiers.insert(Modifiers::ALT);
|
|
||||||
}
|
|
||||||
if self.ctrl_key() {
|
|
||||||
modifiers.insert(Modifiers::CONTROL);
|
|
||||||
}
|
|
||||||
if self.meta_key() {
|
|
||||||
modifiers.insert(Modifiers::META);
|
|
||||||
}
|
|
||||||
if self.shift_key() {
|
|
||||||
modifiers.insert(Modifiers::SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::events::HasTouchData for TouchEvent {
|
|
||||||
fn touches(&self) -> Vec<TouchPoint> {
|
|
||||||
let touches = TouchEvent::touches(self);
|
|
||||||
let mut result = Vec::with_capacity(touches.length() as usize);
|
|
||||||
for i in 0..touches.length() {
|
|
||||||
let touch = touches.get(i).unwrap();
|
|
||||||
result.push(TouchPoint::new(touch));
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn touches_changed(&self) -> Vec<TouchPoint> {
|
|
||||||
let touches = self.changed_touches();
|
|
||||||
let mut result = Vec::with_capacity(touches.length() as usize);
|
|
||||||
for i in 0..touches.length() {
|
|
||||||
let touch = touches.get(i).unwrap();
|
|
||||||
result.push(TouchPoint::new(touch));
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn target_touches(&self) -> Vec<TouchPoint> {
|
|
||||||
let touches = self.target_touches();
|
|
||||||
let mut result = Vec::with_capacity(touches.length() as usize);
|
|
||||||
for i in 0..touches.length() {
|
|
||||||
let touch = touches.get(i).unwrap();
|
|
||||||
result.push(TouchPoint::new(touch));
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasTouchPointData for Touch {
|
|
||||||
fn identifier(&self) -> i32 {
|
|
||||||
self.identifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn radius(&self) -> ScreenPoint {
|
|
||||||
ScreenPoint::new(self.radius_x().into(), self.radius_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rotation(&self) -> f64 {
|
|
||||||
self.rotation_angle() as f64
|
|
||||||
}
|
|
||||||
|
|
||||||
fn force(&self) -> f64 {
|
|
||||||
self.force() as f64
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionLocation for Touch {
|
|
||||||
fn client_coordinates(&self) -> ClientPoint {
|
|
||||||
ClientPoint::new(self.client_x().into(), self.client_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_coordinates(&self) -> ScreenPoint {
|
|
||||||
ScreenPoint::new(self.screen_x().into(), self.screen_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn page_coordinates(&self) -> PagePoint {
|
|
||||||
PagePoint::new(self.page_x().into(), self.page_y().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasPointerData for PointerEvent {
|
|
||||||
fn pointer_id(&self) -> i32 {
|
|
||||||
self.pointer_id()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn width(&self) -> i32 {
|
|
||||||
self.width()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> i32 {
|
|
||||||
self.height()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pressure(&self) -> f32 {
|
|
||||||
self.pressure()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tangential_pressure(&self) -> f32 {
|
|
||||||
self.tangential_pressure()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tilt_x(&self) -> i32 {
|
|
||||||
self.tilt_x()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tilt_y(&self) -> i32 {
|
|
||||||
self.tilt_y()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn twist(&self) -> i32 {
|
|
||||||
self.twist()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pointer_type(&self) -> String {
|
|
||||||
self.pointer_type()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_primary(&self) -> bool {
|
|
||||||
self.is_primary()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionLocation for PointerEvent {
|
|
||||||
fn client_coordinates(&self) -> ClientPoint {
|
|
||||||
ClientPoint::new(self.client_x().into(), self.client_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_coordinates(&self) -> ScreenPoint {
|
|
||||||
ScreenPoint::new(self.screen_x().into(), self.screen_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn page_coordinates(&self) -> PagePoint {
|
|
||||||
PagePoint::new(self.page_x().into(), self.page_y().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionElementOffset for PointerEvent {
|
|
||||||
fn element_coordinates(&self) -> ElementPoint {
|
|
||||||
ElementPoint::new(self.offset_x().into(), self.offset_y().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModifiersInteraction for PointerEvent {
|
|
||||||
fn modifiers(&self) -> Modifiers {
|
|
||||||
let mut modifiers = Modifiers::empty();
|
|
||||||
|
|
||||||
if self.alt_key() {
|
|
||||||
modifiers.insert(Modifiers::ALT);
|
|
||||||
}
|
|
||||||
if self.ctrl_key() {
|
|
||||||
modifiers.insert(Modifiers::CONTROL);
|
|
||||||
}
|
|
||||||
if self.meta_key() {
|
|
||||||
modifiers.insert(Modifiers::META);
|
|
||||||
}
|
|
||||||
if self.shift_key() {
|
|
||||||
modifiers.insert(Modifiers::SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PointerInteraction for PointerEvent {
|
|
||||||
fn held_buttons(&self) -> crate::input_data::MouseButtonSet {
|
|
||||||
decode_mouse_button_set(self.buttons())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trigger_button(&self) -> Option<MouseButton> {
|
|
||||||
Some(MouseButton::from_web_code(self.button()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasWheelData for WheelEvent {
|
|
||||||
fn delta(&self) -> crate::geometry::WheelDelta {
|
|
||||||
crate::geometry::WheelDelta::from_web_attributes(
|
|
||||||
self.delta_mode(),
|
|
||||||
self.delta_x(),
|
|
||||||
self.delta_y(),
|
|
||||||
self.delta_z(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasMouseData for WheelEvent {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionLocation for WheelEvent {
|
|
||||||
fn client_coordinates(&self) -> ClientPoint {
|
|
||||||
ClientPoint::new(self.client_x().into(), self.client_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_coordinates(&self) -> ScreenPoint {
|
|
||||||
ScreenPoint::new(self.screen_x().into(), self.screen_y().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn page_coordinates(&self) -> PagePoint {
|
|
||||||
PagePoint::new(self.page_x().into(), self.page_y().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionElementOffset for WheelEvent {
|
|
||||||
fn element_coordinates(&self) -> ElementPoint {
|
|
||||||
ElementPoint::new(self.offset_x().into(), self.offset_y().into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModifiersInteraction for WheelEvent {
|
|
||||||
fn modifiers(&self) -> Modifiers {
|
|
||||||
let mut modifiers = Modifiers::empty();
|
|
||||||
|
|
||||||
if self.alt_key() {
|
|
||||||
modifiers.insert(Modifiers::ALT);
|
|
||||||
}
|
|
||||||
if self.ctrl_key() {
|
|
||||||
modifiers.insert(Modifiers::CONTROL);
|
|
||||||
}
|
|
||||||
if self.meta_key() {
|
|
||||||
modifiers.insert(Modifiers::META);
|
|
||||||
}
|
|
||||||
if self.shift_key() {
|
|
||||||
modifiers.insert(Modifiers::SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PointerInteraction for WheelEvent {
|
|
||||||
fn held_buttons(&self) -> crate::input_data::MouseButtonSet {
|
|
||||||
decode_mouse_button_set(self.buttons())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trigger_button(&self) -> Option<MouseButton> {
|
|
||||||
Some(MouseButton::from_web_code(self.button()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasAnimationData for AnimationEvent {
|
|
||||||
fn animation_name(&self) -> String {
|
|
||||||
self.animation_name()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pseudo_element(&self) -> String {
|
|
||||||
self.pseudo_element()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn elapsed_time(&self) -> f32 {
|
|
||||||
self.elapsed_time()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasTransitionData for TransitionEvent {
|
|
||||||
fn elapsed_time(&self) -> f32 {
|
|
||||||
self.elapsed_time()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn property_name(&self) -> String {
|
|
||||||
self.property_name()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pseudo_element(&self) -> String {
|
|
||||||
self.pseudo_element()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "mounted")]
|
|
||||||
impl From<&web_sys::Element> for MountedData {
|
|
||||||
fn from(e: &web_sys::Element) -> Self {
|
|
||||||
MountedData::new(e.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "mounted")]
|
|
||||||
impl crate::RenderedElementBacking for web_sys::Element {
|
|
||||||
fn get_scroll_offset(
|
|
||||||
&self,
|
|
||||||
) -> std::pin::Pin<
|
|
||||||
Box<
|
|
||||||
dyn std::future::Future<Output = crate::MountedResult<crate::geometry::PixelsVector2D>>,
|
|
||||||
>,
|
|
||||||
> {
|
|
||||||
let left = self.scroll_left();
|
|
||||||
let top = self.scroll_top();
|
|
||||||
let result = Ok(crate::geometry::PixelsVector2D::new(
|
|
||||||
left as f64,
|
|
||||||
top as f64,
|
|
||||||
));
|
|
||||||
Box::pin(async { result })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_scroll_size(
|
|
||||||
&self,
|
|
||||||
) -> std::pin::Pin<
|
|
||||||
Box<dyn std::future::Future<Output = crate::MountedResult<crate::geometry::PixelsSize>>>,
|
|
||||||
> {
|
|
||||||
let width = self.scroll_width();
|
|
||||||
let height = self.scroll_height();
|
|
||||||
let result = Ok(crate::geometry::PixelsSize::new(
|
|
||||||
width as f64,
|
|
||||||
height as f64,
|
|
||||||
));
|
|
||||||
Box::pin(async { result })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_client_rect(
|
|
||||||
&self,
|
|
||||||
) -> std::pin::Pin<
|
|
||||||
Box<dyn std::future::Future<Output = crate::MountedResult<crate::geometry::PixelsRect>>>,
|
|
||||||
> {
|
|
||||||
let rect = self.get_bounding_client_rect();
|
|
||||||
let result = Ok(crate::geometry::PixelsRect::new(
|
|
||||||
euclid::Point2D::new(rect.left(), rect.top()),
|
|
||||||
euclid::Size2D::new(rect.width(), rect.height()),
|
|
||||||
));
|
|
||||||
Box::pin(async { result })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scroll_to(
|
|
||||||
&self,
|
|
||||||
behavior: crate::ScrollBehavior,
|
|
||||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::MountedResult<()>>>> {
|
|
||||||
let options = web_sys::ScrollIntoViewOptions::new();
|
|
||||||
match behavior {
|
|
||||||
crate::ScrollBehavior::Instant => {
|
|
||||||
options.set_behavior(web_sys::ScrollBehavior::Instant);
|
|
||||||
}
|
|
||||||
crate::ScrollBehavior::Smooth => {
|
|
||||||
options.set_behavior(web_sys::ScrollBehavior::Smooth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.scroll_into_view_with_scroll_into_view_options(&options);
|
|
||||||
|
|
||||||
Box::pin(async { Ok(()) })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_focus(
|
|
||||||
&self,
|
|
||||||
focus: bool,
|
|
||||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::MountedResult<()>>>> {
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct FocusError(wasm_bindgen::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 {}
|
|
||||||
|
|
||||||
let result = self
|
|
||||||
.dyn_ref::<web_sys::HtmlElement>()
|
|
||||||
.ok_or_else(|| crate::MountedError::OperationFailed(Box::new(FocusError(self.into()))))
|
|
||||||
.and_then(|e| {
|
|
||||||
(if focus { e.focus() } else { e.blur() })
|
|
||||||
.map_err(|err| crate::MountedError::OperationFailed(Box::new(FocusError(err))))
|
|
||||||
});
|
|
||||||
Box::pin(async { result })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_first_size(resize_observer_output: js_sys::Array) -> ResizeResult<PixelsSize> {
|
|
||||||
let first = resize_observer_output.get(0);
|
|
||||||
let size = first.unchecked_into::<web_sys::ResizeObserverSize>();
|
|
||||||
|
|
||||||
// inline_size matches the width of the element if its writing-mode is horizontal, the height otherwise
|
|
||||||
let inline_size = size.inline_size();
|
|
||||||
// block_size matches the height of the element if its writing-mode is horizontal, the width otherwise
|
|
||||||
let block_size = size.block_size();
|
|
||||||
|
|
||||||
Ok(PixelsSize::new(inline_size, block_size))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasResizeData for ResizeObserverEntry {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_border_box_size(&self) -> ResizeResult<PixelsSize> {
|
|
||||||
extract_first_size(self.border_box_size())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_content_box_size(&self) -> ResizeResult<PixelsSize> {
|
|
||||||
extract_first_size(self.content_box_size())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasScrollData for Event {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasClipboardData for Event {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Event> for ClipboardData {
|
|
||||||
fn from(e: &Event) -> Self {
|
|
||||||
ClipboardData::new(e.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasFocusData for web_sys::FocusEvent {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasToggleData for web_sys::Event {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasSelectionData for web_sys::Event {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasMediaData for web_sys::Event {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasFileData for web_sys::Event {
|
|
||||||
#[cfg(feature = "file_engine")]
|
|
||||||
fn files(&self) -> Option<std::sync::Arc<dyn crate::file_data::FileEngine>> {
|
|
||||||
let files = self
|
|
||||||
.dyn_ref()
|
|
||||||
.and_then(|input: &web_sys::HtmlInputElement| {
|
|
||||||
input.files().and_then(|files| {
|
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
|
||||||
crate::web_sys_bind::file_engine::WebFileEngine::new(files)
|
|
||||||
.map(|f| std::sync::Arc::new(f) as std::sync::Arc<dyn crate::FileEngine>)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
files
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
mod events;
|
|
||||||
#[cfg(feature = "file_engine")]
|
|
||||||
mod file_engine;
|
|
||||||
#[cfg(feature = "file_engine")]
|
|
||||||
pub use file_engine::*;
|
|
|
@ -12,7 +12,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus-core = { workspace = true }
|
dioxus-core = { workspace = true }
|
||||||
dioxus-core-types = { workspace = true }
|
dioxus-core-types = { workspace = true }
|
||||||
dioxus-html = { workspace = true, features = ["wasm-bind"] }
|
dioxus-html = { workspace = true }
|
||||||
dioxus-devtools = { workspace = true }
|
dioxus-devtools = { workspace = true }
|
||||||
dioxus-signals = { workspace = true }
|
dioxus-signals = { workspace = true }
|
||||||
dioxus-interpreter-js = { workspace = true, features = [
|
dioxus-interpreter-js = { workspace = true, features = [
|
||||||
|
@ -38,33 +38,66 @@ serde = { version = "1.0", optional = true }
|
||||||
serde-wasm-bindgen = { version = "0.5.0", optional = true }
|
serde-wasm-bindgen = { version = "0.5.0", optional = true }
|
||||||
|
|
||||||
ciborium = { workspace = true, optional = true }
|
ciborium = { workspace = true, optional = true }
|
||||||
|
async-trait = { version = "0.1.58", optional = true }
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
version = "0.3.56"
|
version = "0.3.56"
|
||||||
features = [
|
features = [
|
||||||
|
"AnimationEvent",
|
||||||
|
"ClipboardEvent",
|
||||||
|
"CloseEvent",
|
||||||
|
"Comment",
|
||||||
|
"CompositionEvent",
|
||||||
|
"console",
|
||||||
|
"CustomEvent",
|
||||||
|
"DataTransfer",
|
||||||
"Document",
|
"Document",
|
||||||
|
"DragEvent",
|
||||||
|
"FocusEvent",
|
||||||
"HtmlElement",
|
"HtmlElement",
|
||||||
|
"HtmlFormElement",
|
||||||
"HtmlInputElement",
|
"HtmlInputElement",
|
||||||
"HtmlSelectElement",
|
"HtmlSelectElement",
|
||||||
"HtmlTextAreaElement",
|
"HtmlTextAreaElement",
|
||||||
"HtmlFormElement",
|
"InputEvent",
|
||||||
"Text",
|
"KeyboardEvent",
|
||||||
"Comment",
|
"MouseEvent",
|
||||||
"Window",
|
|
||||||
"DataTransfer",
|
|
||||||
"console",
|
|
||||||
"NodeList",
|
"NodeList",
|
||||||
"CloseEvent",
|
"PointerEvent",
|
||||||
"CustomEvent",
|
"ResizeObserverEntry",
|
||||||
|
"ResizeObserverSize",
|
||||||
|
"Text",
|
||||||
|
"Touch",
|
||||||
|
"TouchEvent",
|
||||||
|
"TouchList",
|
||||||
|
"TransitionEvent",
|
||||||
|
"WheelEvent",
|
||||||
|
"Window",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
lazy-js-bundle = { workspace = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["panic_hook", "mounted", "file_engine", "devtools", "document"]
|
default = ["panic_hook", "mounted", "file_engine", "devtools", "document"]
|
||||||
panic_hook = ["dep:console_error_panic_hook"]
|
panic_hook = ["dep:console_error_panic_hook"]
|
||||||
hydrate = ["web-sys/Comment", "ciborium", "dep:serde"]
|
hydrate = ["web-sys/Comment", "ciborium", "dep:serde"]
|
||||||
mounted = ["web-sys/Element", "dioxus-html/mounted"]
|
mounted = [
|
||||||
|
"web-sys/Element",
|
||||||
|
"dioxus-html/mounted",
|
||||||
|
"web-sys/Element",
|
||||||
|
"web-sys/DomRect",
|
||||||
|
"web-sys/ScrollIntoViewOptions",
|
||||||
|
"web-sys/ScrollLogicalPosition",
|
||||||
|
"web-sys/ScrollBehavior",
|
||||||
|
"web-sys/HtmlElement",
|
||||||
|
]
|
||||||
file_engine = [
|
file_engine = [
|
||||||
"dioxus-html/file_engine",
|
"dioxus-html/file_engine",
|
||||||
|
"dep:async-trait",
|
||||||
|
"web-sys/File",
|
||||||
|
"web-sys/FileList",
|
||||||
|
"web-sys/FileReader"
|
||||||
]
|
]
|
||||||
devtools = ["web-sys/MessageEvent", "web-sys/WebSocket", "web-sys/Location", "dep:serde_json", "dep:serde", "dioxus-core/serialize"]
|
devtools = ["web-sys/MessageEvent", "web-sys/WebSocket", "web-sys/Location", "dep:serde_json", "dep:serde", "dioxus-core/serialize"]
|
||||||
document = ["dioxus-html/document", "dep:serde-wasm-bindgen", "dep:serde_json", "dep:serde"]
|
document = ["dioxus-html/document", "dep:serde-wasm-bindgen", "dep:serde_json", "dep:serde"]
|
||||||
|
|
7
packages/web/build.rs
Normal file
7
packages/web/build.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
// If any TS files change, re-run the build script
|
||||||
|
lazy_js_bundle::LazyTypeScriptBindings::new()
|
||||||
|
.with_watching("./src/ts")
|
||||||
|
.with_binding("./src/ts/eval.ts", "./src/js/eval.js")
|
||||||
|
.run();
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
use dioxus_core::ScopeId;
|
use dioxus_core::ScopeId;
|
||||||
use dioxus_html::document::{
|
use dioxus_html::document::{Document, EvalError, Evaluator};
|
||||||
Document, EvalError, Evaluator, JSOwner, WeakDioxusChannel, WebDioxusChannel,
|
|
||||||
};
|
|
||||||
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
|
use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
|
||||||
use js_sys::Function;
|
use js_sys::Function;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -11,6 +9,50 @@ use std::pin::Pin;
|
||||||
use std::{rc::Rc, str::FromStr};
|
use std::{rc::Rc, str::FromStr};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||||
|
pub struct JSOwner {
|
||||||
|
_owner: Box<dyn std::any::Any>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JSOwner {
|
||||||
|
pub fn new(owner: impl std::any::Any) -> Self {
|
||||||
|
Self {
|
||||||
|
_owner: Box::new(owner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen::prelude::wasm_bindgen(module = "/src/js/eval.js")]
|
||||||
|
extern "C" {
|
||||||
|
pub type WebDioxusChannel;
|
||||||
|
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new(owner: JSOwner) -> WebDioxusChannel;
|
||||||
|
|
||||||
|
#[wasm_bindgen(method, js_name = "rustSend")]
|
||||||
|
pub fn rust_send(this: &WebDioxusChannel, value: wasm_bindgen::JsValue);
|
||||||
|
|
||||||
|
#[wasm_bindgen(method, js_name = "rustRecv")]
|
||||||
|
pub async fn rust_recv(this: &WebDioxusChannel) -> wasm_bindgen::JsValue;
|
||||||
|
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
pub fn send(this: &WebDioxusChannel, value: wasm_bindgen::JsValue);
|
||||||
|
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
pub async fn recv(this: &WebDioxusChannel) -> wasm_bindgen::JsValue;
|
||||||
|
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
pub fn weak(this: &WebDioxusChannel) -> WeakDioxusChannel;
|
||||||
|
|
||||||
|
pub type WeakDioxusChannel;
|
||||||
|
|
||||||
|
#[wasm_bindgen(method, js_name = "rustSend")]
|
||||||
|
pub fn rust_send(this: &WeakDioxusChannel, value: wasm_bindgen::JsValue);
|
||||||
|
|
||||||
|
#[wasm_bindgen(method, js_name = "rustRecv")]
|
||||||
|
pub async fn rust_recv(this: &WeakDioxusChannel) -> wasm_bindgen::JsValue;
|
||||||
|
}
|
||||||
|
|
||||||
/// Provides the WebEvalProvider through [`ScopeId::provide_context`].
|
/// Provides the WebEvalProvider through [`ScopeId::provide_context`].
|
||||||
pub fn init_document() {
|
pub fn init_document() {
|
||||||
let provider: Rc<dyn Document> = Rc::new(WebDocument);
|
let provider: Rc<dyn Document> = Rc::new(WebDocument);
|
||||||
|
|
|
@ -1,591 +0,0 @@
|
||||||
use std::{any::Any, collections::HashMap};
|
|
||||||
|
|
||||||
use dioxus_html::{
|
|
||||||
point_interaction::{
|
|
||||||
InteractionElementOffset, InteractionLocation, ModifiersInteraction, PointerInteraction,
|
|
||||||
},
|
|
||||||
DragData, FormData, FormValue, HasDragData, HasFileData, HasFormData, HasImageData,
|
|
||||||
HasMouseData, HtmlEventConverter, ImageData, MountedData, PlatformEventData, ScrollData,
|
|
||||||
};
|
|
||||||
use js_sys::Array;
|
|
||||||
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
|
|
||||||
use web_sys::{Document, Element, Event, MouseEvent};
|
|
||||||
|
|
||||||
pub(crate) struct WebEventConverter;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn downcast_event(event: &dioxus_html::PlatformEventData) -> &GenericWebSysEvent {
|
|
||||||
event
|
|
||||||
.downcast::<GenericWebSysEvent>()
|
|
||||||
.expect("event should be a GenericWebSysEvent")
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HtmlEventConverter for WebEventConverter {
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_animation_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::AnimationData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_clipboard_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::ClipboardData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_composition_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::CompositionData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData {
|
|
||||||
let event = downcast_event(event);
|
|
||||||
DragData::new(WebDragData::new(event.raw.clone().unchecked_into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_focus_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FocusData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_form_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FormData {
|
|
||||||
let event = downcast_event(event);
|
|
||||||
FormData::new(WebFormData::new(event.element.clone(), event.raw.clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_image_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::ImageData {
|
|
||||||
let event = downcast_event(event);
|
|
||||||
let error = event.raw.type_() == "error";
|
|
||||||
ImageData::new(WebImageEvent::new(event.raw.clone(), error))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_keyboard_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::KeyboardData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_media_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MediaData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_mounted_data(&self, event: &dioxus_html::PlatformEventData) -> MountedData {
|
|
||||||
#[cfg(feature = "mounted")]
|
|
||||||
{
|
|
||||||
MountedData::from(
|
|
||||||
event
|
|
||||||
.downcast::<web_sys::Element>()
|
|
||||||
.expect("event should be a web_sys::Element"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "mounted"))]
|
|
||||||
{
|
|
||||||
panic!("mounted events are not supported without the mounted feature on the dioxus-web crate enabled")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_mouse_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MouseData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_pointer_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::PointerData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_resize_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::ResizeData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_scroll_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::ScrollData {
|
|
||||||
ScrollData::from(downcast_event(event).raw.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_selection_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::SelectionData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_toggle_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::ToggleData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_touch_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::TouchData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_transition_data(
|
|
||||||
&self,
|
|
||||||
event: &dioxus_html::PlatformEventData,
|
|
||||||
) -> dioxus_html::TransitionData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn convert_wheel_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::WheelData {
|
|
||||||
downcast_event(event).raw.clone().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A extension trait for web-sys events that provides a way to get the event as a web-sys event.
|
|
||||||
pub trait WebEventExt<E> {
|
|
||||||
/// Try to downcast this event as a `web-sys` event.
|
|
||||||
fn try_as_web_event(&self) -> Option<E>;
|
|
||||||
|
|
||||||
/// Downcast this event as a `web-sys` event.
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_web_event(&self) -> E
|
|
||||||
where
|
|
||||||
E: 'static,
|
|
||||||
{
|
|
||||||
self.try_as_web_event().unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"Error downcasting to `web-sys`, event should be a {}.",
|
|
||||||
std::any::type_name::<E>()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::AnimationEvent> for dioxus_html::AnimationData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::AnimationEvent> {
|
|
||||||
self.downcast::<web_sys::AnimationEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::Event> for dioxus_html::ClipboardData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::Event> {
|
|
||||||
self.downcast::<web_sys::Event>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::CompositionEvent> for dioxus_html::CompositionData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::CompositionEvent> {
|
|
||||||
self.downcast::<web_sys::CompositionEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::MouseEvent> for dioxus_html::DragData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::MouseEvent> {
|
|
||||||
self.downcast::<WebDragData>()
|
|
||||||
.map(|data| &data.raw)
|
|
||||||
.cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::FocusEvent> for dioxus_html::FocusData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::FocusEvent> {
|
|
||||||
self.downcast::<web_sys::FocusEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::Event> for dioxus_html::FormData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::Event> {
|
|
||||||
self.downcast::<web_sys::Event>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<WebImageEvent> for dioxus_html::ImageData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<WebImageEvent> {
|
|
||||||
self.downcast::<WebImageEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::KeyboardEvent> for dioxus_html::KeyboardData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::KeyboardEvent> {
|
|
||||||
self.downcast::<web_sys::KeyboardEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::Event> for dioxus_html::MediaData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::Event> {
|
|
||||||
self.downcast::<web_sys::Event>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::Element> for MountedData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::Element> {
|
|
||||||
self.downcast::<web_sys::Element>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::MouseEvent> for dioxus_html::MouseData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::MouseEvent> {
|
|
||||||
self.downcast::<web_sys::MouseEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::PointerEvent> for dioxus_html::PointerData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::PointerEvent> {
|
|
||||||
self.downcast::<web_sys::PointerEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::Event> for ScrollData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::Event> {
|
|
||||||
self.downcast::<web_sys::Event>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::Event> for dioxus_html::SelectionData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::Event> {
|
|
||||||
self.downcast::<web_sys::Event>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::Event> for dioxus_html::ToggleData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::Event> {
|
|
||||||
self.downcast::<web_sys::Event>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::TouchEvent> for dioxus_html::TouchData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::TouchEvent> {
|
|
||||||
self.downcast::<web_sys::TouchEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::TransitionEvent> for dioxus_html::TransitionData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::TransitionEvent> {
|
|
||||||
self.downcast::<web_sys::TransitionEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::WheelEvent> for dioxus_html::WheelData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::WheelEvent> {
|
|
||||||
self.downcast::<web_sys::WheelEvent>().cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebEventExt<web_sys::ResizeObserverEntry> for dioxus_html::ResizeData {
|
|
||||||
#[inline(always)]
|
|
||||||
fn try_as_web_event(&self) -> Option<web_sys::ResizeObserverEntry> {
|
|
||||||
self.downcast::<web_sys::CustomEvent>()
|
|
||||||
.and_then(|e| e.detail().dyn_into::<web_sys::ResizeObserverEntry>().ok())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GenericWebSysEvent {
|
|
||||||
raw: Event,
|
|
||||||
element: Element,
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: some of these events are being casted to the wrong event type.
|
|
||||||
// We need tests that simulate clicks/etc and make sure every event type works.
|
|
||||||
pub(crate) fn virtual_event_from_websys_event(
|
|
||||||
event: web_sys::Event,
|
|
||||||
target: Element,
|
|
||||||
) -> PlatformEventData {
|
|
||||||
PlatformEventData::new(Box::new(GenericWebSysEvent {
|
|
||||||
raw: event,
|
|
||||||
element: target,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn load_document() -> Document {
|
|
||||||
web_sys::window()
|
|
||||||
.expect("should have access to the Window")
|
|
||||||
.document()
|
|
||||||
.expect("should have access to the Document")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct WebImageEvent {
|
|
||||||
raw: Event,
|
|
||||||
error: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebImageEvent {
|
|
||||||
fn new(raw: Event, error: bool) -> Self {
|
|
||||||
Self { raw, error }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasImageData for WebImageEvent {
|
|
||||||
fn load_error(&self) -> bool {
|
|
||||||
self.error
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
&self.raw as &dyn Any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WebFormData {
|
|
||||||
element: Element,
|
|
||||||
raw: Event,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebFormData {
|
|
||||||
fn new(element: Element, raw: Event) -> Self {
|
|
||||||
Self { element, raw }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasFormData for WebFormData {
|
|
||||||
fn value(&self) -> String {
|
|
||||||
let target = &self.element;
|
|
||||||
target
|
|
||||||
.dyn_ref()
|
|
||||||
.map(|input: &web_sys::HtmlInputElement| {
|
|
||||||
// todo: special case more input types
|
|
||||||
match input.type_().as_str() {
|
|
||||||
"checkbox" => {
|
|
||||||
match input.checked() {
|
|
||||||
true => "true".to_string(),
|
|
||||||
false => "false".to_string(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
input.value()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
target
|
|
||||||
.dyn_ref()
|
|
||||||
.map(|input: &web_sys::HtmlTextAreaElement| input.value())
|
|
||||||
})
|
|
||||||
// select elements are NOT input events - because - why woudn't they be??
|
|
||||||
.or_else(|| {
|
|
||||||
target
|
|
||||||
.dyn_ref()
|
|
||||||
.map(|input: &web_sys::HtmlSelectElement| input.value())
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
target
|
|
||||||
.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")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn values(&self) -> HashMap<String, FormValue> {
|
|
||||||
let mut values = HashMap::new();
|
|
||||||
|
|
||||||
fn insert_value(map: &mut HashMap<String, FormValue>, key: String, new_value: String) {
|
|
||||||
map.entry(key.clone()).or_default().0.push(new_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to fill in form values
|
|
||||||
if let Some(form) = self.element.dyn_ref::<web_sys::HtmlFormElement>() {
|
|
||||||
let form_data = get_form_data(form);
|
|
||||||
for value in form_data.entries().into_iter().flatten() {
|
|
||||||
if let Ok(array) = value.dyn_into::<Array>() {
|
|
||||||
if let Some(name) = array.get(0).as_string() {
|
|
||||||
if let Ok(item_values) = array.get(1).dyn_into::<Array>() {
|
|
||||||
item_values
|
|
||||||
.iter()
|
|
||||||
.filter_map(|v| v.as_string())
|
|
||||||
.for_each(|v| insert_value(&mut values, name.clone(), v));
|
|
||||||
} else if let Ok(item_value) = array.get(1).dyn_into::<JsValue>() {
|
|
||||||
insert_value(&mut values, name, item_value.as_string().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let Some(select) = self.element.dyn_ref::<web_sys::HtmlSelectElement>() {
|
|
||||||
// try to fill in select element values
|
|
||||||
let options = get_select_data(select);
|
|
||||||
values.insert("options".to_string(), FormValue(options));
|
|
||||||
}
|
|
||||||
|
|
||||||
values
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
&self.raw as &dyn Any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasFileData for WebFormData {
|
|
||||||
#[cfg(feature = "file_engine")]
|
|
||||||
fn files(&self) -> Option<std::sync::Arc<dyn dioxus_html::FileEngine>> {
|
|
||||||
let files = self
|
|
||||||
.element
|
|
||||||
.dyn_ref()
|
|
||||||
.and_then(|input: &web_sys::HtmlInputElement| {
|
|
||||||
input.files().and_then(|files| {
|
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
|
||||||
dioxus_html::WebFileEngine::new(files).map(|f| {
|
|
||||||
std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WebDragData {
|
|
||||||
raw: MouseEvent,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WebDragData {
|
|
||||||
fn new(raw: MouseEvent) -> Self {
|
|
||||||
Self { raw }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasDragData for WebDragData {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
&self.raw as &dyn std::any::Any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasMouseData for WebDragData {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
&self.raw as &dyn std::any::Any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PointerInteraction for WebDragData {
|
|
||||||
fn trigger_button(&self) -> Option<dioxus_html::input_data::MouseButton> {
|
|
||||||
self.raw.trigger_button()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn held_buttons(&self) -> dioxus_html::input_data::MouseButtonSet {
|
|
||||||
self.raw.held_buttons()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModifiersInteraction for WebDragData {
|
|
||||||
fn modifiers(&self) -> dioxus_html::prelude::Modifiers {
|
|
||||||
self.raw.modifiers()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionElementOffset for WebDragData {
|
|
||||||
fn coordinates(&self) -> dioxus_html::geometry::Coordinates {
|
|
||||||
self.raw.coordinates()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn element_coordinates(&self) -> dioxus_html::geometry::ElementPoint {
|
|
||||||
self.raw.element_coordinates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InteractionLocation for WebDragData {
|
|
||||||
fn client_coordinates(&self) -> dioxus_html::geometry::ClientPoint {
|
|
||||||
self.raw.client_coordinates()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_coordinates(&self) -> dioxus_html::geometry::ScreenPoint {
|
|
||||||
self.raw.screen_coordinates()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn page_coordinates(&self) -> dioxus_html::geometry::PagePoint {
|
|
||||||
self.raw.page_coordinates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasFileData for WebDragData {
|
|
||||||
#[cfg(feature = "file_engine")]
|
|
||||||
fn files(&self) -> Option<std::sync::Arc<dyn dioxus_html::FileEngine>> {
|
|
||||||
let files = self
|
|
||||||
.raw
|
|
||||||
.dyn_ref::<web_sys::DragEvent>()
|
|
||||||
.and_then(|drag_event| {
|
|
||||||
drag_event.data_transfer().and_then(|dt| {
|
|
||||||
dt.files().and_then(|files| {
|
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
|
||||||
dioxus_html::WebFileEngine::new(files).map(|f| {
|
|
||||||
std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// web-sys does not expose the keys api for form data, so we need to manually bind to it
|
|
||||||
#[wasm_bindgen(inline_js = r#"
|
|
||||||
export function get_form_data(form) {
|
|
||||||
let values = new Map();
|
|
||||||
const formData = new FormData(form);
|
|
||||||
|
|
||||||
for (let name of formData.keys()) {
|
|
||||||
values.set(name, formData.getAll(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
"#)]
|
|
||||||
extern "C" {
|
|
||||||
fn get_form_data(form: &web_sys::HtmlFormElement) -> js_sys::Map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// web-sys does not expose the keys api for select data, so we need to manually bind to it
|
|
||||||
#[wasm_bindgen(inline_js = r#"
|
|
||||||
export function get_select_data(select) {
|
|
||||||
let values = [];
|
|
||||||
for (let i = 0; i < select.options.length; i++) {
|
|
||||||
let option = select.options[i];
|
|
||||||
if (option.selected) {
|
|
||||||
values.push(option.value.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
"#)]
|
|
||||||
extern "C" {
|
|
||||||
fn get_select_data(select: &web_sys::HtmlSelectElement) -> Vec<String>;
|
|
||||||
}
|
|
32
packages/web/src/events/animation.rs
Normal file
32
packages/web/src/events/animation.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use dioxus_html::HasAnimationData;
|
||||||
|
use web_sys::AnimationEvent;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasAnimationData for Synthetic<AnimationEvent> {
|
||||||
|
fn animation_name(&self) -> String {
|
||||||
|
self.event.animation_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pseudo_element(&self) -> String {
|
||||||
|
self.event.pseudo_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn elapsed_time(&self) -> f32 {
|
||||||
|
self.event.elapsed_time()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::AnimationData {
|
||||||
|
type WebEvent = web_sys::AnimationEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::AnimationEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::AnimationEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
26
packages/web/src/events/clipboard.rs
Normal file
26
packages/web/src/events/clipboard.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use dioxus_html::HasClipboardData;
|
||||||
|
use web_sys::Event;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl From<&Event> for Synthetic<Event> {
|
||||||
|
fn from(e: &Event) -> Self {
|
||||||
|
Synthetic::new(e.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasClipboardData for Synthetic<Event> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::ClipboardData {
|
||||||
|
type WebEvent = web_sys::Event;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::Event>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
24
packages/web/src/events/composition.rs
Normal file
24
packages/web/src/events/composition.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use dioxus_html::HasCompositionData;
|
||||||
|
use web_sys::CompositionEvent;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasCompositionData for Synthetic<CompositionEvent> {
|
||||||
|
fn data(&self) -> std::string::String {
|
||||||
|
self.event.data().unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::CompositionData {
|
||||||
|
type WebEvent = web_sys::CompositionEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::CompositionEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
108
packages/web/src/events/drag.rs
Normal file
108
packages/web/src/events/drag.rs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
use dioxus_html::{
|
||||||
|
prelude::{
|
||||||
|
InteractionElementOffset, InteractionLocation, ModifiersInteraction, PointerInteraction,
|
||||||
|
},
|
||||||
|
HasDragData, HasFileData, HasMouseData,
|
||||||
|
};
|
||||||
|
use web_sys::MouseEvent;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
pub(crate) struct WebDragData {
|
||||||
|
raw: Synthetic<MouseEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebDragData {
|
||||||
|
pub fn new(raw: MouseEvent) -> Self {
|
||||||
|
Self {
|
||||||
|
raw: Synthetic::new(raw),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasDragData for WebDragData {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
&self.raw as &dyn std::any::Any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasMouseData for WebDragData {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
&self.raw as &dyn std::any::Any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerInteraction for WebDragData {
|
||||||
|
fn trigger_button(&self) -> Option<dioxus_html::input_data::MouseButton> {
|
||||||
|
self.raw.trigger_button()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn held_buttons(&self) -> dioxus_html::input_data::MouseButtonSet {
|
||||||
|
self.raw.held_buttons()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModifiersInteraction for WebDragData {
|
||||||
|
fn modifiers(&self) -> dioxus_html::prelude::Modifiers {
|
||||||
|
self.raw.modifiers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionElementOffset for WebDragData {
|
||||||
|
fn coordinates(&self) -> dioxus_html::geometry::Coordinates {
|
||||||
|
self.raw.coordinates()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn element_coordinates(&self) -> dioxus_html::geometry::ElementPoint {
|
||||||
|
self.raw.element_coordinates()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionLocation for WebDragData {
|
||||||
|
fn client_coordinates(&self) -> dioxus_html::geometry::ClientPoint {
|
||||||
|
self.raw.client_coordinates()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_coordinates(&self) -> dioxus_html::geometry::ScreenPoint {
|
||||||
|
self.raw.screen_coordinates()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_coordinates(&self) -> dioxus_html::geometry::PagePoint {
|
||||||
|
self.raw.page_coordinates()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasFileData for WebDragData {
|
||||||
|
#[cfg(feature = "file_engine")]
|
||||||
|
fn files(&self) -> Option<std::sync::Arc<dyn dioxus_html::FileEngine>> {
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
let files = self
|
||||||
|
.raw
|
||||||
|
.event
|
||||||
|
.dyn_ref::<web_sys::DragEvent>()
|
||||||
|
.and_then(|drag_event| {
|
||||||
|
drag_event.data_transfer().and_then(|dt| {
|
||||||
|
dt.files().and_then(|files| {
|
||||||
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
|
crate::file_engine::WebFileEngine::new(files).map(|f| {
|
||||||
|
std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::DragData {
|
||||||
|
type WebEvent = web_sys::MouseEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::MouseEvent> {
|
||||||
|
self.downcast::<WebDragData>()
|
||||||
|
.map(|data| &data.raw.event)
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
}
|
24
packages/web/src/events/file.rs
Normal file
24
packages/web/src/events/file.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use dioxus_html::HasFileData;
|
||||||
|
|
||||||
|
use super::Synthetic;
|
||||||
|
|
||||||
|
impl HasFileData for Synthetic<web_sys::Event> {
|
||||||
|
#[cfg(feature = "file_engine")]
|
||||||
|
fn files(&self) -> Option<std::sync::Arc<dyn dioxus_html::FileEngine>> {
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
let files = self
|
||||||
|
.event
|
||||||
|
.dyn_ref()
|
||||||
|
.and_then(|input: &web_sys::HtmlInputElement| {
|
||||||
|
input.files().and_then(|files| {
|
||||||
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
|
crate::file_engine::WebFileEngine::new(files).map(|f| {
|
||||||
|
std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
files
|
||||||
|
}
|
||||||
|
}
|
19
packages/web/src/events/focus.rs
Normal file
19
packages/web/src/events/focus.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use dioxus_html::HasFocusData;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasFocusData for Synthetic<web_sys::FocusEvent> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::FocusData {
|
||||||
|
type WebEvent = web_sys::FocusEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::FocusEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
160
packages/web/src/events/form.rs
Normal file
160
packages/web/src/events/form.rs
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
use std::{any::Any, collections::HashMap};
|
||||||
|
|
||||||
|
use dioxus_html::{FormValue, HasFileData, HasFormData};
|
||||||
|
use js_sys::Array;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
use wasm_bindgen::{prelude::wasm_bindgen, JsCast};
|
||||||
|
use web_sys::{Element, Event};
|
||||||
|
|
||||||
|
use super::WebEventExt;
|
||||||
|
|
||||||
|
pub(crate) struct WebFormData {
|
||||||
|
element: Element,
|
||||||
|
raw: Event,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::FormData {
|
||||||
|
type WebEvent = Event;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<WebFormData>().map(|e| e.raw.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebFormData {
|
||||||
|
pub fn new(element: Element, raw: Event) -> Self {
|
||||||
|
Self { element, raw }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasFormData for WebFormData {
|
||||||
|
fn value(&self) -> String {
|
||||||
|
let target = &self.element;
|
||||||
|
target
|
||||||
|
.dyn_ref()
|
||||||
|
.map(|input: &web_sys::HtmlInputElement| {
|
||||||
|
// todo: special case more input types
|
||||||
|
match input.type_().as_str() {
|
||||||
|
"checkbox" => {
|
||||||
|
match input.checked() {
|
||||||
|
true => "true".to_string(),
|
||||||
|
false => "false".to_string(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
input.value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
target
|
||||||
|
.dyn_ref()
|
||||||
|
.map(|input: &web_sys::HtmlTextAreaElement| input.value())
|
||||||
|
})
|
||||||
|
// select elements are NOT input events - because - why woudn't they be??
|
||||||
|
.or_else(|| {
|
||||||
|
target
|
||||||
|
.dyn_ref()
|
||||||
|
.map(|input: &web_sys::HtmlSelectElement| input.value())
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
target
|
||||||
|
.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")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn values(&self) -> HashMap<String, FormValue> {
|
||||||
|
let mut values = HashMap::new();
|
||||||
|
|
||||||
|
fn insert_value(map: &mut HashMap<String, FormValue>, key: String, new_value: String) {
|
||||||
|
map.entry(key.clone()).or_default().0.push(new_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to fill in form values
|
||||||
|
if let Some(form) = self.element.dyn_ref::<web_sys::HtmlFormElement>() {
|
||||||
|
let form_data = get_form_data(form);
|
||||||
|
for value in form_data.entries().into_iter().flatten() {
|
||||||
|
if let Ok(array) = value.dyn_into::<Array>() {
|
||||||
|
if let Some(name) = array.get(0).as_string() {
|
||||||
|
if let Ok(item_values) = array.get(1).dyn_into::<Array>() {
|
||||||
|
item_values
|
||||||
|
.iter()
|
||||||
|
.filter_map(|v| v.as_string())
|
||||||
|
.for_each(|v| insert_value(&mut values, name.clone(), v));
|
||||||
|
} else if let Ok(item_value) = array.get(1).dyn_into::<JsValue>() {
|
||||||
|
insert_value(&mut values, name, item_value.as_string().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(select) = self.element.dyn_ref::<web_sys::HtmlSelectElement>() {
|
||||||
|
// try to fill in select element values
|
||||||
|
let options = get_select_data(select);
|
||||||
|
values.insert("options".to_string(), FormValue(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
values
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
&self.raw as &dyn Any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasFileData for WebFormData {
|
||||||
|
#[cfg(feature = "file_engine")]
|
||||||
|
fn files(&self) -> Option<std::sync::Arc<dyn dioxus_html::FileEngine>> {
|
||||||
|
let files = self
|
||||||
|
.element
|
||||||
|
.dyn_ref()
|
||||||
|
.and_then(|input: &web_sys::HtmlInputElement| {
|
||||||
|
input.files().and_then(|files| {
|
||||||
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
|
crate::file_engine::WebFileEngine::new(files).map(|f| {
|
||||||
|
std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// web-sys does not expose the keys api for select data, so we need to manually bind to it
|
||||||
|
#[wasm_bindgen(inline_js = r#"
|
||||||
|
export function get_select_data(select) {
|
||||||
|
let values = [];
|
||||||
|
for (let i = 0; i < select.options.length; i++) {
|
||||||
|
let option = select.options[i];
|
||||||
|
if (option.selected) {
|
||||||
|
values.push(option.value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
"#)]
|
||||||
|
extern "C" {
|
||||||
|
fn get_select_data(select: &web_sys::HtmlSelectElement) -> Vec<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// web-sys does not expose the keys api for form data, so we need to manually bind to it
|
||||||
|
#[wasm_bindgen(inline_js = r#"
|
||||||
|
export function get_form_data(form) {
|
||||||
|
let values = new Map();
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
for (let name of formData.keys()) {
|
||||||
|
values.set(name, formData.getAll(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
"#)]
|
||||||
|
extern "C" {
|
||||||
|
fn get_form_data(form: &web_sys::HtmlFormElement) -> js_sys::Map;
|
||||||
|
}
|
67
packages/web/src/events/keyboard.rs
Normal file
67
packages/web/src/events/keyboard.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use dioxus_html::{
|
||||||
|
input_data::decode_key_location,
|
||||||
|
prelude::{Code, Key, Location, Modifiers, ModifiersInteraction},
|
||||||
|
HasKeyboardData,
|
||||||
|
};
|
||||||
|
use web_sys::KeyboardEvent;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasKeyboardData for Synthetic<KeyboardEvent> {
|
||||||
|
fn key(&self) -> Key {
|
||||||
|
Key::from_str(self.event.key().as_str()).unwrap_or(Key::Unidentified)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn code(&self) -> Code {
|
||||||
|
Code::from_str(self.event.code().as_str()).unwrap_or(Code::Unidentified)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn location(&self) -> Location {
|
||||||
|
decode_key_location(self.event.location() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_auto_repeating(&self) -> bool {
|
||||||
|
self.event.repeat()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_composing(&self) -> bool {
|
||||||
|
self.event.is_composing()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModifiersInteraction for Synthetic<KeyboardEvent> {
|
||||||
|
fn modifiers(&self) -> Modifiers {
|
||||||
|
let mut modifiers = Modifiers::empty();
|
||||||
|
|
||||||
|
if self.event.alt_key() {
|
||||||
|
modifiers.insert(Modifiers::ALT);
|
||||||
|
}
|
||||||
|
if self.event.ctrl_key() {
|
||||||
|
modifiers.insert(Modifiers::CONTROL);
|
||||||
|
}
|
||||||
|
if self.event.meta_key() {
|
||||||
|
modifiers.insert(Modifiers::META);
|
||||||
|
}
|
||||||
|
if self.event.shift_key() {
|
||||||
|
modifiers.insert(Modifiers::SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::KeyboardData {
|
||||||
|
type WebEvent = web_sys::KeyboardEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::KeyboardEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::KeyboardEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
37
packages/web/src/events/load.rs
Normal file
37
packages/web/src/events/load.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
use dioxus_html::HasImageData;
|
||||||
|
use web_sys::Event;
|
||||||
|
|
||||||
|
use super::WebEventExt;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct WebImageEvent {
|
||||||
|
raw: Event,
|
||||||
|
error: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebImageEvent {
|
||||||
|
pub fn new(raw: Event, error: bool) -> Self {
|
||||||
|
Self { raw, error }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasImageData for WebImageEvent {
|
||||||
|
fn load_error(&self) -> bool {
|
||||||
|
self.error
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
&self.raw as &dyn Any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::ImageData {
|
||||||
|
type WebEvent = Event;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Event> {
|
||||||
|
self.downcast::<WebImageEvent>().map(|e| e.raw.clone())
|
||||||
|
}
|
||||||
|
}
|
19
packages/web/src/events/media.rs
Normal file
19
packages/web/src/events/media.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use dioxus_html::HasMediaData;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasMediaData for Synthetic<web_sys::Event> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::MediaData {
|
||||||
|
type WebEvent = web_sys::Event;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::Event>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
278
packages/web/src/events/mod.rs
Normal file
278
packages/web/src/events/mod.rs
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
use dioxus_html::{
|
||||||
|
DragData, FormData, HtmlEventConverter, ImageData, MountedData, PlatformEventData,
|
||||||
|
};
|
||||||
|
use drag::WebDragData;
|
||||||
|
use form::WebFormData;
|
||||||
|
use load::WebImageEvent;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use web_sys::{Document, Element, Event};
|
||||||
|
|
||||||
|
mod animation;
|
||||||
|
mod clipboard;
|
||||||
|
mod composition;
|
||||||
|
mod drag;
|
||||||
|
mod file;
|
||||||
|
mod focus;
|
||||||
|
mod form;
|
||||||
|
mod keyboard;
|
||||||
|
mod load;
|
||||||
|
mod media;
|
||||||
|
#[cfg(feature = "mounted")]
|
||||||
|
mod mounted;
|
||||||
|
mod mouse;
|
||||||
|
mod pointer;
|
||||||
|
mod resize;
|
||||||
|
mod selection;
|
||||||
|
mod toggle;
|
||||||
|
mod touch;
|
||||||
|
mod transition;
|
||||||
|
mod wheel;
|
||||||
|
|
||||||
|
/// A wrapper for the websys event that allows us to give it the impls from dioxus-html
|
||||||
|
pub(crate) struct Synthetic<T: 'static> {
|
||||||
|
/// The inner web sys event that the synthetic event wraps
|
||||||
|
pub event: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Synthetic<T> {
|
||||||
|
/// Create a new synthetic event from a web sys event
|
||||||
|
pub fn new(event: T) -> Self {
|
||||||
|
Self { event }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct WebEventConverter;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn downcast_event(event: &dioxus_html::PlatformEventData) -> &GenericWebSysEvent {
|
||||||
|
event
|
||||||
|
.downcast::<GenericWebSysEvent>()
|
||||||
|
.expect("event should be a GenericWebSysEvent")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HtmlEventConverter for WebEventConverter {
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_animation_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::AnimationData {
|
||||||
|
Synthetic::<web_sys::AnimationEvent>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_clipboard_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::ClipboardData {
|
||||||
|
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_composition_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::CompositionData {
|
||||||
|
Synthetic::<web_sys::CompositionEvent>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData {
|
||||||
|
let event = downcast_event(event);
|
||||||
|
DragData::new(WebDragData::new(event.raw.clone().unchecked_into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_focus_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FocusData {
|
||||||
|
Synthetic::<web_sys::FocusEvent>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_form_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FormData {
|
||||||
|
let event = downcast_event(event);
|
||||||
|
FormData::new(WebFormData::new(event.element.clone(), event.raw.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_image_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::ImageData {
|
||||||
|
let event = downcast_event(event);
|
||||||
|
let error = event.raw.type_() == "error";
|
||||||
|
ImageData::new(WebImageEvent::new(event.raw.clone(), error))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_keyboard_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::KeyboardData {
|
||||||
|
Synthetic::<web_sys::KeyboardEvent>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_media_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MediaData {
|
||||||
|
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_mounted_data(&self, event: &dioxus_html::PlatformEventData) -> MountedData {
|
||||||
|
#[cfg(feature = "mounted")]
|
||||||
|
{
|
||||||
|
Synthetic::new(
|
||||||
|
event
|
||||||
|
.downcast::<web_sys::Element>()
|
||||||
|
.expect("event should be a web_sys::Element")
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "mounted"))]
|
||||||
|
{
|
||||||
|
panic!("mounted events are not supported without the mounted feature on the dioxus-web crate enabled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_mouse_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MouseData {
|
||||||
|
Synthetic::<web_sys::MouseEvent>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_pointer_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::PointerData {
|
||||||
|
Synthetic::<web_sys::PointerEvent>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_resize_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::ResizeData {
|
||||||
|
Synthetic::<web_sys::ResizeObserverEntry>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_scroll_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::ScrollData {
|
||||||
|
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_selection_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::SelectionData {
|
||||||
|
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_toggle_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::ToggleData {
|
||||||
|
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_touch_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::TouchData {
|
||||||
|
Synthetic::<web_sys::TouchEvent>::from(downcast_event(event).raw.clone()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn convert_transition_data(
|
||||||
|
&self,
|
||||||
|
event: &dioxus_html::PlatformEventData,
|
||||||
|
) -> dioxus_html::TransitionData {
|
||||||
|
Synthetic::<web_sys::TransitionEvent>::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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A extension trait for web-sys events that provides a way to get the event as a web-sys event.
|
||||||
|
pub trait WebEventExt {
|
||||||
|
/// The web specific event type
|
||||||
|
type WebEvent;
|
||||||
|
|
||||||
|
/// Try to downcast this event as a `web-sys` event.
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent>;
|
||||||
|
|
||||||
|
/// Downcast this event as a `web-sys` event.
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_web_event(&self) -> Self::WebEvent
|
||||||
|
where
|
||||||
|
Self::WebEvent: 'static,
|
||||||
|
{
|
||||||
|
self.try_as_web_event().unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"Error downcasting to `web-sys`, event should be a {}.",
|
||||||
|
std::any::type_name::<Self::WebEvent>()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GenericWebSysEvent {
|
||||||
|
raw: Event,
|
||||||
|
element: Element,
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: some of these events are being casted to the wrong event type.
|
||||||
|
// We need tests that simulate clicks/etc and make sure every event type works.
|
||||||
|
pub(crate) fn virtual_event_from_websys_event(
|
||||||
|
event: web_sys::Event,
|
||||||
|
target: Element,
|
||||||
|
) -> PlatformEventData {
|
||||||
|
PlatformEventData::new(Box::new(GenericWebSysEvent {
|
||||||
|
raw: event,
|
||||||
|
element: target,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn load_document() -> Document {
|
||||||
|
web_sys::window()
|
||||||
|
.expect("should have access to the Window")
|
||||||
|
.document()
|
||||||
|
.expect("should have access to the Document")
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! uncheck_convert {
|
||||||
|
($t:ty) => {
|
||||||
|
impl From<Event> for Synthetic<$t> {
|
||||||
|
#[inline]
|
||||||
|
fn from(e: Event) -> Self {
|
||||||
|
let e: $t = e.unchecked_into();
|
||||||
|
Self::new(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Event> for Synthetic<$t> {
|
||||||
|
#[inline]
|
||||||
|
fn from(e: &Event) -> Self {
|
||||||
|
let e: &$t = e.unchecked_ref();
|
||||||
|
Self::new(e.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($($t:ty),+ $(,)?) => {
|
||||||
|
$(uncheck_convert!($t);)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
uncheck_convert![
|
||||||
|
web_sys::CompositionEvent,
|
||||||
|
web_sys::KeyboardEvent,
|
||||||
|
web_sys::TouchEvent,
|
||||||
|
web_sys::PointerEvent,
|
||||||
|
web_sys::WheelEvent,
|
||||||
|
web_sys::AnimationEvent,
|
||||||
|
web_sys::TransitionEvent,
|
||||||
|
web_sys::MouseEvent,
|
||||||
|
web_sys::FocusEvent,
|
||||||
|
];
|
126
packages/web/src/events/mounted.rs
Normal file
126
packages/web/src/events/mounted.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
use dioxus_html::{
|
||||||
|
geometry::euclid::{Point2D, Size2D},
|
||||||
|
MountedData,
|
||||||
|
};
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl dioxus_html::RenderedElementBacking for Synthetic<web_sys::Element> {
|
||||||
|
fn get_scroll_offset(
|
||||||
|
&self,
|
||||||
|
) -> std::pin::Pin<
|
||||||
|
Box<
|
||||||
|
dyn std::future::Future<
|
||||||
|
Output = dioxus_html::MountedResult<dioxus_html::geometry::PixelsVector2D>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
let left = self.event.scroll_left();
|
||||||
|
let top = self.event.scroll_top();
|
||||||
|
let result = Ok(dioxus_html::geometry::PixelsVector2D::new(
|
||||||
|
left as f64,
|
||||||
|
top as f64,
|
||||||
|
));
|
||||||
|
Box::pin(async { result })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scroll_size(
|
||||||
|
&self,
|
||||||
|
) -> std::pin::Pin<
|
||||||
|
Box<
|
||||||
|
dyn std::future::Future<
|
||||||
|
Output = dioxus_html::MountedResult<dioxus_html::geometry::PixelsSize>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
let width = self.event.scroll_width();
|
||||||
|
let height = self.event.scroll_height();
|
||||||
|
let result = Ok(dioxus_html::geometry::PixelsSize::new(
|
||||||
|
width as f64,
|
||||||
|
height as f64,
|
||||||
|
));
|
||||||
|
Box::pin(async { result })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_client_rect(
|
||||||
|
&self,
|
||||||
|
) -> std::pin::Pin<
|
||||||
|
Box<
|
||||||
|
dyn std::future::Future<
|
||||||
|
Output = dioxus_html::MountedResult<dioxus_html::geometry::PixelsRect>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
let rect = self.event.get_bounding_client_rect();
|
||||||
|
let result = Ok(dioxus_html::geometry::PixelsRect::new(
|
||||||
|
Point2D::new(rect.left(), rect.top()),
|
||||||
|
Size2D::new(rect.width(), rect.height()),
|
||||||
|
));
|
||||||
|
Box::pin(async { result })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scroll_to(
|
||||||
|
&self,
|
||||||
|
behavior: dioxus_html::ScrollBehavior,
|
||||||
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = dioxus_html::MountedResult<()>>>> {
|
||||||
|
let options = web_sys::ScrollIntoViewOptions::new();
|
||||||
|
match behavior {
|
||||||
|
dioxus_html::ScrollBehavior::Instant => {
|
||||||
|
options.set_behavior(web_sys::ScrollBehavior::Instant);
|
||||||
|
}
|
||||||
|
dioxus_html::ScrollBehavior::Smooth => {
|
||||||
|
options.set_behavior(web_sys::ScrollBehavior::Smooth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.event
|
||||||
|
.scroll_into_view_with_scroll_into_view_options(&options);
|
||||||
|
|
||||||
|
Box::pin(async { Ok(()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_focus(
|
||||||
|
&self,
|
||||||
|
focus: bool,
|
||||||
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = dioxus_html::MountedResult<()>>>> {
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct FocusError(wasm_bindgen::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 {}
|
||||||
|
|
||||||
|
let result = self
|
||||||
|
.event
|
||||||
|
.dyn_ref::<web_sys::HtmlElement>()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
dioxus_html::MountedError::OperationFailed(Box::new(FocusError(
|
||||||
|
self.event.clone().into(),
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
.and_then(|e| {
|
||||||
|
(if focus { e.focus() } else { e.blur() }).map_err(|err| {
|
||||||
|
dioxus_html::MountedError::OperationFailed(Box::new(FocusError(err)))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
Box::pin(async { result })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for MountedData {
|
||||||
|
type WebEvent = web_sys::Element;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::Element> {
|
||||||
|
self.downcast::<Synthetic<web_sys::Element>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
87
packages/web/src/events/mouse.rs
Normal file
87
packages/web/src/events/mouse.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
use dioxus_html::{
|
||||||
|
geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint},
|
||||||
|
input_data::{decode_mouse_button_set, MouseButton},
|
||||||
|
prelude::{
|
||||||
|
InteractionElementOffset, InteractionLocation, Modifiers, ModifiersInteraction,
|
||||||
|
PointerInteraction,
|
||||||
|
},
|
||||||
|
HasDragData, HasFileData, HasMouseData,
|
||||||
|
};
|
||||||
|
use web_sys::MouseEvent;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl InteractionLocation for Synthetic<MouseEvent> {
|
||||||
|
fn client_coordinates(&self) -> ClientPoint {
|
||||||
|
ClientPoint::new(self.event.client_x().into(), self.event.client_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_coordinates(&self) -> PagePoint {
|
||||||
|
PagePoint::new(self.event.page_x().into(), self.event.page_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_coordinates(&self) -> ScreenPoint {
|
||||||
|
ScreenPoint::new(self.event.screen_x().into(), self.event.screen_y().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionElementOffset for Synthetic<MouseEvent> {
|
||||||
|
fn element_coordinates(&self) -> ElementPoint {
|
||||||
|
ElementPoint::new(self.event.offset_x().into(), self.event.offset_y().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModifiersInteraction for Synthetic<MouseEvent> {
|
||||||
|
fn modifiers(&self) -> Modifiers {
|
||||||
|
let mut modifiers = Modifiers::empty();
|
||||||
|
|
||||||
|
if self.event.alt_key() {
|
||||||
|
modifiers.insert(Modifiers::ALT);
|
||||||
|
}
|
||||||
|
if self.event.ctrl_key() {
|
||||||
|
modifiers.insert(Modifiers::CONTROL);
|
||||||
|
}
|
||||||
|
if self.event.meta_key() {
|
||||||
|
modifiers.insert(Modifiers::META);
|
||||||
|
}
|
||||||
|
if self.event.shift_key() {
|
||||||
|
modifiers.insert(Modifiers::SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerInteraction for Synthetic<MouseEvent> {
|
||||||
|
fn held_buttons(&self) -> dioxus_html::input_data::MouseButtonSet {
|
||||||
|
decode_mouse_button_set(self.event.buttons())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_button(&self) -> Option<MouseButton> {
|
||||||
|
Some(MouseButton::from_web_code(self.event.button()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasMouseData for Synthetic<MouseEvent> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasFileData for Synthetic<MouseEvent> {}
|
||||||
|
|
||||||
|
impl HasDragData for Synthetic<MouseEvent> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::MouseData {
|
||||||
|
type WebEvent = web_sys::MouseEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::MouseEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::MouseEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
119
packages/web/src/events/pointer.rs
Normal file
119
packages/web/src/events/pointer.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
use dioxus_html::{
|
||||||
|
geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint},
|
||||||
|
input_data::{decode_mouse_button_set, MouseButton},
|
||||||
|
prelude::{
|
||||||
|
InteractionElementOffset, InteractionLocation, Modifiers, ModifiersInteraction,
|
||||||
|
PointerInteraction,
|
||||||
|
},
|
||||||
|
HasPointerData,
|
||||||
|
};
|
||||||
|
use web_sys::PointerEvent;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasPointerData for Synthetic<PointerEvent> {
|
||||||
|
fn pointer_id(&self) -> i32 {
|
||||||
|
self.event.pointer_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> i32 {
|
||||||
|
self.event.width()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> i32 {
|
||||||
|
self.event.height()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pressure(&self) -> f32 {
|
||||||
|
self.event.pressure()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tangential_pressure(&self) -> f32 {
|
||||||
|
self.event.tangential_pressure()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tilt_x(&self) -> i32 {
|
||||||
|
self.event.tilt_x()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tilt_y(&self) -> i32 {
|
||||||
|
self.event.tilt_y()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn twist(&self) -> i32 {
|
||||||
|
self.event.twist()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pointer_type(&self) -> String {
|
||||||
|
self.event.pointer_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_primary(&self) -> bool {
|
||||||
|
self.event.is_primary()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionLocation for Synthetic<PointerEvent> {
|
||||||
|
fn client_coordinates(&self) -> ClientPoint {
|
||||||
|
ClientPoint::new(self.event.client_x().into(), self.event.client_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_coordinates(&self) -> ScreenPoint {
|
||||||
|
ScreenPoint::new(self.event.screen_x().into(), self.event.screen_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_coordinates(&self) -> PagePoint {
|
||||||
|
PagePoint::new(self.event.page_x().into(), self.event.page_y().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionElementOffset for Synthetic<PointerEvent> {
|
||||||
|
fn element_coordinates(&self) -> ElementPoint {
|
||||||
|
ElementPoint::new(self.event.offset_x().into(), self.event.offset_y().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModifiersInteraction for Synthetic<PointerEvent> {
|
||||||
|
fn modifiers(&self) -> Modifiers {
|
||||||
|
let mut modifiers = Modifiers::empty();
|
||||||
|
|
||||||
|
if self.event.alt_key() {
|
||||||
|
modifiers.insert(Modifiers::ALT);
|
||||||
|
}
|
||||||
|
if self.event.ctrl_key() {
|
||||||
|
modifiers.insert(Modifiers::CONTROL);
|
||||||
|
}
|
||||||
|
if self.event.meta_key() {
|
||||||
|
modifiers.insert(Modifiers::META);
|
||||||
|
}
|
||||||
|
if self.event.shift_key() {
|
||||||
|
modifiers.insert(Modifiers::SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerInteraction for Synthetic<PointerEvent> {
|
||||||
|
fn held_buttons(&self) -> dioxus_html::input_data::MouseButtonSet {
|
||||||
|
decode_mouse_button_set(self.event.buttons())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_button(&self) -> Option<MouseButton> {
|
||||||
|
Some(MouseButton::from_web_code(self.event.button()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::PointerData {
|
||||||
|
type WebEvent = web_sys::PointerEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::PointerEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::PointerEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
57
packages/web/src/events/resize.rs
Normal file
57
packages/web/src/events/resize.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use dioxus_html::{geometry::PixelsSize, HasResizeData, ResizeResult};
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use web_sys::{CustomEvent, Event, ResizeObserverEntry};
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl From<Event> for Synthetic<ResizeObserverEntry> {
|
||||||
|
#[inline]
|
||||||
|
fn from(e: Event) -> Self {
|
||||||
|
<Synthetic<ResizeObserverEntry> as From<&Event>>::from(&e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Event> for Synthetic<ResizeObserverEntry> {
|
||||||
|
#[inline]
|
||||||
|
fn from(e: &Event) -> Self {
|
||||||
|
let e: &CustomEvent = e.unchecked_ref();
|
||||||
|
let value = e.detail();
|
||||||
|
Self::new(value.unchecked_into::<ResizeObserverEntry>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasResizeData for Synthetic<ResizeObserverEntry> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_border_box_size(&self) -> ResizeResult<PixelsSize> {
|
||||||
|
extract_first_size(self.event.border_box_size())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_content_box_size(&self) -> ResizeResult<PixelsSize> {
|
||||||
|
extract_first_size(self.event.content_box_size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::ResizeData {
|
||||||
|
type WebEvent = web_sys::ResizeObserverEntry;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::ResizeObserverEntry> {
|
||||||
|
self.downcast::<Synthetic<web_sys::ResizeObserverEntry>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_first_size(resize_observer_output: js_sys::Array) -> ResizeResult<PixelsSize> {
|
||||||
|
let first = resize_observer_output.get(0);
|
||||||
|
let size = first.unchecked_into::<web_sys::ResizeObserverSize>();
|
||||||
|
|
||||||
|
// inline_size matches the width of the element if its writing-mode is horizontal, the height otherwise
|
||||||
|
let inline_size = size.inline_size();
|
||||||
|
// block_size matches the height of the element if its writing-mode is horizontal, the width otherwise
|
||||||
|
let block_size = size.block_size();
|
||||||
|
|
||||||
|
Ok(PixelsSize::new(inline_size, block_size))
|
||||||
|
}
|
19
packages/web/src/events/selection.rs
Normal file
19
packages/web/src/events/selection.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use dioxus_html::HasSelectionData;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasSelectionData for Synthetic<web_sys::Event> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::SelectionData {
|
||||||
|
type WebEvent = web_sys::Event;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::Event>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
19
packages/web/src/events/toggle.rs
Normal file
19
packages/web/src/events/toggle.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use dioxus_html::HasToggleData;
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasToggleData for Synthetic<web_sys::Event> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::ToggleData {
|
||||||
|
type WebEvent = web_sys::Event;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::Event>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
111
packages/web/src/events/touch.rs
Normal file
111
packages/web/src/events/touch.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
use dioxus_html::{
|
||||||
|
geometry::{ClientPoint, PagePoint, ScreenPoint},
|
||||||
|
prelude::{InteractionLocation, Modifiers, ModifiersInteraction},
|
||||||
|
HasTouchPointData, TouchPoint,
|
||||||
|
};
|
||||||
|
use web_sys::{Touch, TouchEvent};
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl ModifiersInteraction for Synthetic<TouchEvent> {
|
||||||
|
fn modifiers(&self) -> Modifiers {
|
||||||
|
let mut modifiers = Modifiers::empty();
|
||||||
|
|
||||||
|
if self.event.alt_key() {
|
||||||
|
modifiers.insert(Modifiers::ALT);
|
||||||
|
}
|
||||||
|
if self.event.ctrl_key() {
|
||||||
|
modifiers.insert(Modifiers::CONTROL);
|
||||||
|
}
|
||||||
|
if self.event.meta_key() {
|
||||||
|
modifiers.insert(Modifiers::META);
|
||||||
|
}
|
||||||
|
if self.event.shift_key() {
|
||||||
|
modifiers.insert(Modifiers::SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dioxus_html::events::HasTouchData for Synthetic<TouchEvent> {
|
||||||
|
fn touches(&self) -> Vec<TouchPoint> {
|
||||||
|
let touches = TouchEvent::touches(&self.event);
|
||||||
|
let mut result = Vec::with_capacity(touches.length() as usize);
|
||||||
|
for i in 0..touches.length() {
|
||||||
|
let touch = touches.get(i).unwrap();
|
||||||
|
result.push(TouchPoint::new(Synthetic::new(touch)));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn touches_changed(&self) -> Vec<TouchPoint> {
|
||||||
|
let touches = self.event.changed_touches();
|
||||||
|
let mut result = Vec::with_capacity(touches.length() as usize);
|
||||||
|
for i in 0..touches.length() {
|
||||||
|
let touch = touches.get(i).unwrap();
|
||||||
|
result.push(TouchPoint::new(Synthetic::new(touch)));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_touches(&self) -> Vec<TouchPoint> {
|
||||||
|
let touches = self.event.target_touches();
|
||||||
|
let mut result = Vec::with_capacity(touches.length() as usize);
|
||||||
|
for i in 0..touches.length() {
|
||||||
|
let touch = touches.get(i).unwrap();
|
||||||
|
result.push(TouchPoint::new(Synthetic::new(touch)));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasTouchPointData for Synthetic<Touch> {
|
||||||
|
fn identifier(&self) -> i32 {
|
||||||
|
self.event.identifier()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn radius(&self) -> ScreenPoint {
|
||||||
|
ScreenPoint::new(self.event.radius_x().into(), self.event.radius_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotation(&self) -> f64 {
|
||||||
|
self.event.rotation_angle() as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn force(&self) -> f64 {
|
||||||
|
self.event.force() as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionLocation for Synthetic<Touch> {
|
||||||
|
fn client_coordinates(&self) -> ClientPoint {
|
||||||
|
ClientPoint::new(self.event.client_x().into(), self.event.client_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_coordinates(&self) -> ScreenPoint {
|
||||||
|
ScreenPoint::new(self.event.screen_x().into(), self.event.screen_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_coordinates(&self) -> PagePoint {
|
||||||
|
PagePoint::new(self.event.page_x().into(), self.event.page_y().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::TouchData {
|
||||||
|
type WebEvent = web_sys::TouchEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<web_sys::TouchEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::TouchEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
22
packages/web/src/events/transition.rs
Normal file
22
packages/web/src/events/transition.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use dioxus_html::HasTransitionData;
|
||||||
|
use web_sys::TransitionEvent;
|
||||||
|
|
||||||
|
use super::Synthetic;
|
||||||
|
|
||||||
|
impl HasTransitionData for Synthetic<TransitionEvent> {
|
||||||
|
fn elapsed_time(&self) -> f32 {
|
||||||
|
self.event.elapsed_time()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn property_name(&self) -> String {
|
||||||
|
self.event.property_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pseudo_element(&self) -> String {
|
||||||
|
self.event.pseudo_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
110
packages/web/src/events/wheel.rs
Normal file
110
packages/web/src/events/wheel.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
use dioxus_html::{
|
||||||
|
geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint},
|
||||||
|
input_data::{decode_mouse_button_set, MouseButton},
|
||||||
|
prelude::{
|
||||||
|
InteractionElementOffset, InteractionLocation, Modifiers, ModifiersInteraction,
|
||||||
|
PointerInteraction,
|
||||||
|
},
|
||||||
|
HasMouseData, HasScrollData, HasWheelData,
|
||||||
|
};
|
||||||
|
use web_sys::{Event, WheelEvent};
|
||||||
|
|
||||||
|
use super::{Synthetic, WebEventExt};
|
||||||
|
|
||||||
|
impl HasWheelData for Synthetic<WheelEvent> {
|
||||||
|
fn delta(&self) -> dioxus_html::geometry::WheelDelta {
|
||||||
|
dioxus_html::geometry::WheelDelta::from_web_attributes(
|
||||||
|
self.event.delta_mode(),
|
||||||
|
self.event.delta_x(),
|
||||||
|
self.event.delta_y(),
|
||||||
|
self.event.delta_z(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasMouseData for Synthetic<WheelEvent> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionLocation for Synthetic<WheelEvent> {
|
||||||
|
fn client_coordinates(&self) -> ClientPoint {
|
||||||
|
ClientPoint::new(self.event.client_x().into(), self.event.client_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_coordinates(&self) -> ScreenPoint {
|
||||||
|
ScreenPoint::new(self.event.screen_x().into(), self.event.screen_y().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_coordinates(&self) -> PagePoint {
|
||||||
|
PagePoint::new(self.event.page_x().into(), self.event.page_y().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractionElementOffset for Synthetic<WheelEvent> {
|
||||||
|
fn element_coordinates(&self) -> ElementPoint {
|
||||||
|
ElementPoint::new(self.event.offset_x().into(), self.event.offset_y().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModifiersInteraction for Synthetic<WheelEvent> {
|
||||||
|
fn modifiers(&self) -> Modifiers {
|
||||||
|
let mut modifiers = Modifiers::empty();
|
||||||
|
|
||||||
|
if self.event.alt_key() {
|
||||||
|
modifiers.insert(Modifiers::ALT);
|
||||||
|
}
|
||||||
|
if self.event.ctrl_key() {
|
||||||
|
modifiers.insert(Modifiers::CONTROL);
|
||||||
|
}
|
||||||
|
if self.event.meta_key() {
|
||||||
|
modifiers.insert(Modifiers::META);
|
||||||
|
}
|
||||||
|
if self.event.shift_key() {
|
||||||
|
modifiers.insert(Modifiers::SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerInteraction for Synthetic<WheelEvent> {
|
||||||
|
fn held_buttons(&self) -> dioxus_html::input_data::MouseButtonSet {
|
||||||
|
decode_mouse_button_set(self.event.buttons())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_button(&self) -> Option<MouseButton> {
|
||||||
|
Some(MouseButton::from_web_code(self.event.button()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasScrollData for Synthetic<Event> {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::ScrollData {
|
||||||
|
type WebEvent = web_sys::Event;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::Event>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebEventExt for dioxus_html::WheelData {
|
||||||
|
type WebEvent = web_sys::WheelEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn try_as_web_event(&self) -> Option<Self::WebEvent> {
|
||||||
|
self.downcast::<Synthetic<web_sys::WheelEvent>>()
|
||||||
|
.map(|e| e.event.clone())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use crate::FileEngine;
|
use dioxus_html::FileEngine;
|
||||||
use futures_channel::oneshot;
|
use futures_channel::oneshot;
|
||||||
use js_sys::Uint8Array;
|
use js_sys::Uint8Array;
|
||||||
use wasm_bindgen::{prelude::Closure, JsCast};
|
use wasm_bindgen::{prelude::Closure, JsCast};
|
|
@ -1 +1 @@
|
||||||
class Channel{pending;waiting;constructor(){this.pending=[],this.waiting=[]}send(data){if(this.waiting.length>0){this.waiting.shift()(data);return}this.pending.push(data)}async recv(){return new Promise((resolve,_reject)=>{if(this.pending.length>0){resolve(this.pending.shift());return}this.waiting.push(resolve)})}}class WeakDioxusChannel{inner;constructor(channel){this.inner=new WeakRef(channel)}rustSend(data){let channel=this.inner.deref();if(channel)channel.rustSend(data)}async rustRecv(){let channel=this.inner.deref();if(channel)return await channel.rustRecv()}}class DioxusChannel{weak(){return new WeakDioxusChannel(this)}}class WebDioxusChannel extends DioxusChannel{js_to_rust;rust_to_js;owner;constructor(owner){super();this.owner=owner,this.js_to_rust=new Channel,this.rust_to_js=new Channel}weak(){return new WeakDioxusChannel(this)}async recv(){return await this.rust_to_js.recv()}send(data){this.js_to_rust.send(data)}rustSend(data){this.rust_to_js.send(data)}async rustRecv(){return await this.js_to_rust.recv()}}export{WebDioxusChannel,WeakDioxusChannel,DioxusChannel,Channel};
|
class Channel{pending;waiting;constructor(){this.pending=[],this.waiting=[]}send(data){if(this.waiting.length>0){this.waiting.shift()(data);return}this.pending.push(data)}async recv(){return new Promise((resolve,_reject)=>{if(this.pending.length>0){resolve(this.pending.shift());return}this.waiting.push(resolve)})}}class WeakDioxusChannel{inner;constructor(channel){this.inner=new WeakRef(channel)}rustSend(data){let channel=this.inner.deref();if(channel)channel.rustSend(data)}async rustRecv(){let channel=this.inner.deref();if(channel)return await channel.rustRecv()}}class DioxusChannel{weak(){return new WeakDioxusChannel(this)}}class WebDioxusChannel extends DioxusChannel{js_to_rust;rust_to_js;owner;constructor(owner){super();this.owner=owner,this.js_to_rust=new Channel,this.rust_to_js=new Channel}weak(){return new WeakDioxusChannel(this)}async recv(){return await this.rust_to_js.recv()}send(data){this.js_to_rust.send(data)}rustSend(data){this.rust_to_js.send(data)}async rustRecv(){return await this.js_to_rust.recv()}}export{WebDioxusChannel};
|
1
packages/web/src/js/hash.txt
Normal file
1
packages/web/src/js/hash.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[3479327739946104450]
|
|
@ -29,15 +29,19 @@ use futures_util::{pin_mut, select, FutureExt, StreamExt};
|
||||||
mod cfg;
|
mod cfg;
|
||||||
mod dom;
|
mod dom;
|
||||||
|
|
||||||
mod event;
|
mod events;
|
||||||
pub mod launch;
|
pub mod launch;
|
||||||
mod mutations;
|
mod mutations;
|
||||||
pub use event::*;
|
pub use events::*;
|
||||||
|
|
||||||
#[cfg(feature = "document")]
|
#[cfg(feature = "document")]
|
||||||
mod document;
|
mod document;
|
||||||
|
#[cfg(feature = "file_engine")]
|
||||||
|
mod file_engine;
|
||||||
#[cfg(feature = "document")]
|
#[cfg(feature = "document")]
|
||||||
pub use document::WebDocument;
|
pub use document::WebDocument;
|
||||||
|
#[cfg(feature = "file_engine")]
|
||||||
|
pub use file_engine::*;
|
||||||
|
|
||||||
#[cfg(all(feature = "devtools", debug_assertions))]
|
#[cfg(all(feature = "devtools", debug_assertions))]
|
||||||
mod devtools;
|
mod devtools;
|
||||||
|
|
43
packages/web/src/ts/eval.ts
Normal file
43
packages/web/src/ts/eval.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import {
|
||||||
|
DioxusChannel,
|
||||||
|
Channel,
|
||||||
|
WeakDioxusChannel,
|
||||||
|
} from "../../../html/src/ts/eval";
|
||||||
|
|
||||||
|
export class WebDioxusChannel extends DioxusChannel {
|
||||||
|
js_to_rust: Channel;
|
||||||
|
rust_to_js: Channel;
|
||||||
|
owner: any;
|
||||||
|
|
||||||
|
constructor(owner: any) {
|
||||||
|
super();
|
||||||
|
this.owner = owner;
|
||||||
|
this.js_to_rust = new Channel();
|
||||||
|
this.rust_to_js = new Channel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a weak reference to this channel
|
||||||
|
weak(): WeakDioxusChannel {
|
||||||
|
return new WeakDioxusChannel(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive message from Rust
|
||||||
|
async recv() {
|
||||||
|
return await this.rust_to_js.recv();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send message to rust.
|
||||||
|
send(data: any) {
|
||||||
|
this.js_to_rust.send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data from rust to javascript
|
||||||
|
rustSend(data: any) {
|
||||||
|
this.rust_to_js.send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive data sent from javascript in rust
|
||||||
|
async rustRecv(): Promise<any> {
|
||||||
|
return await this.js_to_rust.recv();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue