Feat: move webview logic into library
This commit is contained in:
parent
18a7a1f9c4
commit
32b45e5ba1
|
@ -10,6 +10,7 @@
|
|||
Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust.
|
||||
|
||||
```rust
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
let (value, set_value) = use_state(&ctx, || "...?");
|
||||
|
||||
|
@ -23,6 +24,7 @@ static Example: FC<()> = |ctx| {
|
|||
</div>
|
||||
})
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
Dioxus can be used to deliver webapps, desktop apps, static pages, liveview apps, Android apps, iOS Apps, and more. At its core, Dioxus is entirely renderer agnostic and has great documentation for creating new renderers for any platform.
|
||||
|
@ -86,3 +88,10 @@ Dioxus LiveHost is a paid service dedicated to hosting your Dioxus Apps - whethe
|
|||
For small teams, LiveHost is free 🎉. Check out the pricing page to see if Dioxus LiveHost is good fit for your team.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -79,7 +79,6 @@ impl<'a> Context<'a> {
|
|||
let safe_nodes = lazy_nodes(self.bump);
|
||||
let unsafe_nodes = unsafe { std::mem::transmute::<VNode<'a>, VNode<'static>>(safe_nodes) };
|
||||
self.final_nodes.deref().borrow_mut().replace(unsafe_nodes);
|
||||
info!("lazy nodes have been generated");
|
||||
DomTree {}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ pub struct Scope {
|
|||
pub frames: ActiveFrame,
|
||||
|
||||
// IE Which listeners need to be woken up?
|
||||
pub listeners: Vec<Box<dyn Fn()>>,
|
||||
pub listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>>,
|
||||
|
||||
// lying, cheating reference >:(
|
||||
pub props: Box<dyn std::any::Any>,
|
||||
|
@ -55,7 +55,7 @@ impl Scope {
|
|||
// Capture the caller
|
||||
let caller = f as *const ();
|
||||
|
||||
let listeners: Vec<Box<dyn Fn()>> = vec![Box::new(|| {
|
||||
let listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>> = vec![Box::new(|_| {
|
||||
log::info!("Base listener called");
|
||||
})];
|
||||
|
||||
|
|
|
@ -98,12 +98,7 @@ impl VirtualDom {
|
|||
|
||||
component.run::<()>();
|
||||
|
||||
let old = component.old_frame();
|
||||
let new = component.new_frame();
|
||||
dbg!(old);
|
||||
dbg!(new);
|
||||
|
||||
diff_machine.diff_node(old, new);
|
||||
diff_machine.diff_node(component.old_frame(), component.new_frame());
|
||||
|
||||
Ok(diff_machine.consume())
|
||||
}
|
||||
|
@ -136,7 +131,7 @@ impl VirtualDom {
|
|||
let EventTrigger {
|
||||
component_id,
|
||||
listener_id,
|
||||
event: _,
|
||||
event: source,
|
||||
} = event;
|
||||
|
||||
let component = self
|
||||
|
@ -151,7 +146,7 @@ impl VirtualDom {
|
|||
.as_ref();
|
||||
|
||||
// Run the callback with the user event
|
||||
listener();
|
||||
listener(source);
|
||||
|
||||
// Mark dirty components. Descend from the highest node until all dirty nodes are updated.
|
||||
let mut affected_components = Vec::new();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use dioxus_core::changelist::Edit;
|
||||
use fxhash::FxHashMap;
|
||||
use log::{debug};
|
||||
use log::debug;
|
||||
use wasm_bindgen::{closure::Closure, JsCast};
|
||||
use web_sys::{window, Document, Element, Event, Node};
|
||||
|
||||
|
@ -8,13 +8,13 @@ use web_sys::{window, Document, Element, Event, Node};
|
|||
pub struct CacheId(u32);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PatchMachine {
|
||||
pub(crate) struct PatchMachine {
|
||||
container: Element,
|
||||
pub stack: Stack,
|
||||
pub(crate) stack: Stack,
|
||||
temporaries: FxHashMap<u32, Node>,
|
||||
templates: FxHashMap<CacheId, Node>,
|
||||
callback: Option<Closure<dyn FnMut(&Event)>>,
|
||||
document: Document,
|
||||
// templates: FxHashMap<CacheId, Node>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -65,10 +65,10 @@ impl PatchMachine {
|
|||
.expect("must have access to the Document");
|
||||
|
||||
Self {
|
||||
// templates: Default::default(),
|
||||
container,
|
||||
stack: Stack::with_capacity(20),
|
||||
temporaries: Default::default(),
|
||||
templates: Default::default(),
|
||||
callback: None,
|
||||
document,
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ impl PatchMachine {
|
|||
pub fn unmount(&mut self) {
|
||||
self.stack.clear();
|
||||
self.temporaries.clear();
|
||||
self.templates.clear();
|
||||
// self.templates.clear();
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
|
@ -92,7 +92,8 @@ impl PatchMachine {
|
|||
}
|
||||
|
||||
pub fn get_template(&self, id: CacheId) -> Option<&Node> {
|
||||
self.templates.get(&id)
|
||||
todo!()
|
||||
// self.templates.get(&id)
|
||||
}
|
||||
|
||||
pub fn init_events_trampoline(&mut self, _trampoline: ()) {
|
||||
|
@ -379,273 +380,22 @@ impl PatchMachine {
|
|||
}
|
||||
}
|
||||
|
||||
// // 0
|
||||
// pub fn set_text(&mut self, text: &str) {
|
||||
// self.stack.top().set_text_content(Some(text));
|
||||
// // 24
|
||||
// pub fn save_template(&mut self, id: CacheId) {
|
||||
// let template = self.stack.top();
|
||||
// let t = template.clone_node_with_deep(true).unwrap();
|
||||
// // self.templates.insert(id, t);
|
||||
// }
|
||||
|
||||
// // 1
|
||||
// pub fn remove_self_and_next_siblings(&mut self) {
|
||||
// let node = self.stack.pop();
|
||||
// let mut sibling = node.next_sibling();
|
||||
|
||||
// while let Some(inner) = sibling {
|
||||
// let temp = inner.next_sibling();
|
||||
// if let Some(sibling) = inner.dyn_ref::<Element>() {
|
||||
// sibling.remove();
|
||||
// }
|
||||
// sibling = temp;
|
||||
// }
|
||||
// if let Some(node) = node.dyn_ref::<Element>() {
|
||||
// node.remove();
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 2
|
||||
// pub fn replace_with(&mut self) {
|
||||
// let new_node = self.stack.pop();
|
||||
// let old_node = self.stack.pop();
|
||||
|
||||
// if old_node.has_type::<Element>() {
|
||||
// old_node
|
||||
// .dyn_ref::<Element>()
|
||||
// .unwrap()
|
||||
// .replace_with_with_node_1(&new_node)
|
||||
// .unwrap();
|
||||
// } else if old_node.has_type::<web_sys::CharacterData>() {
|
||||
// old_node
|
||||
// .dyn_ref::<web_sys::CharacterData>()
|
||||
// .unwrap()
|
||||
// .replace_with_with_node_1(&new_node)
|
||||
// .unwrap();
|
||||
// } else if old_node.has_type::<web_sys::DocumentType>() {
|
||||
// old_node
|
||||
// .dyn_ref::<web_sys::DocumentType>()
|
||||
// .unwrap()
|
||||
// .replace_with_with_node_1(&new_node)
|
||||
// .unwrap();
|
||||
// } else {
|
||||
// panic!("Cannot replace node: {:?}", old_node);
|
||||
// }
|
||||
|
||||
// self.stack.push(new_node);
|
||||
// }
|
||||
|
||||
// // 3
|
||||
// pub fn set_attribute(&mut self, name: &str, value: &str) {
|
||||
// let node = self.stack.top();
|
||||
|
||||
// if let Some(node) = node.dyn_ref::<Element>() {
|
||||
// node.set_attribute(name, value).unwrap();
|
||||
|
||||
// // Some attributes are "volatile" and don't work through `setAttribute`.
|
||||
// // TODO:
|
||||
// // if name == "value" {
|
||||
// // node.set_value(value);
|
||||
// // }
|
||||
// // if name == "checked" {
|
||||
// // node.set_checked(true);
|
||||
// // }
|
||||
// // if name == "selected" {
|
||||
// // node.set_selected(true);
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 4
|
||||
// pub fn remove_attribute(&mut self, name: &str) {
|
||||
// let node = self.stack.top();
|
||||
// if let Some(node) = node.dyn_ref::<Element>() {
|
||||
// node.remove_attribute(name).unwrap();
|
||||
|
||||
// // Some attributes are "volatile" and don't work through `removeAttribute`.
|
||||
// // TODO:
|
||||
// // if name == "value" {
|
||||
// // node.set_value("");
|
||||
// // }
|
||||
// // if name == "checked" {
|
||||
// // node.set_checked(false);
|
||||
// // }
|
||||
// // if name == "selected" {
|
||||
// // node.set_selected(false);
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 5
|
||||
// pub fn push_reverse_child(&mut self, n: u32) {
|
||||
// let parent = self.stack.top();
|
||||
// let children = parent.child_nodes();
|
||||
// let child = children.get(children.length() - n - 1).unwrap();
|
||||
// self.stack.push(child);
|
||||
// }
|
||||
|
||||
// // 6
|
||||
// pub fn pop_push_child(&mut self, n: u32) {
|
||||
// self.stack.pop();
|
||||
// let parent = self.stack.top();
|
||||
// let children = parent.child_nodes();
|
||||
// let child = children.get(n).unwrap();
|
||||
// self.stack.push(child);
|
||||
// }
|
||||
|
||||
// // 7
|
||||
// pub fn pop(&mut self) {
|
||||
// self.stack.pop();
|
||||
// }
|
||||
|
||||
// // 8
|
||||
// pub fn append_child(&mut self) {
|
||||
// let child = self.stack.pop();
|
||||
// self.stack.top().append_child(&child).unwrap();
|
||||
// }
|
||||
|
||||
// // 9
|
||||
// pub fn create_text_node(&mut self, text: &str) {
|
||||
// self.stack.push(
|
||||
// self.document
|
||||
// .create_text_node(text)
|
||||
// .dyn_into::<Node>()
|
||||
// .unwrap(),
|
||||
// );
|
||||
// }
|
||||
|
||||
// // 10
|
||||
// pub fn create_element(&mut self, tag_name: &str) {
|
||||
// let el = self
|
||||
// .document
|
||||
// .create_element(tag_name)
|
||||
// .unwrap()
|
||||
// .dyn_into::<Node>()
|
||||
// .unwrap();
|
||||
// self.stack.push(el);
|
||||
// }
|
||||
|
||||
// // 11
|
||||
// pub fn new_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
|
||||
// let el = self.stack.top();
|
||||
|
||||
// let el = el
|
||||
// .dyn_ref::<Element>()
|
||||
// .expect(&format!("not an element: {:?}", el));
|
||||
// el.add_event_listener_with_callback(
|
||||
// event_type,
|
||||
// self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
|
||||
// )
|
||||
// .unwrap();
|
||||
// debug!("adding attributes: {}, {}", a, b);
|
||||
// el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
|
||||
// .unwrap();
|
||||
// el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// // 12
|
||||
// pub fn update_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
|
||||
// if let Some(el) = self.stack.top().dyn_ref::<Element>() {
|
||||
// el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
|
||||
// .unwrap();
|
||||
// el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
|
||||
// .unwrap();
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 13
|
||||
// pub fn remove_event_listener(&mut self, event_type: &str) {
|
||||
// if let Some(el) = self.stack.top().dyn_ref::<Element>() {
|
||||
// el.remove_event_listener_with_callback(
|
||||
// event_type,
|
||||
// self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
|
||||
// )
|
||||
// .unwrap();
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 16
|
||||
// pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) {
|
||||
// let el = self
|
||||
// .document
|
||||
// .create_element_ns(Some(ns), tag_name)
|
||||
// .unwrap()
|
||||
// .dyn_into::<Node>()
|
||||
// .unwrap();
|
||||
// self.stack.push(el);
|
||||
// }
|
||||
|
||||
// // 17
|
||||
// pub fn save_children_to_temporaries(&mut self, mut temp: u32, start: u32, end: u32) {
|
||||
// let parent = self.stack.top();
|
||||
// let children = parent.child_nodes();
|
||||
// for i in start..end {
|
||||
// self.temporaries.insert(temp, children.get(i).unwrap());
|
||||
// temp += 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 18
|
||||
// pub fn push_child(&mut self, n: u32) {
|
||||
// let parent = self.stack.top();
|
||||
// let child = parent.child_nodes().get(n).unwrap();
|
||||
// self.stack.push(child);
|
||||
// }
|
||||
|
||||
// // 19
|
||||
// pub fn push_temporary(&mut self, temp: u32) {
|
||||
// let t = self.temporaries.get(&temp).unwrap().clone();
|
||||
// // 25
|
||||
// pub fn push_template(&mut self, id: CacheId) {
|
||||
// let template = self.get_template(id).unwrap();
|
||||
// let t = template.clone_node_with_deep(true).unwrap();
|
||||
// self.stack.push(t);
|
||||
// }
|
||||
|
||||
// // 20
|
||||
// pub fn insert_before(&mut self) {
|
||||
// let before = self.stack.pop();
|
||||
// let after = self.stack.pop();
|
||||
// after
|
||||
// .parent_node()
|
||||
// .unwrap()
|
||||
// .insert_before(&before, Some(&after))
|
||||
// .unwrap();
|
||||
// self.stack.push(before);
|
||||
// pub fn has_template(&self, id: CacheId) -> bool {
|
||||
// todo!()
|
||||
// // self.templates.contains_key(&id)
|
||||
// }
|
||||
|
||||
// // 21
|
||||
// pub fn pop_push_reverse_child(&mut self, n: u32) {
|
||||
// self.stack.pop();
|
||||
// let parent = self.stack.top();
|
||||
// let children = parent.child_nodes();
|
||||
// let child = children.get(children.length() - n - 1).unwrap();
|
||||
// self.stack.push(child);
|
||||
// }
|
||||
|
||||
// // 22
|
||||
// pub fn remove_child(&mut self, n: u32) {
|
||||
// let parent = self.stack.top();
|
||||
// if let Some(child) = parent.child_nodes().get(n).unwrap().dyn_ref::<Element>() {
|
||||
// child.remove();
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 23
|
||||
// pub fn set_class(&mut self, class_name: &str) {
|
||||
// if let Some(el) = self.stack.top().dyn_ref::<Element>() {
|
||||
// el.set_class_name(class_name);
|
||||
// }
|
||||
// }
|
||||
|
||||
// 24
|
||||
pub fn save_template(&mut self, id: CacheId) {
|
||||
let template = self.stack.top();
|
||||
let t = template.clone_node_with_deep(true).unwrap();
|
||||
self.templates.insert(id, t);
|
||||
}
|
||||
|
||||
// 25
|
||||
pub fn push_template(&mut self, id: CacheId) {
|
||||
let template = self.get_template(id).unwrap();
|
||||
let t = template.clone_node_with_deep(true).unwrap();
|
||||
self.stack.push(t);
|
||||
}
|
||||
|
||||
pub fn has_template(&self, id: CacheId) -> bool {
|
||||
self.templates.contains_key(&id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,6 @@ pub mod interpreter;
|
|||
///
|
||||
pub struct WebsysRenderer {
|
||||
internal_dom: VirtualDom,
|
||||
|
||||
// this should be a component index
|
||||
_event_map: FxHashMap<(u32, u32), u32>,
|
||||
}
|
||||
|
||||
impl WebsysRenderer {
|
||||
|
@ -58,10 +55,7 @@ impl WebsysRenderer {
|
|||
/// Create a new text renderer from an existing Virtual DOM.
|
||||
pub fn from_vdom(dom: VirtualDom) -> Self {
|
||||
// todo: initialize the event registry properly
|
||||
Self {
|
||||
internal_dom: dom,
|
||||
_event_map: FxHashMap::default(),
|
||||
}
|
||||
Self { internal_dom: dom }
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
|
||||
|
@ -72,7 +66,7 @@ impl WebsysRenderer {
|
|||
let root_node = body_element.first_child().unwrap();
|
||||
patch_machine.stack.push(root_node);
|
||||
|
||||
// todo: initialize the event registry properly on the root element
|
||||
// todo: initialize the event registry properly on the root
|
||||
|
||||
self.internal_dom
|
||||
.rebuild()?
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
// This file interperets incoming edit messages into the page and renders them.
|
||||
// This is written in javascript to be slightly easier to work with (instead of having to pre-compile the wasm)
|
||||
// One day, we'll probably using wasmbindgen for the inner, but a javascripty one is fine too.
|
|
@ -1,152 +1,52 @@
|
|||
//! An example where the dioxus vdom is running in a native thread, interacting with webview
|
||||
//! Content is passed from the native thread into the webview
|
||||
|
||||
use std::{
|
||||
borrow::BorrowMut,
|
||||
rc::Rc,
|
||||
sync::{mpsc::channel, Arc},
|
||||
};
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
// use async_std::{channel, task::block_on};
|
||||
fn main(){
|
||||
dioxus_webview::launch(
|
||||
// Customize the webview
|
||||
|builder| {
|
||||
builder
|
||||
.title("Test Dioxus App")
|
||||
.size(320, 480)
|
||||
.resizable(true)
|
||||
.debug(true)
|
||||
},
|
||||
// Props
|
||||
(),
|
||||
// Draw the root component
|
||||
|ctx, _props| {
|
||||
ctx.view(html! {
|
||||
<div>
|
||||
<div class="flex items-center justify-center flex-col">
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
|
||||
// Title
|
||||
<div class="font-bold text-xl"> "Jon's awesome site!!11" </div>
|
||||
|
||||
use dioxus_core::{dodriodiff::DiffMachine, prelude::bumpalo::Bump, prelude::*, scope};
|
||||
use scope::Scope;
|
||||
use web_view::Handle;
|
||||
static HTML_CONTENT: &'static str = include_str!("./index.html");
|
||||
// Subtext / description
|
||||
<div class="text-sm text-gray-500"> "He worked so hard on it :)" </div>
|
||||
|
||||
enum InnerEvent {
|
||||
Initiate(Handle<()>),
|
||||
}
|
||||
<div class="flex flex-row items-center justify-center mt-6">
|
||||
// Main number
|
||||
<div class="font-medium text-6xl">
|
||||
"1337"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// async_std::task::spawn(async {
|
||||
// #[async_std::main]
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let (sender, receiver) = channel::<InnerEvent>();
|
||||
// let (sender, receiver) = channel::unbounded::<InnerEvent>();
|
||||
|
||||
// let task = async_std::task::spawn(async move {
|
||||
let mut view = web_view::builder()
|
||||
.title("My Project")
|
||||
.content(web_view::Content::Html(HTML_CONTENT))
|
||||
.size(320, 480)
|
||||
.resizable(true)
|
||||
.debug(true)
|
||||
.user_data(())
|
||||
.invoke_handler(|view, arg| {
|
||||
// todo: handle events here
|
||||
println!("handling invoker");
|
||||
let handle = view.handle();
|
||||
sender.send(InnerEvent::Initiate(handle));
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
println!("building the diff");
|
||||
let bump = Bump::new();
|
||||
let mut diff_machine = DiffMachine::new(&bump);
|
||||
let old = html! {<div> </div>}(&bump);
|
||||
|
||||
// let mut scope = Scope::new(TEST, (), None);
|
||||
// scope.run::<()>();
|
||||
let new = html! {
|
||||
<div>
|
||||
<div class="flex items-center justify-center flex-col">
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
|
||||
// Title
|
||||
<div class="font-bold text-xl">
|
||||
"Jon's awesome site!!11"
|
||||
</div>
|
||||
|
||||
// Subtext / description
|
||||
<div class="text-sm text-gray-500">
|
||||
"He worked so hard on it :)"
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center justify-center mt-6">
|
||||
// Main number
|
||||
<div class="font-medium text-6xl">
|
||||
"1337"
|
||||
// Try another
|
||||
<div class="flex flex-row justify-between mt-6">
|
||||
<a href="http://localhost:8080/fib/{}" class="underline">
|
||||
"Legit made my own React"
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// Try another
|
||||
<div class="flex flex-row justify-between mt-6">
|
||||
// <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
|
||||
"Legit made my own React"
|
||||
// </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}(&bump);
|
||||
|
||||
diff_machine.diff_node(&old, &new);
|
||||
|
||||
let edits = diff_machine.consume();
|
||||
let ready_edits = serde_json::to_string(&edits)?;
|
||||
let ref_edits = Arc::new(ready_edits);
|
||||
|
||||
loop {
|
||||
view.step().expect("should not fail");
|
||||
// if let Some(evt) = receiver.try_recv() {}
|
||||
if let Ok(event) = receiver.try_recv() {
|
||||
match event {
|
||||
InnerEvent::Initiate(handle) => {
|
||||
// println!("awesome, things worked");
|
||||
let ediits = ref_edits.clone();
|
||||
// println!("{}", ediits);
|
||||
handle
|
||||
.dispatch(move |view| {
|
||||
view.eval(format!("EditListReceived(`{}`);", ediits).as_str())?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.expect("Dispatch failed");
|
||||
// let g = handle.();
|
||||
}
|
||||
}
|
||||
}
|
||||
// let event = receiver.try_recv();
|
||||
|
||||
// view.eval("alert('omg');")?;
|
||||
// view.step().expect("webview should not fail")?;
|
||||
}
|
||||
})
|
||||
},
|
||||
).expect("Webview finished");
|
||||
}
|
||||
|
||||
// static TEST: FC<()> = |ctx, props| {
|
||||
// ctx.view(html! {
|
||||
// <div>
|
||||
// <div class="flex items-center justify-center flex-col">
|
||||
// <div class="flex items-center justify-center">
|
||||
// <div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
|
||||
// // Title
|
||||
// <div class="font-bold text-xl">
|
||||
// "Jon's awesome site!!11"
|
||||
// </div>
|
||||
|
||||
// // Subtext / description
|
||||
// <div class="text-sm text-gray-500">
|
||||
// "He worked so hard on it :)"
|
||||
// </div>
|
||||
|
||||
// <div class="flex flex-row items-center justify-center mt-6">
|
||||
// // Main number
|
||||
// <div class="font-medium text-6xl">
|
||||
// "1337"
|
||||
// </div>
|
||||
// </div>
|
||||
|
||||
// // Try another
|
||||
// <div class="flex flex-row justify-between mt-6">
|
||||
// // <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
|
||||
// "Legit made my own React"
|
||||
// // </a>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// })
|
||||
// };
|
||||
|
|
|
@ -12,34 +12,6 @@
|
|||
<div></div>
|
||||
</body>
|
||||
<script>
|
||||
// #[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
// pub enum Edit<'d> {
|
||||
// SetText { text: &'d str },
|
||||
// RemoveSelfAndNextSiblings {},
|
||||
// ReplaceWith,
|
||||
// SetAttribute { name: &'d str, value: &'d str },
|
||||
// RemoveAttribute { name: &'d str },
|
||||
// PushReverseChild { n: u32 },
|
||||
// PopPushChild { n: u32 },
|
||||
// Pop,
|
||||
// AppendChild,
|
||||
// CreateTextNode { text: &'d str },
|
||||
// CreateElement { tag_name: &'d str },
|
||||
// NewEventListener { event_type: &'d str, a: u32, b: u32 },
|
||||
// UpdateEventListener { event_type: &'d str, a: u32, b: u32 },
|
||||
// RemoveEventListener { event_type: &'d str },
|
||||
// CreateElementNs { tag_name: &'d str, ns: &'d str },
|
||||
// SaveChildrenToTemporaries { temp: u32, start: u32, end: u32 },
|
||||
// PushChild { n: u32 },
|
||||
// PushTemporary { temp: u32 },
|
||||
// InsertBefore,
|
||||
// PopPushReverseChild { n: u32 },
|
||||
// RemoveChild { n: u32 },
|
||||
// SetClass { class_name: &'d str },
|
||||
// }
|
||||
|
||||
// const interpreter = new Interpreter();
|
||||
|
||||
class Interpreter {
|
||||
constructor(root) {
|
||||
this.stack = [root];
|
||||
|
@ -302,20 +274,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
let op = new OPTABLE();
|
||||
const c = window.document.body.firstChild;
|
||||
console.log("First child");
|
||||
console.log(c);
|
||||
const op_table = new OPTABLE();
|
||||
const interpreter = new Interpreter(window.document.body);
|
||||
|
||||
function EditListReceived(rawEditList) {
|
||||
let editList = JSON.parse(rawEditList);
|
||||
console.log(editList);
|
||||
editList.forEach(function (edit, index) {
|
||||
// console.log("processing edit");
|
||||
const name = edit.type;
|
||||
console.log(name);
|
||||
const f = op[name];
|
||||
f(edit, interpreter);
|
||||
op_table[edit.type](edit, interpreter);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,8 +1,18 @@
|
|||
use dioxus_core::prelude::*;
|
||||
use web_view::WebViewBuilder;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn new<T>(root: FC<T>) -> WebviewRenderer<T> {
|
||||
WebviewRenderer::new(root)
|
||||
use dioxus_core::prelude::*;
|
||||
use web_view::Handle;
|
||||
use web_view::{WVResult, WebView, WebViewBuilder};
|
||||
|
||||
static HTML_CONTENT: &'static str = include_str!("./index.html");
|
||||
|
||||
pub fn launch<T: 'static>(
|
||||
builder: impl FnOnce(DioxusWebviewBuilder) -> DioxusWebviewBuilder,
|
||||
props: T,
|
||||
root: FC<T>,
|
||||
) -> anyhow::Result<()> {
|
||||
WebviewRenderer::run(root, props, builder)
|
||||
}
|
||||
|
||||
/// The `WebviewRenderer` provides a way of rendering a Dioxus Virtual DOM through a bridge to a Webview instance.
|
||||
|
@ -11,13 +21,78 @@ pub struct WebviewRenderer<T> {
|
|||
/// The root component used to render the Webview
|
||||
root: FC<T>,
|
||||
}
|
||||
enum InnerEvent {
|
||||
Initiate(Handle<()>),
|
||||
}
|
||||
|
||||
impl<T: 'static> WebviewRenderer<T> {
|
||||
pub fn run(
|
||||
root: FC<T>,
|
||||
props: T,
|
||||
user_builder: impl FnOnce(DioxusWebviewBuilder) -> DioxusWebviewBuilder,
|
||||
) -> anyhow::Result<()> {
|
||||
let (sender, receiver) = channel::<InnerEvent>();
|
||||
|
||||
let DioxusWebviewBuilder {
|
||||
title,
|
||||
width,
|
||||
height,
|
||||
resizable,
|
||||
debug,
|
||||
frameless,
|
||||
visible,
|
||||
min_width,
|
||||
min_height,
|
||||
} = user_builder(DioxusWebviewBuilder::new());
|
||||
|
||||
let mut view = web_view::builder()
|
||||
.invoke_handler(|view, arg| {
|
||||
let handle = view.handle();
|
||||
sender
|
||||
.send(InnerEvent::Initiate(handle))
|
||||
.expect("should not fail");
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.content(web_view::Content::Html(HTML_CONTENT))
|
||||
.user_data(())
|
||||
.title(title)
|
||||
.size(width, height)
|
||||
.resizable(resizable)
|
||||
.debug(debug)
|
||||
.frameless(frameless)
|
||||
.visible(visible)
|
||||
.min_size(min_width, min_height)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut vdom = VirtualDom::new_with_props(root, props);
|
||||
let edits = vdom.rebuild()?;
|
||||
let ref_edits = Arc::new(serde_json::to_string(&edits)?);
|
||||
|
||||
loop {
|
||||
view.step()
|
||||
.expect("should not fail")
|
||||
.expect("should not fail");
|
||||
|
||||
if let Ok(event) = receiver.try_recv() {
|
||||
if let InnerEvent::Initiate(handle) = event {
|
||||
let editlist = ref_edits.clone();
|
||||
handle
|
||||
.dispatch(move |view| {
|
||||
view.eval(format!("EditListReceived(`{}`);", editlist).as_str())
|
||||
})
|
||||
.expect("Dispatch failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> WebviewRenderer<T> {
|
||||
/// Create a new text-renderer instance from a functional component root.
|
||||
/// Automatically progresses the creation of the VNode tree to completion.
|
||||
///
|
||||
/// A VDom is automatically created. If you want more granular control of the VDom, use `from_vdom`
|
||||
pub fn new(root: FC<T>) -> Self {
|
||||
pub fn new(root: FC<T>, builder: impl FnOnce() -> WVResult<WebView<'static, ()>>) -> Self {
|
||||
Self { root }
|
||||
}
|
||||
|
||||
|
@ -36,41 +111,92 @@ impl<T> WebviewRenderer<T> {
|
|||
pub fn update_mut(&mut self, modifier: impl Fn(&mut T)) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn launch(self, props: T) {
|
||||
todo!()
|
||||
// let mut ctx = Context { props: &props };
|
||||
// let WebviewRenderer { root } = self;
|
||||
// let content = root(&mut ctx);
|
||||
// let html_content = content.to_string();
|
||||
// /*
|
||||
// TODO: @Jon
|
||||
// Launch the webview with a premade VDom app
|
||||
// */
|
||||
|
||||
// web_view::builder()
|
||||
// .title("My Project")
|
||||
// .content(web_view::Content::Html(html_content))
|
||||
// .size(320, 480)
|
||||
// .resizable(true)
|
||||
// .debug(true)
|
||||
// .user_data(())
|
||||
// .invoke_handler(|_webview, _arg| Ok(()))
|
||||
// .run()
|
||||
// .unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// mod receiver {
|
||||
// use dioxus_core::prelude::*;
|
||||
pub struct DioxusWebviewBuilder<'a> {
|
||||
pub(crate) title: &'a str,
|
||||
pub(crate) width: i32,
|
||||
pub(crate) height: i32,
|
||||
pub(crate) resizable: bool,
|
||||
pub(crate) debug: bool,
|
||||
pub(crate) frameless: bool,
|
||||
pub(crate) visible: bool,
|
||||
pub(crate) min_width: i32,
|
||||
pub(crate) min_height: i32,
|
||||
}
|
||||
impl<'a> DioxusWebviewBuilder<'a> {
|
||||
fn new() -> Self {
|
||||
#[cfg(debug_assertions)]
|
||||
let debug = true;
|
||||
#[cfg(not(debug_assertions))]
|
||||
let debug = false;
|
||||
|
||||
// /// The receiver app is a container that builds a connection to the host process that shuttles events and patches.
|
||||
// pub(crate) static ReceiverApp: FC<()> = |ctx| {
|
||||
// //
|
||||
// html! {
|
||||
// <div>
|
||||
// {}
|
||||
// </div>
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
DioxusWebviewBuilder {
|
||||
title: "Application",
|
||||
width: 800,
|
||||
height: 600,
|
||||
resizable: true,
|
||||
debug,
|
||||
frameless: false,
|
||||
visible: true,
|
||||
min_width: 300,
|
||||
min_height: 300,
|
||||
}
|
||||
}
|
||||
/// Sets the title of the WebView window.
|
||||
///
|
||||
/// Defaults to `"Application"`.
|
||||
pub fn title(mut self, title: &'a str) -> Self {
|
||||
self.title = title;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the size of the WebView window.
|
||||
///
|
||||
/// Defaults to 800 x 600.
|
||||
pub fn size(mut self, width: i32, height: i32) -> Self {
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the resizability of the WebView window. If set to false, the window cannot be resized.
|
||||
///
|
||||
/// Defaults to `true`.
|
||||
pub fn resizable(mut self, resizable: bool) -> Self {
|
||||
self.resizable = resizable;
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables or disables debug mode.
|
||||
///
|
||||
/// Defaults to `true` for debug builds, `false` for release builds.
|
||||
pub fn debug(mut self, debug: bool) -> Self {
|
||||
self.debug = debug;
|
||||
self
|
||||
}
|
||||
/// The window crated will be frameless
|
||||
///
|
||||
/// defaults to `false`
|
||||
pub fn frameless(mut self, frameless: bool) -> Self {
|
||||
self.frameless = frameless;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the visibility of the WebView window.
|
||||
///
|
||||
/// defaults to `true`
|
||||
pub fn visible(mut self, visible: bool) -> Self {
|
||||
self.visible = visible;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the minimum size of the WebView window.
|
||||
///
|
||||
/// Defaults to 300 x 300.
|
||||
pub fn min_size(mut self, width: i32, height: i32) -> Self {
|
||||
self.min_width = width;
|
||||
self.min_height = height;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue