chore: clean up desktop
This commit is contained in:
1 parent
67a6fa9eb8
commit
1b14b309e9
19 files changed
+305
-298
No files matched your search
+10
-22
@@ -25,6 +25,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
if val.get() == "0" {
|
if val.get() == "0" {
|
||||||
val.set(String::new());
|
val.set(String::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
val.make_mut().push_str(num.to_string().as_str());
|
val.make_mut().push_str(num.to_string().as_str());
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,12 +100,8 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
div { class: "digit-keys",
|
div { class: "digit-keys",
|
||||||
button { class: "calculator-key key-0", onclick: move |_| input_digit(0),
|
button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" }
|
||||||
"0"
|
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'), "●" }
|
||||||
}
|
|
||||||
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'),
|
|
||||||
"●"
|
|
||||||
}
|
|
||||||
(1..10).map(|k| rsx!{
|
(1..10).map(|k| rsx!{
|
||||||
button {
|
button {
|
||||||
class: "calculator-key {k}",
|
class: "calculator-key {k}",
|
||||||
@@ -116,22 +113,13 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
div { class: "operator-keys",
|
div { class: "operator-keys",
|
||||||
button { class: "calculator-key key-divide", onclick: move |_| input_operator("/"),
|
button { class: "calculator-key key-divide", onclick: move |_| input_operator("/"), "÷" }
|
||||||
"÷"
|
button { class: "calculator-key key-multiply", onclick: move |_| input_operator("*"), "×" }
|
||||||
}
|
button { class: "calculator-key key-subtract", onclick: move |_| input_operator("-"), "−" }
|
||||||
button { class: "calculator-key key-multiply", onclick: move |_| input_operator("*"),
|
button { class: "calculator-key key-add", onclick: move |_| input_operator("+"), "+" }
|
||||||
"×"
|
button {
|
||||||
}
|
class: "calculator-key key-equals",
|
||||||
button { class: "calculator-key key-subtract", onclick: move |_| input_operator("-"),
|
onclick: move |_| val.set(format!("{}", calc_val(val.as_str()))),
|
||||||
"−"
|
|
||||||
}
|
|
||||||
button { class: "calculator-key key-add", onclick: move |_| input_operator("+"),
|
|
||||||
"+"
|
|
||||||
}
|
|
||||||
button { class: "calculator-key key-equals",
|
|
||||||
onclick: move |_| {
|
|
||||||
val.set(format!("{}", calc_val(val.as_str())));
|
|
||||||
},
|
|
||||||
"="
|
"="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
let login = use_callback!(cx, || move |evt: MouseEvent| async move {
|
let login = use_callback!(cx, move |_| async move {
|
||||||
let res = reqwest::get("https://dog.ceo/api/breeds/list/all")
|
let res = reqwest::get("https://dog.ceo/api/breeds/list/all")
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -13,7 +13,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
println!("{}, ", res);
|
println!("{:#?}, ", res);
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
button {
|
button {
|
||||||
onclick: move |evt| {
|
onclick: move |evt| {
|
||||||
println!("clicked! bottom no bubbling");
|
println!("clicked! bottom no bubbling");
|
||||||
evt.cancel_bubble();
|
evt.stop_propogation();
|
||||||
},
|
},
|
||||||
"Dont propogate"
|
"Dont propogate"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use dioxus_ssr::config::SsrConfig;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut vdom = VirtualDom::new(example);
|
let mut vdom = VirtualDom::new(example);
|
||||||
vdom.rebuild();
|
_ = vdom.rebuild();
|
||||||
|
|
||||||
let out = dioxus_ssr::render_vdom_cfg(&vdom, SsrConfig::default().newline(true).indent(true));
|
let out = dioxus_ssr::render_vdom_cfg(&vdom, SsrConfig::default().newline(true).indent(true));
|
||||||
println!("{}", out);
|
println!("{}", out);
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
use dioxus::prelude::*;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
dioxus_desktop::launch(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
|
||||||
let mut idx = use_state(cx, || 0);
|
|
||||||
let onhover = |h| println!("go!");
|
|
||||||
|
|
||||||
cx.render(rsx! {
|
|
||||||
div {
|
|
||||||
button { onclick: move |_| idx += 1, "+" }
|
|
||||||
button { onclick: move |_| idx -= 1, "-" }
|
|
||||||
ul {
|
|
||||||
(0..**idx).map(|i| rsx! {
|
|
||||||
Child { i: i, onhover: onhover }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline_props]
|
|
||||||
fn Child<'a>(cx: Scope<'a>, i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element {
|
|
||||||
cx.render(rsx! {
|
|
||||||
li {
|
|
||||||
onmouseover: move |e| onhover.call(e),
|
|
||||||
"{i}"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
use dioxus::prelude::*;
|
|
||||||
use dioxus_desktop::{Config, LogicalSize, WindowBuilder};
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
dioxus_desktop::launch(|cx| cx.render(rsx! { async_app {} }));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn async_app(cx: Scope<'_>) -> Element {
|
|
||||||
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
|
||||||
|
|
||||||
cx.render(rsx! {
|
|
||||||
div {
|
|
||||||
"hi!"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -35,13 +35,13 @@ fn app(cx: Scope) -> Element {
|
|||||||
nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center" }
|
nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center" }
|
||||||
button {
|
button {
|
||||||
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
|
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
|
||||||
onmousedown: |evt| evt.cancel_bubble(),
|
onmousedown: |evt| evt.stop_propogation(),
|
||||||
onclick: move |_| window.set_minimized(true),
|
onclick: move |_| window.set_minimized(true),
|
||||||
"Minimize"
|
"Minimize"
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
|
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
|
||||||
onmousedown: |evt| evt.cancel_bubble(),
|
onmousedown: |evt| evt.stop_propogation(),
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
|
|
||||||
window.set_fullscreen(!**fullscreen);
|
window.set_fullscreen(!**fullscreen);
|
||||||
@@ -52,7 +52,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
|
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
|
||||||
onmousedown: |evt| evt.cancel_bubble(),
|
onmousedown: |evt| evt.stop_propogation(),
|
||||||
onclick: move |_| window.close(),
|
onclick: move |_| window.close(),
|
||||||
"Close"
|
"Close"
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
div {
|
div {
|
||||||
button {
|
button {
|
||||||
class: "inline-flex items-center text-white bg-green-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
|
class: "inline-flex items-center text-white bg-green-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
|
||||||
onmousedown: |evt| evt.cancel_bubble(),
|
onmousedown: |evt| evt.stop_propogation(),
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
window.set_always_on_top(!always_on_top);
|
window.set_always_on_top(!always_on_top);
|
||||||
always_on_top.set(!always_on_top);
|
always_on_top.set(!always_on_top);
|
||||||
@@ -77,7 +77,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
div {
|
div {
|
||||||
button {
|
button {
|
||||||
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
|
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
|
||||||
onmousedown: |evt| evt.cancel_bubble(),
|
onmousedown: |evt| evt.stop_propogation(),
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
window.set_decorations(!decorations);
|
window.set_decorations(!decorations);
|
||||||
decorations.set(!decorations);
|
decorations.set(!decorations);
|
||||||
@@ -88,7 +88,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
div {
|
div {
|
||||||
button {
|
button {
|
||||||
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
|
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
|
||||||
onmousedown: |evt| evt.cancel_bubble(),
|
onmousedown: |evt| evt.stop_propogation(),
|
||||||
onclick: move |_| window.set_title("Dioxus Application"),
|
onclick: move |_| window.set_title("Dioxus Application"),
|
||||||
"Change Title"
|
"Change Title"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,15 +159,24 @@ pub enum TemplateNode<'a> {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// This template node is just a piece of static text
|
/// This template node is just a piece of static text
|
||||||
Text { text: &'a str },
|
Text {
|
||||||
|
/// The actual text
|
||||||
|
text: &'a str,
|
||||||
|
},
|
||||||
|
|
||||||
/// This template node is unknown, and needs to be created at runtime.
|
/// This template node is unknown, and needs to be created at runtime.
|
||||||
Dynamic { id: usize },
|
Dynamic {
|
||||||
|
/// The index of the dynamic node in the VNode's dynamic_nodes list
|
||||||
|
id: usize,
|
||||||
|
},
|
||||||
|
|
||||||
/// This template node is known to be some text, but needs to be created at runtime
|
/// This template node is known to be some text, but needs to be created at runtime
|
||||||
///
|
///
|
||||||
/// This is separate from the pure Dynamic variant for various optimizations
|
/// This is separate from the pure Dynamic variant for various optimizations
|
||||||
DynamicText { id: usize },
|
DynamicText {
|
||||||
|
/// The index of the dynamic node in the VNode's dynamic_nodes list
|
||||||
|
id: usize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node created at runtime
|
/// A node created at runtime
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ webbrowser = "0.8.0"
|
|||||||
infer = "0.11.0"
|
infer = "0.11.0"
|
||||||
dunce = "1.0.2"
|
dunce = "1.0.2"
|
||||||
|
|
||||||
interprocess = { version = "1.1.1" }
|
interprocess = { version = "1.1.1", optional = true}
|
||||||
futures-util = "0.3.25"
|
futures-util = "0.3.25"
|
||||||
|
|
||||||
[target.'cfg(target_os = "ios")'.dependencies]
|
[target.'cfg(target_os = "ios")'.dependencies]
|
||||||
@@ -44,11 +44,12 @@ objc_id = "0.1.1"
|
|||||||
core-foundation = "0.9.3"
|
core-foundation = "0.9.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["tokio_runtime"]
|
default = ["tokio_runtime", "hot-reload"]
|
||||||
tokio_runtime = ["tokio"]
|
tokio_runtime = ["tokio"]
|
||||||
fullscreen = ["wry/fullscreen"]
|
fullscreen = ["wry/fullscreen"]
|
||||||
transparent = ["wry/transparent"]
|
transparent = ["wry/transparent"]
|
||||||
tray = ["wry/tray"]
|
tray = ["wry/tray"]
|
||||||
|
hot-reload = ["interprocess"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dioxus-core-macro = { path = "../core-macro" }
|
dioxus-core-macro = { path = "../core-macro" }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::desktop_context::{DesktopContext, UserWindowEvent};
|
use crate::desktop_context::{DesktopContext, UserWindowEvent};
|
||||||
use crate::events::{decode_event, EventMessage};
|
use crate::events::{decode_event, EventMessage};
|
||||||
use dioxus_core::*;
|
use dioxus_core::*;
|
||||||
use futures_channel::mpsc::UnboundedReceiver;
|
use futures_channel::mpsc::{unbounded, UnboundedSender};
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
@@ -22,6 +22,9 @@ pub(super) struct DesktopController {
|
|||||||
pub(super) pending_edits: Arc<Mutex<Vec<String>>>,
|
pub(super) pending_edits: Arc<Mutex<Vec<String>>>,
|
||||||
pub(super) quit_app_on_close: bool,
|
pub(super) quit_app_on_close: bool,
|
||||||
pub(super) is_ready: Arc<AtomicBool>,
|
pub(super) is_ready: Arc<AtomicBool>,
|
||||||
|
pub(super) proxy: EventLoopProxy<UserWindowEvent>,
|
||||||
|
pub(super) event_tx: UnboundedSender<serde_json::Value>,
|
||||||
|
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
pub(super) views: Vec<*mut Object>,
|
pub(super) views: Vec<*mut Object>,
|
||||||
}
|
}
|
||||||
@@ -33,9 +36,10 @@ impl DesktopController {
|
|||||||
root: Component<P>,
|
root: Component<P>,
|
||||||
props: P,
|
props: P,
|
||||||
proxy: EventLoopProxy<UserWindowEvent>,
|
proxy: EventLoopProxy<UserWindowEvent>,
|
||||||
mut event_rx: UnboundedReceiver<serde_json::Value>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let edit_queue = Arc::new(Mutex::new(Vec::new()));
|
let edit_queue = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
let (event_tx, mut event_rx) = unbounded();
|
||||||
|
let proxy2 = proxy.clone();
|
||||||
|
|
||||||
let pending_edits = edit_queue.clone();
|
let pending_edits = edit_queue.clone();
|
||||||
let desktop_context_proxy = proxy.clone();
|
let desktop_context_proxy = proxy.clone();
|
||||||
@@ -87,6 +91,8 @@ impl DesktopController {
|
|||||||
webviews: HashMap::new(),
|
webviews: HashMap::new(),
|
||||||
is_ready: Arc::new(AtomicBool::new(false)),
|
is_ready: Arc::new(AtomicBool::new(false)),
|
||||||
quit_app_on_close: true,
|
quit_app_on_close: true,
|
||||||
|
proxy: proxy2,
|
||||||
|
event_tx,
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
views: vec![],
|
views: vec![],
|
||||||
}
|
}
|
||||||
@@ -117,4 +123,8 @@ impl DesktopController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_template(&self, serialized_template: String) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -168,6 +168,11 @@ pub enum UserWindowEvent {
|
|||||||
DragWindow,
|
DragWindow,
|
||||||
FocusWindow,
|
FocusWindow,
|
||||||
|
|
||||||
|
/// Set a new Dioxus template for hot-reloading
|
||||||
|
///
|
||||||
|
/// Is a no-op in release builds. Must fit the right format for templates
|
||||||
|
SetTemplate(String),
|
||||||
|
|
||||||
Visible(bool),
|
Visible(bool),
|
||||||
Minimize(bool),
|
Minimize(bool),
|
||||||
Maximize(bool),
|
Maximize(bool),
|
||||||
@@ -195,97 +200,101 @@ pub enum UserWindowEvent {
|
|||||||
PopView,
|
PopView,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn handler(
|
impl DesktopController {
|
||||||
user_event: UserWindowEvent,
|
pub(super) fn handle_event(
|
||||||
desktop: &mut DesktopController,
|
&mut self,
|
||||||
control_flow: &mut ControlFlow,
|
user_event: UserWindowEvent,
|
||||||
) {
|
control_flow: &mut ControlFlow,
|
||||||
// currently dioxus-desktop supports a single window only,
|
) {
|
||||||
// so we can grab the only webview from the map;
|
// currently dioxus-desktop supports a single window only,
|
||||||
// on wayland it is possible that a user event is emitted
|
// so we can grab the only webview from the map;
|
||||||
// before the webview is initialized. ignore the event.
|
// on wayland it is possible that a user event is emitted
|
||||||
let webview = if let Some(webview) = desktop.webviews.values().next() {
|
// before the webview is initialized. ignore the event.
|
||||||
webview
|
let webview = if let Some(webview) = self.webviews.values().next() {
|
||||||
} else {
|
webview
|
||||||
return;
|
} else {
|
||||||
};
|
return;
|
||||||
let window = webview.window();
|
};
|
||||||
|
|
||||||
match user_event {
|
let window = webview.window();
|
||||||
Initialize | EditsReady => desktop.try_load_ready_webviews(),
|
|
||||||
CloseWindow => *control_flow = ControlFlow::Exit,
|
match user_event {
|
||||||
DragWindow => {
|
Initialize | EditsReady => self.try_load_ready_webviews(),
|
||||||
// if the drag_window has any errors, we don't do anything
|
SetTemplate(template) => self.set_template(template),
|
||||||
window.fullscreen().is_none().then(|| window.drag_window());
|
CloseWindow => *control_flow = ControlFlow::Exit,
|
||||||
}
|
DragWindow => {
|
||||||
Visible(state) => window.set_visible(state),
|
// if the drag_window has any errors, we don't do anything
|
||||||
Minimize(state) => window.set_minimized(state),
|
window.fullscreen().is_none().then(|| window.drag_window());
|
||||||
Maximize(state) => window.set_maximized(state),
|
|
||||||
MaximizeToggle => window.set_maximized(!window.is_maximized()),
|
|
||||||
Fullscreen(state) => {
|
|
||||||
if let Some(handle) = window.current_monitor() {
|
|
||||||
window.set_fullscreen(state.then_some(WryFullscreen::Borderless(Some(handle))));
|
|
||||||
}
|
}
|
||||||
}
|
Visible(state) => window.set_visible(state),
|
||||||
FocusWindow => window.set_focus(),
|
Minimize(state) => window.set_minimized(state),
|
||||||
Resizable(state) => window.set_resizable(state),
|
Maximize(state) => window.set_maximized(state),
|
||||||
AlwaysOnTop(state) => window.set_always_on_top(state),
|
MaximizeToggle => window.set_maximized(!window.is_maximized()),
|
||||||
|
Fullscreen(state) => {
|
||||||
CursorVisible(state) => window.set_cursor_visible(state),
|
if let Some(handle) = window.current_monitor() {
|
||||||
CursorGrab(state) => {
|
window.set_fullscreen(state.then_some(WryFullscreen::Borderless(Some(handle))));
|
||||||
let _ = window.set_cursor_grab(state);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SetTitle(content) => window.set_title(&content),
|
|
||||||
SetDecorations(state) => window.set_decorations(state),
|
|
||||||
|
|
||||||
SetZoomLevel(scale_factor) => webview.zoom(scale_factor),
|
|
||||||
|
|
||||||
Print => {
|
|
||||||
if let Err(e) = webview.print() {
|
|
||||||
// we can't panic this error.
|
|
||||||
log::warn!("Open print modal failed: {e}");
|
|
||||||
}
|
}
|
||||||
}
|
FocusWindow => window.set_focus(),
|
||||||
DevTool => {
|
Resizable(state) => window.set_resizable(state),
|
||||||
#[cfg(debug_assertions)]
|
AlwaysOnTop(state) => window.set_always_on_top(state),
|
||||||
webview.open_devtools();
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
log::warn!("Devtools are disabled in release builds");
|
|
||||||
}
|
|
||||||
|
|
||||||
Eval(code) => {
|
CursorVisible(state) => window.set_cursor_visible(state),
|
||||||
if let Err(e) = webview.evaluate_script(code.as_str()) {
|
CursorGrab(state) => {
|
||||||
// we can't panic this error.
|
let _ = window.set_cursor_grab(state);
|
||||||
log::warn!("Eval script error: {e}");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "ios")]
|
SetTitle(content) => window.set_title(&content),
|
||||||
PushView(view) => unsafe {
|
SetDecorations(state) => window.set_decorations(state),
|
||||||
use objc::runtime::Object;
|
|
||||||
use objc::*;
|
|
||||||
assert!(is_main_thread());
|
|
||||||
let ui_view = window.ui_view() as *mut Object;
|
|
||||||
let ui_view_frame: *mut Object = msg_send![ui_view, frame];
|
|
||||||
let _: () = msg_send![view, setFrame: ui_view_frame];
|
|
||||||
let _: () = msg_send![view, setAutoresizingMask: 31];
|
|
||||||
|
|
||||||
let ui_view_controller = window.ui_view_controller() as *mut Object;
|
SetZoomLevel(scale_factor) => webview.zoom(scale_factor),
|
||||||
let _: () = msg_send![ui_view_controller, setView: view];
|
|
||||||
desktop.views.push(ui_view);
|
Print => {
|
||||||
},
|
if let Err(e) = webview.print() {
|
||||||
|
// we can't panic this error.
|
||||||
|
log::warn!("Open print modal failed: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DevTool => {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
webview.open_devtools();
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
log::warn!("Devtools are disabled in release builds");
|
||||||
|
}
|
||||||
|
|
||||||
|
Eval(code) => {
|
||||||
|
if let Err(e) = webview.evaluate_script(code.as_str()) {
|
||||||
|
// we can't panic this error.
|
||||||
|
log::warn!("Eval script error: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
PushView(view) => unsafe {
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc::*;
|
||||||
|
assert!(is_main_thread());
|
||||||
|
let ui_view = window.ui_view() as *mut Object;
|
||||||
|
let ui_view_frame: *mut Object = msg_send![ui_view, frame];
|
||||||
|
let _: () = msg_send![view, setFrame: ui_view_frame];
|
||||||
|
let _: () = msg_send![view, setAutoresizingMask: 31];
|
||||||
|
|
||||||
#[cfg(target_os = "ios")]
|
|
||||||
PopView => unsafe {
|
|
||||||
use objc::runtime::Object;
|
|
||||||
use objc::*;
|
|
||||||
assert!(is_main_thread());
|
|
||||||
if let Some(view) = desktop.views.pop() {
|
|
||||||
let ui_view_controller = window.ui_view_controller() as *mut Object;
|
let ui_view_controller = window.ui_view_controller() as *mut Object;
|
||||||
let _: () = msg_send![ui_view_controller, setView: view];
|
let _: () = msg_send![ui_view_controller, setView: view];
|
||||||
}
|
desktop.views.push(ui_view);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[cfg(target_os = "ios")]
|
||||||
|
PopView => unsafe {
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc::*;
|
||||||
|
assert!(is_main_thread());
|
||||||
|
if let Some(view) = desktop.views.pop() {
|
||||||
|
let ui_view_controller = window.ui_view_controller() as *mut Object;
|
||||||
|
let _: () = msg_send![ui_view_controller, setView: view];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,31 @@
|
|||||||
use dioxus_core::VirtualDom;
|
use dioxus_core::VirtualDom;
|
||||||
use interprocess::local_socket::LocalSocketStream;
|
|
||||||
// use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
|
use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{sync::Arc, sync::Mutex};
|
use std::{sync::Arc, sync::Mutex};
|
||||||
|
|
||||||
fn _handle_error(connection: std::io::Result<LocalSocketStream>) -> Option<LocalSocketStream> {
|
fn handle_error(connection: std::io::Result<LocalSocketStream>) -> Option<LocalSocketStream> {
|
||||||
connection
|
connection
|
||||||
.map_err(|error| eprintln!("Incoming connection failed: {}", error))
|
.map_err(|error| eprintln!("Incoming connection failed: {}", error))
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn _init(_dom: &VirtualDom) {
|
pub(crate) fn init(_dom: &VirtualDom) {
|
||||||
let latest_in_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
|
let latest_in_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
|
||||||
Arc::new(Mutex::new(None));
|
Arc::new(Mutex::new(None));
|
||||||
let _latest_in_connection_handle = latest_in_connection.clone();
|
|
||||||
|
let latest_in_connection_handle = latest_in_connection.clone();
|
||||||
|
|
||||||
// connect to processes for incoming data
|
// connect to processes for incoming data
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
// if let Ok(listener) = LocalSocketListener::bind("@dioxusin") {
|
let temp_file = std::env::temp_dir().join("@dioxusin");
|
||||||
// for conn in listener.incoming().filter_map(handle_error) {
|
|
||||||
// *latest_in_connection_handle.lock().unwrap() = Some(BufReader::new(conn));
|
if let Ok(listener) = LocalSocketListener::bind(temp_file) {
|
||||||
// }
|
for conn in listener.incoming().filter_map(handle_error) {
|
||||||
// }
|
*latest_in_connection_handle.lock().unwrap() = Some(BufReader::new(conn));
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
|
|||||||
+125
-111
@@ -8,13 +8,17 @@ mod controller;
|
|||||||
mod desktop_context;
|
mod desktop_context;
|
||||||
mod escape;
|
mod escape;
|
||||||
mod events;
|
mod events;
|
||||||
#[cfg(any(feature = "hot-reload", debug_assertions))]
|
|
||||||
mod hot_reload;
|
|
||||||
mod protocol;
|
mod protocol;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "hot-reload", debug_assertions))]
|
||||||
|
mod hot_reload;
|
||||||
|
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use desktop_context::UserWindowEvent;
|
use desktop_context::UserWindowEvent;
|
||||||
pub use desktop_context::{use_eval, use_window, DesktopContext};
|
pub use desktop_context::{use_eval, use_window, DesktopContext};
|
||||||
use futures_channel::mpsc::unbounded;
|
use futures_channel::mpsc::UnboundedSender;
|
||||||
pub use wry;
|
pub use wry;
|
||||||
pub use wry::application as tao;
|
pub use wry::application as tao;
|
||||||
|
|
||||||
@@ -100,15 +104,68 @@ pub fn launch_cfg(root: Component, config_builder: Config) {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cfg: Config) {
|
pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cfg: Config) {
|
||||||
let event_loop = EventLoop::with_user_event();
|
let event_loop = EventLoop::with_user_event();
|
||||||
|
let mut desktop = DesktopController::new_on_tokio(root, props, event_loop.create_proxy());
|
||||||
|
|
||||||
let (event_tx, event_rx) = unbounded();
|
event_loop.run(move |window_event, event_loop, control_flow| {
|
||||||
let mut desktop =
|
*control_flow = ControlFlow::Wait;
|
||||||
DesktopController::new_on_tokio(root, props, event_loop.create_proxy(), event_rx);
|
|
||||||
let proxy = event_loop.create_proxy();
|
|
||||||
|
|
||||||
// We assume that if the icon is None, then the user just didnt set it
|
match window_event {
|
||||||
|
Event::NewEvents(StartCause::Init) => desktop.start(&mut cfg, event_loop),
|
||||||
|
|
||||||
|
Event::WindowEvent {
|
||||||
|
event, window_id, ..
|
||||||
|
} => match event {
|
||||||
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
|
WindowEvent::Destroyed { .. } => desktop.close_window(window_id, control_flow),
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
|
||||||
|
Event::UserEvent(user_event) => desktop.handle_event(user_event, control_flow),
|
||||||
|
Event::MainEventsCleared => {}
|
||||||
|
Event::Resumed => {}
|
||||||
|
Event::Suspended => {}
|
||||||
|
Event::LoopDestroyed => {}
|
||||||
|
Event::RedrawRequested(_id) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DesktopController {
|
||||||
|
fn start(
|
||||||
|
&mut self,
|
||||||
|
cfg: &mut Config,
|
||||||
|
event_loop: &tao::event_loop::EventLoopWindowTarget<UserWindowEvent>,
|
||||||
|
) {
|
||||||
|
let webview = build_webview(
|
||||||
|
cfg,
|
||||||
|
event_loop,
|
||||||
|
self.is_ready.clone(),
|
||||||
|
self.proxy.clone(),
|
||||||
|
self.event_tx.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.webviews.insert(webview.window().id(), webview);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_webview(
|
||||||
|
cfg: &mut Config,
|
||||||
|
event_loop: &tao::event_loop::EventLoopWindowTarget<UserWindowEvent>,
|
||||||
|
is_ready: Arc<AtomicBool>,
|
||||||
|
proxy: tao::event_loop::EventLoopProxy<UserWindowEvent>,
|
||||||
|
event_tx: UnboundedSender<serde_json::Value>,
|
||||||
|
) -> wry::webview::WebView {
|
||||||
|
let builder = cfg.window.clone();
|
||||||
|
let window = builder.build(event_loop).unwrap();
|
||||||
|
let file_handler = cfg.file_drop_handler.take();
|
||||||
|
let custom_head = cfg.custom_head.clone();
|
||||||
|
let resource_dir = cfg.resource_dir.clone();
|
||||||
|
let index_file = cfg.custom_index.clone();
|
||||||
|
|
||||||
|
// We assume that if the icon is None in cfg, then the user just didnt set it
|
||||||
if cfg.window.window.window_icon.is_none() {
|
if cfg.window.window.window_icon.is_none() {
|
||||||
cfg.window = cfg.window.with_window_icon(Some(
|
window.set_window_icon(Some(
|
||||||
tao::window::Icon::from_rgba(
|
tao::window::Icon::from_rgba(
|
||||||
include_bytes!("./assets/default_icon.bin").to_vec(),
|
include_bytes!("./assets/default_icon.bin").to_vec(),
|
||||||
460,
|
460,
|
||||||
@@ -118,84 +175,62 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
event_loop.run(move |window_event, event_loop, control_flow| {
|
let mut webview = WebViewBuilder::new(window)
|
||||||
*control_flow = ControlFlow::Wait;
|
.unwrap()
|
||||||
|
.with_transparent(cfg.window.window.transparent)
|
||||||
// println!("window event: {:?}", window_event);
|
.with_url("dioxus://index.html/")
|
||||||
match window_event {
|
.unwrap()
|
||||||
Event::NewEvents(StartCause::Init) => {
|
.with_ipc_handler(move |_window: &Window, payload: String| {
|
||||||
let builder = cfg.window.clone();
|
parse_ipc_message(&payload)
|
||||||
|
.map(|message| match message.method() {
|
||||||
let window = builder.build(event_loop).unwrap();
|
"user_event" => {
|
||||||
let window_id = window.id();
|
_ = event_tx.unbounded_send(message.params());
|
||||||
|
}
|
||||||
let (is_ready, _) = (desktop.is_ready.clone(), ());
|
"initialize" => {
|
||||||
// let (is_ready, sender) = (desktop.is_ready.clone(), desktop.sender.clone());
|
is_ready.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
let _ = proxy.send_event(UserWindowEvent::EditsReady);
|
||||||
let proxy = proxy.clone();
|
}
|
||||||
|
"browser_open" => {
|
||||||
let file_handler = cfg.file_drop_handler.take();
|
let data = message.params();
|
||||||
let custom_head = cfg.custom_head.clone();
|
log::trace!("Open browser: {:?}", data);
|
||||||
let resource_dir = cfg.resource_dir.clone();
|
if let Some(temp) = data.as_object() {
|
||||||
let index_file = cfg.custom_index.clone();
|
if temp.contains_key("href") {
|
||||||
let event_tx = event_tx.clone();
|
let url = temp.get("href").unwrap().as_str().unwrap();
|
||||||
|
if let Err(e) = webbrowser::open(url) {
|
||||||
let mut webview = WebViewBuilder::new(window)
|
log::error!("Open Browser error: {:?}", e);
|
||||||
.unwrap()
|
|
||||||
.with_transparent(cfg.window.window.transparent)
|
|
||||||
.with_url("dioxus://index.html/")
|
|
||||||
.unwrap()
|
|
||||||
.with_ipc_handler(move |_window: &Window, payload: String| {
|
|
||||||
parse_ipc_message(&payload)
|
|
||||||
.map(|message| match message.method() {
|
|
||||||
"user_event" => {
|
|
||||||
_ = event_tx.unbounded_send(message.params());
|
|
||||||
}
|
}
|
||||||
"initialize" => {
|
}
|
||||||
is_ready.store(true, std::sync::atomic::Ordering::Relaxed);
|
}
|
||||||
let _ = proxy.send_event(UserWindowEvent::EditsReady);
|
}
|
||||||
}
|
_ => (),
|
||||||
"browser_open" => {
|
})
|
||||||
let data = message.params();
|
.unwrap_or_else(|| {
|
||||||
log::trace!("Open browser: {:?}", data);
|
log::warn!("invalid IPC message received");
|
||||||
if let Some(temp) = data.as_object() {
|
});
|
||||||
if temp.contains_key("href") {
|
})
|
||||||
let url = temp.get("href").unwrap().as_str().unwrap();
|
.with_custom_protocol(String::from("dioxus"), move |r| {
|
||||||
if let Err(e) = webbrowser::open(url) {
|
protocol::desktop_handler(
|
||||||
log::error!("Open Browser error: {:?}", e);
|
r,
|
||||||
}
|
resource_dir.clone(),
|
||||||
}
|
custom_head.clone(),
|
||||||
}
|
index_file.clone(),
|
||||||
}
|
)
|
||||||
_ => (),
|
})
|
||||||
})
|
.with_file_drop_handler(move |window, evet| {
|
||||||
.unwrap_or_else(|| {
|
file_handler
|
||||||
log::warn!("invalid IPC message received");
|
.as_ref()
|
||||||
});
|
.map(|handler| handler(window, evet))
|
||||||
})
|
.unwrap_or_default()
|
||||||
.with_custom_protocol(String::from("dioxus"), move |r| {
|
});
|
||||||
protocol::desktop_handler(
|
|
||||||
r,
|
|
||||||
resource_dir.clone(),
|
|
||||||
custom_head.clone(),
|
|
||||||
index_file.clone(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.with_file_drop_handler(move |window, evet| {
|
|
||||||
file_handler
|
|
||||||
.as_ref()
|
|
||||||
.map(|handler| handler(window, evet))
|
|
||||||
.unwrap_or_default()
|
|
||||||
});
|
|
||||||
|
|
||||||
for (name, handler) in cfg.protocols.drain(..) {
|
for (name, handler) in cfg.protocols.drain(..) {
|
||||||
webview = webview.with_custom_protocol(name, handler)
|
webview = webview.with_custom_protocol(name, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.disable_context_menu {
|
if cfg.disable_context_menu {
|
||||||
// in release mode, we don't want to show the dev tool or reload menus
|
// in release mode, we don't want to show the dev tool or reload menus
|
||||||
webview = webview.with_initialization_script(
|
webview = webview.with_initialization_script(
|
||||||
r#"
|
r#"
|
||||||
if (document.addEventListener) {
|
if (document.addEventListener) {
|
||||||
document.addEventListener('contextmenu', function(e) {
|
document.addEventListener('contextmenu', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -206,32 +241,11 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// in debug, we are okay with the reload menu showing and dev tool
|
// in debug, we are okay with the reload menu showing and dev tool
|
||||||
webview = webview.with_devtools(true);
|
webview = webview.with_devtools(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
desktop.webviews.insert(window_id, webview.build().unwrap());
|
webview.build().unwrap()
|
||||||
}
|
|
||||||
|
|
||||||
Event::WindowEvent {
|
|
||||||
event, window_id, ..
|
|
||||||
} => match event {
|
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
|
||||||
WindowEvent::Destroyed { .. } => desktop.close_window(window_id, control_flow),
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
|
|
||||||
Event::UserEvent(user_event) => {
|
|
||||||
desktop_context::handler(user_event, &mut desktop, control_flow)
|
|
||||||
}
|
|
||||||
Event::MainEventsCleared => {}
|
|
||||||
Event::Resumed => {}
|
|
||||||
Event::Suspended => {}
|
|
||||||
Event::LoopDestroyed => {}
|
|
||||||
Event::RedrawRequested(_id) => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,12 @@ macro_rules! use_callback {
|
|||||||
move || $($rest)*
|
move || $($rest)*
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
($cx:ident, $($rest:tt)*) => {
|
||||||
|
use_callback(
|
||||||
|
$cx,
|
||||||
|
move || $($rest)*
|
||||||
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
pub fn use_callback<'a, T, R, F>(cx: &'a ScopeState, make: impl FnOnce() -> R) -> impl FnMut(T) + 'a
|
pub fn use_callback<'a, T, R, F>(cx: &'a ScopeState, make: impl FnOnce() -> R) -> impl FnMut(T) + 'a
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ extern "C" {
|
|||||||
#[wasm_bindgen(method)]
|
#[wasm_bindgen(method)]
|
||||||
pub fn MountToRoot(this: &Interpreter);
|
pub fn MountToRoot(this: &Interpreter);
|
||||||
|
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
pub fn AppendChildren(this: &Interpreter, m: u32);
|
||||||
|
|
||||||
#[wasm_bindgen(method)]
|
#[wasm_bindgen(method)]
|
||||||
pub fn AssignId(this: &Interpreter, path: &[u8], id: u32);
|
pub fn AssignId(this: &Interpreter, path: &[u8], id: u32);
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,6 @@ export class Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleEdits(edits) {
|
handleEdits(edits) {
|
||||||
|
|
||||||
for (let template of edits.templates) {
|
for (let template of edits.templates) {
|
||||||
this.SaveTemplate(template);
|
this.SaveTemplate(template);
|
||||||
}
|
}
|
||||||
@@ -276,7 +275,16 @@ export class Interpreter {
|
|||||||
}
|
}
|
||||||
HydrateText(path, value, id) {
|
HydrateText(path, value, id) {
|
||||||
let node = this.LoadChild(path);
|
let node = this.LoadChild(path);
|
||||||
node.textContent = value;
|
|
||||||
|
if (node.nodeType == Node.TEXT_NODE) {
|
||||||
|
node.textContent = value;
|
||||||
|
} else {
|
||||||
|
// replace with a textnode
|
||||||
|
let text = document.createTextNode(value);
|
||||||
|
node.replaceWith(text);
|
||||||
|
node = text;
|
||||||
|
}
|
||||||
|
|
||||||
this.nodes[id] = node;
|
this.nodes[id] = node;
|
||||||
}
|
}
|
||||||
ReplacePlaceholder(path, m) {
|
ReplacePlaceholder(path, m) {
|
||||||
|
|||||||
@@ -220,7 +220,12 @@ impl<S: State> RealDom<S> {
|
|||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let node = self.tree.get_mut(node_id).unwrap();
|
||||||
if let NodeType::Text { text } = &mut node.node_data.node_type {
|
if let NodeType::Text { text } = &mut node.node_data.node_type {
|
||||||
*text = value.to_string();
|
*text = value.to_string();
|
||||||
|
} else {
|
||||||
|
node.node_data.node_type = NodeType::Text {
|
||||||
|
text: value.to_string(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated);
|
mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated);
|
||||||
}
|
}
|
||||||
LoadTemplate { name, index, id } => {
|
LoadTemplate { name, index, id } => {
|
||||||
|
|||||||
@@ -14,15 +14,14 @@ use futures_channel::mpsc;
|
|||||||
use js_sys::Function;
|
use js_sys::Function;
|
||||||
use std::{any::Any, rc::Rc};
|
use std::{any::Any, rc::Rc};
|
||||||
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
|
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
|
||||||
use web_sys::{Document, Element, Event, HtmlElement};
|
use web_sys::{Document, Element, Event};
|
||||||
|
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
|
|
||||||
pub struct WebsysDom {
|
pub struct WebsysDom {
|
||||||
document: Document,
|
|
||||||
interpreter: Interpreter,
|
interpreter: Interpreter,
|
||||||
handler: Closure<dyn FnMut(&Event)>,
|
handler: Closure<dyn FnMut(&Event)>,
|
||||||
root: Element,
|
_root: Element,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebsysDom {
|
impl WebsysDom {
|
||||||
@@ -36,9 +35,8 @@ impl WebsysDom {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
document,
|
|
||||||
interpreter: Interpreter::new(root.clone()),
|
interpreter: Interpreter::new(root.clone()),
|
||||||
root,
|
_root: root,
|
||||||
handler: Closure::wrap(Box::new(move |event: &web_sys::Event| {
|
handler: Closure::wrap(Box::new(move |event: &web_sys::Event| {
|
||||||
let _ = event_channel.unbounded_send(event.clone());
|
let _ = event_channel.unbounded_send(event.clone());
|
||||||
})),
|
})),
|
||||||
@@ -63,7 +61,7 @@ impl WebsysDom {
|
|||||||
let i = &self.interpreter;
|
let i = &self.interpreter;
|
||||||
for edit in edits.drain(..) {
|
for edit in edits.drain(..) {
|
||||||
match edit {
|
match edit {
|
||||||
AppendChildren { id, m } => i.AppendChildren(id, m),
|
AppendChildren { id, m } => i.AppendChildren(m as u32),
|
||||||
AssignId { path, id } => i.AssignId(path, id.0 as u32),
|
AssignId { path, id } => i.AssignId(path, id.0 as u32),
|
||||||
CreatePlaceholder { id } => i.CreatePlaceholder(id.0 as u32),
|
CreatePlaceholder { id } => i.CreatePlaceholder(id.0 as u32),
|
||||||
CreateTextNode { value, id } => i.CreateTextNode(value.into(), id.0 as u32),
|
CreateTextNode { value, id } => i.CreateTextNode(value.into(), id.0 as u32),
|
||||||
@@ -87,8 +85,8 @@ impl WebsysDom {
|
|||||||
self.interpreter.NewEventListener(
|
self.interpreter.NewEventListener(
|
||||||
name,
|
name,
|
||||||
id.0 as u32,
|
id.0 as u32,
|
||||||
self.handler.as_ref().unchecked_ref(),
|
|
||||||
event_bubbles(&name[2..]),
|
event_bubbles(&name[2..]),
|
||||||
|
self.handler.as_ref().unchecked_ref(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
RemoveEventListener { name, id } => i.RemoveEventListener(name, id.0 as u32),
|
RemoveEventListener { name, id } => i.RemoveEventListener(name, id.0 as u32),
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
|
|||||||
let mut res = {
|
let mut res = {
|
||||||
let work = dom.wait_for_work().fuse();
|
let work = dom.wait_for_work().fuse();
|
||||||
pin_mut!(work);
|
pin_mut!(work);
|
||||||
|
|
||||||
futures_util::select! {
|
futures_util::select! {
|
||||||
_ = work => None,
|
_ = work => None,
|
||||||
new_template = hotreload_rx.next() => {
|
new_template = hotreload_rx.next() => {
|
||||||
|
|||||||
Reference in new issue
Block a user