wip: docs and router

This commit is contained in:
Jonathan Kelley committed 2021-11-19 00:49:04 -05:00
1 parent 8bf57dc21d
commit a5f05d73ac
50 files changed
+1263 -234

No files matched your search

+20 -2
View File
@@ -11,10 +11,17 @@ license = "MIT/Apache-2.0"
dioxus-core = { path = "../core", version = "0.1.2" }
dioxus-html = { path = "../html" }
js-sys = "0.3"
# wasm-bindgen-shared = { path = "../../../Tinkering/wasm-bindgen/crates/shared" }
# wasm-bindgen-macro-support = { path = "../../../Tinkering/wasm-bindgen/crates/macro-support" }
# wasm-bindgen = { features = [
wasm-bindgen = { version = "0.2.78", features = ["enable-interning"] }
# wasm-bindgen = { version = "0.2.78", features = ["enable-interning"] }
# wasm-bindgen = { version = "0.2.78", features = ["enable-interning"] }
lazy_static = "1.4.0"
wasm-bindgen-futures = "0.4.20"
log = "0.4.14"
log = { version = "0.4.14", features = ["release_max_level_off"] }
fxhash = "0.2.1"
wasm-logger = "0.2.0"
console_error_panic_hook = "0.1.6"
@@ -24,6 +31,11 @@ async-channel = "1.6.1"
anyhow = "1.0"
gloo-timers = { version = "0.2.1", features = ["futures"] }
futures-util = "0.3.15"
smallstr = "0.2.0"
[patch.crates-io]
wasm-bindgen = { path = "../../../Tinkering/wasm-bindgen/" }
[dependencies.web-sys]
version = "0.3.51"
@@ -65,6 +77,7 @@ features = [
"IdleDeadline",
]
[lib]
crate-type = ["cdylib", "rlib"]
@@ -76,7 +89,12 @@ serde = { version = "1.0.126", features = ["derive"] }
reqwest = { version = "0.11", features = ["json"] }
dioxus-hooks = { path = "../hooks" }
dioxus-core-macro = { path = "../core-macro" }
# rand = { version="0.8.4", features=["small_rng"] }
rand = { version = "0.8.4", features = ["small_rng"] }
[dev-dependencies.getrandom]
version = "0.2"
features = ["js"]
# surf = { version = "2.3.1", default-features = false, features = [
# "wasm-client",
# ] }
+243
View File
@@ -0,0 +1,243 @@
use std::cell::Cell;
use dioxus::prelude::*;
use dioxus_core as dioxus;
use dioxus_core_macro::*;
use dioxus_hooks::{use_ref, use_state};
use dioxus_html as dioxus_elements;
use dioxus_web;
use gloo_timers::future::TimeoutFuture;
use rand::prelude::*;
fn main() {
console_error_panic_hook::set_once();
if cfg!(debug_assertions) {
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
log::debug!("hello world");
}
for a in ADJECTIVES {
wasm_bindgen::intern(*a);
}
for a in COLOURS {
wasm_bindgen::intern(*a);
}
for a in NOUNS {
wasm_bindgen::intern(*a);
}
for a in [
"container",
"jumbotron",
"row",
"Dioxus",
"col-md-6",
"col-md-1",
"Create 1,000 rows",
"run",
"Create 10,000 rows",
"runlots",
"Append 1,000 rows",
"add",
"Update every 10th row",
"update",
"Clear",
"clear",
"Swap rows",
"swaprows",
"preloadicon glyphicon glyphicon-remove", //
"aria-hidden",
"onclick",
"true",
"false",
"danger",
"type",
"id",
"class",
"glyphicon glyphicon-remove remove",
"dioxus-id",
"dioxus-event-click",
"dioxus",
"click",
"1.10",
"lbl",
"remove",
"dioxus-event",
"col-sm-6 smallpad",
"btn btn-primary btn-block",
"",
" ",
] {
wasm_bindgen::intern(a);
}
for x in 0..100_000 {
wasm_bindgen::intern(&x.to_string());
}
dioxus_web::launch(App, |c| c.rootname("main"));
}
#[derive(Clone, PartialEq, Copy)]
struct Label {
key: usize,
labels: [&'static str; 3],
}
static mut Counter: Cell<usize> = Cell::new(1);
impl Label {
fn new_list(num: usize) -> Vec<Self> {
let mut rng = SmallRng::from_entropy();
let mut labels = Vec::with_capacity(num);
let offset = unsafe { Counter.get() };
unsafe { Counter.set(offset + num) };
for k in offset..(offset + num) {
labels.push(Label {
key: k,
labels: [
ADJECTIVES.choose(&mut rng).unwrap(),
COLOURS.choose(&mut rng).unwrap(),
NOUNS.choose(&mut rng).unwrap(),
],
});
}
labels
}
}
static App: FC<()> = |cx, _props| {
let mut items = use_ref(cx, || vec![]);
let mut selected = use_state(cx, || None);
cx.render(rsx! {
div { class: "container"
div { class: "jumbotron"
div { class: "row"
div { class: "col-md-6", h1 { "Dioxus" } }
div { class: "col-md-6"
div { class: "row"
ActionButton { name: "Create 1,000 rows", id: "run",
onclick: move || items.set(Label::new_list(1_000)),
}
ActionButton { name: "Create 10,000 rows", id: "runlots",
onclick: move || items.set(Label::new_list(10_000)),
}
ActionButton { name: "Append 1,000 rows", id: "add",
onclick: move || items.write().extend(Label::new_list(1_000)),
}
ActionButton { name: "Update every 10th row", id: "update",
onclick: move || items.write().iter_mut().step_by(10).for_each(|item| item.labels[2] = "!!!"),
}
ActionButton { name: "Clear", id: "clear",
onclick: move || items.write().clear(),
}
ActionButton { name: "Swap Rows", id: "swaprows",
onclick: move || items.write().swap(0, 998),
}
}
}
}
}
table { class: "table table-hover table-striped test-data"
tbody { id: "tbody"
{items.read().iter().enumerate().map(|(id, item)| {
let [adj, col, noun] = item.labels;
let is_in_danger = if (*selected).map(|s| s == id).unwrap_or(false) {"danger"} else {""};
rsx!(tr {
class: "{is_in_danger}",
key: "{id}",
td { class:"col-md-1" }
td { class:"col-md-1", "{item.key}" }
td { class:"col-md-1", onclick: move |_| selected.set(Some(id)),
a { class: "lbl", "{adj} {col} {noun}" }
}
td { class: "col-md-1"
a { class: "remove", onclick: move |_| { items.write().remove(id); },
span { class: "glyphicon glyphicon-remove remove" aria_hidden: "true" }
}
}
td { class: "col-md-6" }
})
})}
}
}
span { class: "preloadicon glyphicon glyphicon-remove" aria_hidden: "true" }
}
})
};
#[derive(Props)]
struct ActionButtonProps<'a> {
name: &'static str,
id: &'static str,
onclick: &'a dyn Fn(),
}
fn ActionButton(cx: Context, props: &ActionButtonProps) -> Element {
rsx!(cx, div { class: "col-sm-6 smallpad"
button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: move |_| (props.onclick)(),
"{props.name}"
}
})
}
static ADJECTIVES: &[&str] = &[
"pretty",
"large",
"big",
"small",
"tall",
"short",
"long",
"handsome",
"plain",
"quaint",
"clean",
"elegant",
"easy",
"angry",
"crazy",
"helpful",
"mushy",
"odd",
"unsightly",
"adorable",
"important",
"inexpensive",
"cheap",
"expensive",
"fancy",
];
static COLOURS: &[&str] = &[
"red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
"orange",
];
static NOUNS: &[&str] = &[
"table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
"pizza", "mouse", "keyboard",
];
// #[derive(PartialEq, Props)]
// struct RowProps<'a> {
// row_id: usize,
// label: &'a Label,
// }
// fn Row(cx: Context, props: &RowProps) -> Element {
// rsx!(cx, tr {
// td { class:"col-md-1", "{props.row_id}" }
// td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
// a { class: "lbl", {props.label.labels} }
// }
// td { class: "col-md-1"
// a { class: "remove", onclick: move |_| {/* remove */}
// span { class: "glyphicon glyphicon-remove remove" aria_hidden: "true" }
// }
// }
// td { class: "col-md-6" }
// })
// }
+46
View File
@@ -0,0 +1,46 @@
//! Example: README.md showcase
//!
//! The example from the README.md.
use dioxus::prelude::*;
use dioxus_core as dioxus;
use dioxus_core_macro::*;
use dioxus_hooks::use_state;
use dioxus_html as dioxus_elements;
use dioxus_web;
use gloo_timers::future::TimeoutFuture;
fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
dioxus_web::launch(App, |c| c);
}
static App: FC<()> = |cx, props| {
let show = use_state(cx, || true);
let inner = match *show {
true => {
rsx!( div {
"hello world"
})
}
false => {
rsx!( div {
// h1 {
"bello world"
// }
})
}
};
rsx!(cx, div {
button {
"toggle"
onclick: move |_| {
let cur = *show;
show.set(!cur);
}
}
{inner}
})
};
+5
View File
@@ -7,6 +7,11 @@
/// Eventually we might want to procedurally generate these strings for common words, phrases, and values.
pub(crate) fn intern_cached_strings() {
let cached_words = [
// Important tags to dioxus
"dioxus-id",
"dioxus",
"dioxus-event-click", // todo: more events
"click",
// All the HTML Tags
"a",
"abbr",
+1 -1
View File
@@ -17,7 +17,7 @@ impl Default for WebConfig {
fn default() -> Self {
Self {
hydrate: false,
rootname: "dioxusroot".to_string(),
rootname: "main".to_string(),
}
}
}
+45 -23
View File
@@ -213,7 +213,7 @@ impl WebsysDom {
fn create_placeholder(&mut self, id: u64) {
self.create_element("pre", None, id);
// self.set_attribute("hidden", "", None);
self.set_attribute("hidden", "", None, id);
}
fn create_text_node(&mut self, text: &str, id: u64) {
@@ -246,8 +246,15 @@ impl WebsysDom {
.unwrap(),
};
use smallstr;
use smallstr::SmallString;
use std::fmt::Write;
let mut s: SmallString<[u8; 8]> = smallstr::SmallString::new();
write!(s, "{}", id).unwrap();
let el2 = el.dyn_ref::<Element>().unwrap();
el2.set_attribute("dioxus-id", &format!("{}", id)).unwrap();
el2.set_attribute("dioxus-id", s.as_str()).unwrap();
self.stack.push(el.clone());
self.nodes[(id as usize)] = Some(el);
@@ -263,18 +270,21 @@ impl WebsysDom {
let el = self.stack.top();
let el = el
.dyn_ref::<Element>()
.expect(&format!("not an element: {:?}", el));
let el = el.dyn_ref::<Element>().unwrap();
// let el = el.dyn_ref::<Element>().unwrap();
// .expect(&format!("not an element: {:?}", el));
// let scope_id = scope.data().as_ffi();
let scope_id = scope.0 as u64;
// let scope_id = scope.0 as u64;
// "dioxus-event-click",
// "1.10"
// &format!("", scope_id, real_id),
// &format!("dioxus-event-{}", event),
// &format!("{}.{}", scope_id, real_id),
// &format!("dioxus-event-{}", event),
// &format!("{}.{}", scope_id, real_id),
el.set_attribute(
&format!("dioxus-event-{}", event),
&format!("{}.{}", scope_id, real_id),
)
.unwrap();
el.set_attribute("dioxus-event", event).unwrap();
// el.set_attribute(&format!("dioxus-event"), &format!("{}", event))
// .unwrap();
@@ -488,6 +498,8 @@ unsafe impl Sync for DioxusWebsysEvent {}
fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc<dyn Any + Send + Sync> {
use dioxus_html::on::*;
use dioxus_html::KeyCode;
// event.prevent_default();
// use dioxus_core::events::on::*;
match event.type_().as_str() {
"copy" | "cut" | "paste" => Arc::new(ClipboardEvent {}),
@@ -682,30 +694,40 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
use anyhow::Context;
let element_id = target
.get_attribute("dioxus-id")
.context("Could not find element id on event target")?
.parse()?;
// The error handling here is not very descriptive and needs to be replaced with a zero-cost error system
let val: String = target
.get_attribute(&format!("dioxus-event-{}", typ))
.get_attribute("dioxus-event")
.context(format!("wrong format - received {:#?}", typ))?;
// .get_attribute(&format!("dioxus-event-{}", typ))
// .context(format!("wrong format - received {:#?}", typ))?;
let mut fields = val.splitn(3, ".");
let gi_id = fields
.next()
.and_then(|f| f.parse::<u64>().ok())
.context("failed to parse gi id")?;
// let gi_id = fields
// .next()
// .and_then(|f| f.parse::<u64>().ok())
// .context("failed to parse gi id")?;
let real_id = fields
.next()
.and_then(|raw_id| raw_id.parse::<u64>().ok())
.context("failed to parse real id")?;
// let real_id = fields
// .next()
// .and_then(|raw_id| raw_id.parse::<u64>().ok())
// .context("failed to parse real id")?;
let triggered_scope = gi_id;
// let triggered_scope = gi_id;
Ok(UserEvent {
name: event_name_from_typ(&typ),
data: virtual_event_from_websys_event(event.clone()),
element: Some(ElementId(real_id as usize)),
scope_id: Some(ScopeId(triggered_scope as usize)),
element: Some(ElementId(element_id)),
scope_id: None,
// scope_id: Some(ScopeId(triggered_scope as usize)),
// element: Some(ElementId(real_id as usize)),
// scope_id: Some(ScopeId(triggered_scope as usize)),
priority: dioxus_core::EventPriority::Medium,
})
}
+9 -6
View File
@@ -85,7 +85,7 @@ mod ric_raf;
/// dioxus_web::launch(App, |c| c);
/// }
///
/// static App: FC<()> = |(cx, props)| {
/// static App: FC<()> = |cx, props| {
/// rsx!(cx, div {"hello world"})
/// }
/// ```
@@ -109,7 +109,7 @@ pub fn launch(root_component: FC<()>, configuration: impl FnOnce(WebConfig) -> W
/// name: String
/// }
///
/// static App: FC<RootProps> = |(cx, props)| {
/// static App: FC<RootProps> = |cx, props| {
/// rsx!(cx, div {"hello {props.name}"})
/// }
/// ```
@@ -155,7 +155,7 @@ pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg:
// hydrating is simply running the dom for a single render. If the page is already written, then the corresponding
// ElementIds should already line up because the web_sys dom has already loaded elements with the DioxusID into memory
if !should_hydrate {
log::info!("Applying rebuild edits..., {:?}", mutations);
// log::info!("Applying rebuild edits..., {:?}", mutations);
websys_dom.process_edits(&mut mutations.edits);
}
@@ -166,17 +166,20 @@ pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg:
// if there is work then this future resolves immediately.
dom.wait_for_work().await;
// wait for the mainthread to schedule us in
let mut deadline = work_loop.wait_for_idle_time().await;
// // wait for the mainthread to schedule us in
// let mut deadline = work_loop.wait_for_idle_time().await;
// run the virtualdom work phase until the frame deadline is reached
let mutations = dom.work_with_deadline(|| (&mut deadline).now_or_never().is_some());
let mutations = dom.work_with_deadline(|| false);
// // run the virtualdom work phase until the frame deadline is reached
// let mutations = dom.work_with_deadline(|| (&mut deadline).now_or_never().is_some());
// wait for the animation frame to fire so we can apply our changes
work_loop.wait_for_raf().await;
for mut edit in mutations {
// actually apply our changes during the animation frame
// log::info!("Applying change edits..., {:?}", edit);
websys_dom.process_edits(&mut edit.edits);
}
}