mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
chore: clean up desktop
This commit is contained in:
parent
67a6fa9eb8
commit
1b14b309e9
19 changed files with 305 additions and 298 deletions
|
@ -25,6 +25,7 @@ fn app(cx: Scope) -> Element {
|
|||
if val.get() == "0" {
|
||||
val.set(String::new());
|
||||
}
|
||||
|
||||
val.make_mut().push_str(num.to_string().as_str());
|
||||
};
|
||||
|
||||
|
@ -99,12 +100,8 @@ fn app(cx: Scope) -> Element {
|
|||
}
|
||||
}
|
||||
div { class: "digit-keys",
|
||||
button { class: "calculator-key key-0", onclick: move |_| input_digit(0),
|
||||
"0"
|
||||
}
|
||||
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'),
|
||||
"●"
|
||||
}
|
||||
button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" }
|
||||
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'), "●" }
|
||||
(1..10).map(|k| rsx!{
|
||||
button {
|
||||
class: "calculator-key {k}",
|
||||
|
@ -116,22 +113,13 @@ fn app(cx: Scope) -> Element {
|
|||
}
|
||||
}
|
||||
div { class: "operator-keys",
|
||||
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-add", onclick: move |_| input_operator("+"),
|
||||
"+"
|
||||
}
|
||||
button { class: "calculator-key key-equals",
|
||||
onclick: move |_| {
|
||||
val.set(format!("{}", calc_val(val.as_str())));
|
||||
},
|
||||
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-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 {
|
||||
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")
|
||||
.await
|
||||
.unwrap()
|
||||
|
@ -13,7 +13,7 @@ fn app(cx: Scope) -> Element {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("{}, ", res);
|
||||
println!("{:#?}, ", res);
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
|
|
|
@ -22,7 +22,7 @@ fn app(cx: Scope) -> Element {
|
|||
button {
|
||||
onclick: move |evt| {
|
||||
println!("clicked! bottom no bubbling");
|
||||
evt.cancel_bubble();
|
||||
evt.stop_propogation();
|
||||
},
|
||||
"Dont propogate"
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use dioxus_ssr::config::SsrConfig;
|
|||
|
||||
fn main() {
|
||||
let mut vdom = VirtualDom::new(example);
|
||||
vdom.rebuild();
|
||||
_ = vdom.rebuild();
|
||||
|
||||
let out = dioxus_ssr::render_vdom_cfg(&vdom, SsrConfig::default().newline(true).indent(true));
|
||||
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" }
|
||||
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",
|
||||
onmousedown: |evt| evt.cancel_bubble(),
|
||||
onmousedown: |evt| evt.stop_propogation(),
|
||||
onclick: move |_| window.set_minimized(true),
|
||||
"Minimize"
|
||||
}
|
||||
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",
|
||||
onmousedown: |evt| evt.cancel_bubble(),
|
||||
onmousedown: |evt| evt.stop_propogation(),
|
||||
onclick: move |_| {
|
||||
|
||||
window.set_fullscreen(!**fullscreen);
|
||||
|
@ -52,7 +52,7 @@ fn app(cx: Scope) -> Element {
|
|||
}
|
||||
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",
|
||||
onmousedown: |evt| evt.cancel_bubble(),
|
||||
onmousedown: |evt| evt.stop_propogation(),
|
||||
onclick: move |_| window.close(),
|
||||
"Close"
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ fn app(cx: Scope) -> Element {
|
|||
div {
|
||||
button {
|
||||
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 |_| {
|
||||
window.set_always_on_top(!always_on_top);
|
||||
always_on_top.set(!always_on_top);
|
||||
|
@ -77,7 +77,7 @@ fn app(cx: Scope) -> Element {
|
|||
div {
|
||||
button {
|
||||
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_decorations(!decorations);
|
||||
decorations.set(!decorations);
|
||||
|
@ -88,7 +88,7 @@ fn app(cx: Scope) -> Element {
|
|||
div {
|
||||
button {
|
||||
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"),
|
||||
"Change Title"
|
||||
}
|
||||
|
|
|
@ -159,15 +159,24 @@ pub enum TemplateNode<'a> {
|
|||
},
|
||||
|
||||
/// 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.
|
||||
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 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
|
||||
|
|
|
@ -33,7 +33,7 @@ webbrowser = "0.8.0"
|
|||
infer = "0.11.0"
|
||||
dunce = "1.0.2"
|
||||
|
||||
interprocess = { version = "1.1.1" }
|
||||
interprocess = { version = "1.1.1", optional = true}
|
||||
futures-util = "0.3.25"
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
|
@ -44,11 +44,12 @@ objc_id = "0.1.1"
|
|||
core-foundation = "0.9.3"
|
||||
|
||||
[features]
|
||||
default = ["tokio_runtime"]
|
||||
default = ["tokio_runtime", "hot-reload"]
|
||||
tokio_runtime = ["tokio"]
|
||||
fullscreen = ["wry/fullscreen"]
|
||||
transparent = ["wry/transparent"]
|
||||
tray = ["wry/tray"]
|
||||
hot-reload = ["interprocess"]
|
||||
|
||||
[dev-dependencies]
|
||||
dioxus-core-macro = { path = "../core-macro" }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::desktop_context::{DesktopContext, UserWindowEvent};
|
||||
use crate::events::{decode_event, EventMessage};
|
||||
use dioxus_core::*;
|
||||
use futures_channel::mpsc::UnboundedReceiver;
|
||||
use futures_channel::mpsc::{unbounded, UnboundedSender};
|
||||
use futures_util::StreamExt;
|
||||
#[cfg(target_os = "ios")]
|
||||
use objc::runtime::Object;
|
||||
|
@ -22,6 +22,9 @@ pub(super) struct DesktopController {
|
|||
pub(super) pending_edits: Arc<Mutex<Vec<String>>>,
|
||||
pub(super) quit_app_on_close: bool,
|
||||
pub(super) is_ready: Arc<AtomicBool>,
|
||||
pub(super) proxy: EventLoopProxy<UserWindowEvent>,
|
||||
pub(super) event_tx: UnboundedSender<serde_json::Value>,
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
pub(super) views: Vec<*mut Object>,
|
||||
}
|
||||
|
@ -33,9 +36,10 @@ impl DesktopController {
|
|||
root: Component<P>,
|
||||
props: P,
|
||||
proxy: EventLoopProxy<UserWindowEvent>,
|
||||
mut event_rx: UnboundedReceiver<serde_json::Value>,
|
||||
) -> Self {
|
||||
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 desktop_context_proxy = proxy.clone();
|
||||
|
@ -87,6 +91,8 @@ impl DesktopController {
|
|||
webviews: HashMap::new(),
|
||||
is_ready: Arc::new(AtomicBool::new(false)),
|
||||
quit_app_on_close: true,
|
||||
proxy: proxy2,
|
||||
event_tx,
|
||||
#[cfg(target_os = "ios")]
|
||||
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,
|
||||
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),
|
||||
Minimize(bool),
|
||||
Maximize(bool),
|
||||
|
@ -195,24 +200,27 @@ pub enum UserWindowEvent {
|
|||
PopView,
|
||||
}
|
||||
|
||||
pub(super) fn handler(
|
||||
impl DesktopController {
|
||||
pub(super) fn handle_event(
|
||||
&mut self,
|
||||
user_event: UserWindowEvent,
|
||||
desktop: &mut DesktopController,
|
||||
control_flow: &mut ControlFlow,
|
||||
) {
|
||||
) {
|
||||
// currently dioxus-desktop supports a single window only,
|
||||
// so we can grab the only webview from the map;
|
||||
// on wayland it is possible that a user event is emitted
|
||||
// before the webview is initialized. ignore the event.
|
||||
let webview = if let Some(webview) = desktop.webviews.values().next() {
|
||||
let webview = if let Some(webview) = self.webviews.values().next() {
|
||||
webview
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let window = webview.window();
|
||||
|
||||
match user_event {
|
||||
Initialize | EditsReady => desktop.try_load_ready_webviews(),
|
||||
Initialize | EditsReady => self.try_load_ready_webviews(),
|
||||
SetTemplate(template) => self.set_template(template),
|
||||
CloseWindow => *control_flow = ControlFlow::Exit,
|
||||
DragWindow => {
|
||||
// if the drag_window has any errors, we don't do anything
|
||||
|
@ -287,6 +295,7 @@ pub(super) fn handler(
|
|||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
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::time::Duration;
|
||||
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
|
||||
.map_err(|error| eprintln!("Incoming connection failed: {}", error))
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub(crate) fn _init(_dom: &VirtualDom) {
|
||||
pub(crate) fn init(_dom: &VirtualDom) {
|
||||
let latest_in_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
|
||||
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
|
||||
std::thread::spawn(move || {
|
||||
// if let Ok(listener) = LocalSocketListener::bind("@dioxusin") {
|
||||
// for conn in listener.incoming().filter_map(handle_error) {
|
||||
// *latest_in_connection_handle.lock().unwrap() = Some(BufReader::new(conn));
|
||||
// }
|
||||
// }
|
||||
let temp_file = std::env::temp_dir().join("@dioxusin");
|
||||
|
||||
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 || {
|
||||
|
|
|
@ -8,13 +8,17 @@ mod controller;
|
|||
mod desktop_context;
|
||||
mod escape;
|
||||
mod events;
|
||||
#[cfg(any(feature = "hot-reload", debug_assertions))]
|
||||
mod hot_reload;
|
||||
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;
|
||||
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::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) {
|
||||
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();
|
||||
let mut desktop =
|
||||
DesktopController::new_on_tokio(root, props, event_loop.create_proxy(), event_rx);
|
||||
let proxy = event_loop.create_proxy();
|
||||
event_loop.run(move |window_event, event_loop, control_flow| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
// 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() {
|
||||
cfg.window = cfg.window.with_window_icon(Some(
|
||||
window.set_window_icon(Some(
|
||||
tao::window::Icon::from_rgba(
|
||||
include_bytes!("./assets/default_icon.bin").to_vec(),
|
||||
460,
|
||||
|
@ -118,28 +175,6 @@ 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| {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
// println!("window event: {:?}", window_event);
|
||||
match window_event {
|
||||
Event::NewEvents(StartCause::Init) => {
|
||||
let builder = cfg.window.clone();
|
||||
|
||||
let window = builder.build(event_loop).unwrap();
|
||||
let window_id = window.id();
|
||||
|
||||
let (is_ready, _) = (desktop.is_ready.clone(), ());
|
||||
// let (is_ready, sender) = (desktop.is_ready.clone(), desktop.sender.clone());
|
||||
|
||||
let proxy = proxy.clone();
|
||||
|
||||
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();
|
||||
let event_tx = event_tx.clone();
|
||||
|
||||
let mut webview = WebViewBuilder::new(window)
|
||||
.unwrap()
|
||||
.with_transparent(cfg.window.window.transparent)
|
||||
|
@ -212,26 +247,5 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
|
|||
webview = webview.with_devtools(true);
|
||||
}
|
||||
|
||||
desktop.webviews.insert(window_id, 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) => {}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
webview.build().unwrap()
|
||||
}
|
||||
|
|
|
@ -17,6 +17,12 @@ macro_rules! use_callback {
|
|||
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
|
||||
where
|
||||
|
|
|
@ -17,6 +17,9 @@ extern "C" {
|
|||
#[wasm_bindgen(method)]
|
||||
pub fn MountToRoot(this: &Interpreter);
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn AppendChildren(this: &Interpreter, m: u32);
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn AssignId(this: &Interpreter, path: &[u8], id: u32);
|
||||
|
||||
|
|
|
@ -210,7 +210,6 @@ export class Interpreter {
|
|||
}
|
||||
}
|
||||
handleEdits(edits) {
|
||||
|
||||
for (let template of edits.templates) {
|
||||
this.SaveTemplate(template);
|
||||
}
|
||||
|
@ -276,7 +275,16 @@ export class Interpreter {
|
|||
}
|
||||
HydrateText(path, value, id) {
|
||||
let node = this.LoadChild(path);
|
||||
|
||||
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;
|
||||
}
|
||||
ReplacePlaceholder(path, m) {
|
||||
|
|
|
@ -220,7 +220,12 @@ impl<S: State> RealDom<S> {
|
|||
let node = self.tree.get_mut(node_id).unwrap();
|
||||
if let NodeType::Text { text } = &mut node.node_data.node_type {
|
||||
*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);
|
||||
}
|
||||
LoadTemplate { name, index, id } => {
|
||||
|
|
|
@ -14,15 +14,14 @@ use futures_channel::mpsc;
|
|||
use js_sys::Function;
|
||||
use std::{any::Any, rc::Rc};
|
||||
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
|
||||
use web_sys::{Document, Element, Event, HtmlElement};
|
||||
use web_sys::{Document, Element, Event};
|
||||
|
||||
use crate::Config;
|
||||
|
||||
pub struct WebsysDom {
|
||||
document: Document,
|
||||
interpreter: Interpreter,
|
||||
handler: Closure<dyn FnMut(&Event)>,
|
||||
root: Element,
|
||||
_root: Element,
|
||||
}
|
||||
|
||||
impl WebsysDom {
|
||||
|
@ -36,9 +35,8 @@ impl WebsysDom {
|
|||
};
|
||||
|
||||
Self {
|
||||
document,
|
||||
interpreter: Interpreter::new(root.clone()),
|
||||
root,
|
||||
_root: root,
|
||||
handler: Closure::wrap(Box::new(move |event: &web_sys::Event| {
|
||||
let _ = event_channel.unbounded_send(event.clone());
|
||||
})),
|
||||
|
@ -63,7 +61,7 @@ impl WebsysDom {
|
|||
let i = &self.interpreter;
|
||||
for edit in edits.drain(..) {
|
||||
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),
|
||||
CreatePlaceholder { id } => i.CreatePlaceholder(id.0 as u32),
|
||||
CreateTextNode { value, id } => i.CreateTextNode(value.into(), id.0 as u32),
|
||||
|
@ -87,8 +85,8 @@ impl WebsysDom {
|
|||
self.interpreter.NewEventListener(
|
||||
name,
|
||||
id.0 as u32,
|
||||
self.handler.as_ref().unchecked_ref(),
|
||||
event_bubbles(&name[2..]),
|
||||
self.handler.as_ref().unchecked_ref(),
|
||||
);
|
||||
}
|
||||
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 work = dom.wait_for_work().fuse();
|
||||
pin_mut!(work);
|
||||
|
||||
futures_util::select! {
|
||||
_ = work => None,
|
||||
new_template = hotreload_rx.next() => {
|
||||
|
|
Loading…
Reference in a new issue