polish: examples

This commit is contained in:
Jonathan Kelley committed 2021-09-24 00:05:56 -04:00
1 parent 4b6ca05f2c
commit 1a2f91ed91
19 files changed
+327 -183

No files matched your search

+10 -4
View File
@@ -461,9 +461,10 @@ impl<'bump> DiffMachine<'bump> {
let mut please_commit = |edits: &mut Vec<DomEdit>| {
if !has_comitted {
has_comitted = true;
if let Some(root) = root {
edits.push(PushRoot { id: root.as_u64() });
}
log::info!("planning on committing... {:#?}, {:#?}", old, new);
edits.push(PushRoot {
id: root.unwrap().as_u64(),
});
}
};
@@ -475,7 +476,12 @@ impl<'bump> DiffMachine<'bump> {
// TODO: take a more efficient path than this
if old.attributes.len() == new.attributes.len() {
for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) {
if old_attr.value != new_attr.value || old_attr.is_volatile {
log::info!("checking attribute");
if old_attr.value != new_attr.value {
please_commit(&mut self.mutations.edits);
self.mutations.set_attribute(new_attr);
} else if new_attr.is_volatile {
log::debug!("setting due to volatile atttributes");
please_commit(&mut self.mutations.edits);
self.mutations.set_attribute(new_attr);
}
+39 -1
View File
@@ -264,8 +264,10 @@ pub mod on {
ClipboardEventInner(ClipboardEvent): [
/// Called when "copy"
oncopy
/// oncut
oncut
/// onpaste
onpaste
];
@@ -305,7 +307,7 @@ pub mod on {
/// onchange
onchange
/// oninput
/// oninput handler
oninput
/// oninvalid
@@ -446,22 +448,31 @@ pub mod on {
PointerEventInner(PointerEvent): [
/// pointerdown
onpointerdown
/// pointermove
onpointermove
/// pointerup
onpointerup
/// pointercancel
onpointercancel
/// gotpointercapture
ongotpointercapture
/// lostpointercapture
onlostpointercapture
/// pointerenter
onpointerenter
/// pointerleave
onpointerleave
/// pointerover
onpointerover
/// pointerout
onpointerout
];
@@ -474,10 +485,13 @@ pub mod on {
TouchEventInner(TouchEvent): [
/// ontouchcancel
ontouchcancel
/// ontouchend
ontouchend
/// ontouchmove
ontouchmove
/// ontouchstart
ontouchstart
];
@@ -490,48 +504,70 @@ pub mod on {
MediaEventInner(MediaEvent): [
///abort
onabort
///canplay
oncanplay
///canplaythrough
oncanplaythrough
///durationchange
ondurationchange
///emptied
onemptied
///encrypted
onencrypted
///ended
onended
///error
onerror
///loadeddata
onloadeddata
///loadedmetadata
onloadedmetadata
///loadstart
onloadstart
///pause
onpause
///play
onplay
///playing
onplaying
///progress
onprogress
///ratechange
onratechange
///seeked
onseeked
///seeking
onseeking
///stalled
onstalled
///suspend
onsuspend
///timeupdate
ontimeupdate
///volumechange
onvolumechange
///waiting
onwaiting
];
@@ -539,8 +575,10 @@ pub mod on {
AnimationEventInner(AnimationEvent): [
/// onanimationstart
onanimationstart
/// onanimationend
onanimationend
/// onanimationiteration
onanimationiteration
];
+15 -5
View File
@@ -197,6 +197,21 @@ pub struct VElement<'a> {
pub children: &'a [VNode<'a>],
}
impl Debug for VElement<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VElement")
.field("tag_name", &self.tag_name)
.field("namespace", &self.namespace)
.field("key", &self.key)
.field("dom_id", &self.dom_id)
.field("parent_id", &self.parent_id)
.field("listeners", &self.listeners.len())
.field("attributes", &self.attributes)
.field("children", &self.children)
.finish()
}
}
/// A trait for any generic Dioxus Element.
///
/// This trait provides the ability to use custom elements in the `rsx!` macro.
@@ -429,11 +444,6 @@ impl<'a> NodeFactory<'a> {
is_volatile: bool,
) -> Attribute<'a> {
let (value, is_static) = self.raw_text(val);
let is_volatile = match name {
"value" | "checked" | "selected" => true,
_ => false,
};
Attribute {
name,
value,
+16 -14
View File
@@ -72,6 +72,7 @@ use crate::heuristics::*;
use crate::innerlude::*;
use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
use futures_util::{pin_mut, stream::FuturesUnordered, Future, FutureExt, StreamExt};
use fxhash::FxHashMap;
use fxhash::FxHashSet;
use indexmap::IndexSet;
use slab::Slab;
@@ -357,6 +358,8 @@ impl Scheduler {
let shared = self.pool.clone();
let mut machine = unsafe { saved_state.promote(&shared) };
let mut ran_scopes = FxHashSet::default();
if machine.stack.is_empty() {
let shared = self.pool.clone();
@@ -367,11 +370,18 @@ impl Scheduler {
});
if let Some(scopeid) = self.dirty_scopes.pop() {
let component = self.pool.get_scope(scopeid).unwrap();
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
// let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
machine.stack.scope_stack.push(scopeid);
machine.stack.push(DiffInstruction::Diff { new, old });
log::info!("handlng dirty scope {:#?}", scopeid);
if !ran_scopes.contains(&scopeid) {
ran_scopes.insert(scopeid);
let mut component = self.pool.get_scope_mut(scopeid).unwrap();
if component.run_scope(&self.pool) {
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
// let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
machine.stack.scope_stack.push(scopeid);
machine.stack.push(DiffInstruction::Diff { new, old });
}
}
}
}
@@ -472,15 +482,7 @@ impl Scheduler {
while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
match dirty_scope {
SchedulerMsg::Immediate(im) => {
log::debug!("Handling immediate {:?}", im);
if let Some(scope) = self.pool.get_scope_mut(im) {
if scope.run_scope(&self.pool) {
self.dirty_scopes.insert(im);
} else {
todo!()
}
}
self.dirty_scopes.insert(im);
}
SchedulerMsg::UiEvent(e) => self.ui_events.push_back(e),
SchedulerMsg::Task(_) => todo!(),
-1
View File
@@ -3,7 +3,6 @@ use dioxus_core as dioxus;
use dioxus_html as dioxus_elements;
static Parent: FC<()> = |cx, props| {
//
let value = cx.use_hook(|_| String::new(), |f| &*f, |_| {});
cx.render(rsx! {
+2 -2
View File
@@ -49,9 +49,9 @@ use std::{
/// }
/// }
/// ```
pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T>(
pub fn use_state<'a, 'c, T: 'static>(
cx: Context<'a>,
initial_state_fn: F,
initial_state_fn: impl FnOnce() -> T,
) -> UseState<'a, T> {
cx.use_hook(
move |_| UseStateInner {
+1 -1
View File
@@ -6,7 +6,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus-core = { path="../core" }
dioxus-core = { path = "../core" }
[dev-dependencies]
scraper = "0.12.0"
+63 -4
View File
@@ -681,7 +681,10 @@ macro_rules! builder_constructors {
$(
$(#[$attr:meta])*
$name:ident {
$($fil:ident: $vil:ident,)*
$(
$(#[$attr_method:meta])*
$fil:ident: $vil:ident,
)*
};
)*
) => {
@@ -699,6 +702,7 @@ macro_rules! builder_constructors {
impl $name {
$(
$(#[$attr_method])*
pub fn $fil<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr(stringify!($fil), val, None, false)
}
@@ -1525,7 +1529,10 @@ builder_constructors! {
src: Uri,
step: String,
tabindex: usize,
r#type: InputType,
// This has a manual implementation below
// r#type: InputType,
value: String,
width: isize,
};
@@ -1570,7 +1577,10 @@ builder_constructors! {
option {
disabled: Bool,
label: String,
selected: Bool,
// defined below
// selected: Bool,
value: String,
};
@@ -1595,7 +1605,8 @@ builder_constructors! {
/// [`<select>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)
/// element.
select {
value: String,
// defined below
// value: String,
autocomplete: String,
autofocus: Bool,
disabled: Bool,
@@ -1656,6 +1667,54 @@ builder_constructors! {
template {};
}
impl input {
/// The type of input
///
/// Here are the different input types you can use in HTML:
///
/// - `button`
/// - `checkbox`
/// - `color`
/// - `date`
/// - `datetime-local`
/// - `email`
/// - `file`
/// - `hidden`
/// - `image`
/// - `month`
/// - `number`
/// - `password`
/// - `radio`
/// - `range`
/// - `reset`
/// - `search`
/// - `submit`
/// - `tel`
/// - `text`
/// - `time`
/// - `url`
/// - `week`
pub fn r#type<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr("type", val, None, false)
}
}
/*
volatile attributes
*/
impl select {
pub fn value<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr("value", val, None, true)
}
}
impl option {
fn selected<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr("selected", val, None, true)
}
}
pub trait SvgAttributes {
aria_trait_methods! {
accent_height: "accent-height",
+6
View File
@@ -0,0 +1,6 @@
# Known quirks for browsers and their workarounds
- text merging (solved through comment nodes)
- cursor jumping to end on inputs (not yet solved, solved in React already)
- SVG attributes cannot be set (solved using the correct method)
- volatile components
+6 -6
View File
@@ -11,7 +11,7 @@ license = "MIT/Apache-2.0"
dioxus-core = { path = "../core", version = "0.1.2" }
dioxus-html = { path = "../html" }
js-sys = "0.3"
wasm-bindgen = { version = "0.2.71", 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"
@@ -70,12 +70,12 @@ crate-type = ["cdylib", "rlib"]
[dev-dependencies]
im-rc = "15.0.0"
# rand = { version="0.8.4", features=["small_rng"] }
separator = "0.4.1"
uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] }
dioxus-hooks = { path = "../hooks" }
serde = { version = "1.0.126", features = ["derive"] }
surf = { git = "https://github.com/http-rs/surf", rev = "1ffaba8873", default-features = false, features = [
"wasm-client",
] }
# wasm-timer = "0.2.5"
# rand = { version="0.8.4", features=["small_rng"] }
# surf = { version = "2.3.1", default-features = false, features = [
# "wasm-client",
# ] }
+42 -22
View File
@@ -15,7 +15,7 @@ use std::{pin::Pin, time::Duration};
fn main() {
// Setup logging
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once();
// Run the app
@@ -24,32 +24,44 @@ fn main() {
static APP: FC<()> = |cx, props| {
let mut count = use_state(cx, || 3);
let mut content = use_state(cx, || String::from("h1"));
let mut text_content = use_state(cx, || String::from("Hello, world!"));
log::debug!("running scope...");
let mut content = use_state(cx, || String::new());
cx.render(rsx! {
div {
h1 { "content val is {content}" }
input {
value: "{content}"
oninput: move |e| {
content.set(e.value());
}
}
button {
onclick: move |_| count += 1,
"Click to add."
"Current count: {count}"
r#type: "text",
value: "{text_content}"
oninput: move |e| text_content.set(e.value())
}
br {}
{(0..10).map(|f| {
rsx!(
button {
onclick: move |_| count += 1,
"Click to add."
"Current count: {count}"
}
br {}
)
})}
select {
name: "cars"
id: "cars"
value: "h1"
value: "{content}"
oninput: move |ev| {
content.set(ev.value());
match ev.value().as_str() {
"h1" => count.set(0),
"h2" => count.set(5),
"h3" => count.set(10),
s => {}
_ => {}
}
},
@@ -58,14 +70,7 @@ static APP: FC<()> = |cx, props| {
option { value: "h3", "h3" }
}
ul {
{(0..*count).map(|f| rsx!{
li { "a - {f}" }
li { "b - {f}" }
li { "c - {f}" }
})}
}
{render_list(cx, *count)}
{render_bullets(cx)}
@@ -80,4 +85,19 @@ fn render_bullets(cx: Context) -> DomTree {
})
}
static Child: FC<()> = |cx, props| rsx!(cx, div {"hello child"});
fn render_list(cx: Context, count: usize) -> DomTree {
let items = (0..count).map(|f| {
rsx! {
li { "a - {f}" }
li { "b - {f}" }
li { "c - {f}" }
}
});
rsx!(cx, ul { {items} })
}
static Child: FC<()> = |cx, props| {
// render
rsx!(cx, div {"hello child"})
};
+1 -1
View File
@@ -24,7 +24,7 @@ fn main() {
dioxus_web::launch(App, |c| c)
}
static App: FC<()> = |cx, props|{
static App: FC<()> = |cx, props| {
let mut state = use_state(cx, || 0);
cx.render(rsx! {
div {
+11 -3
View File
@@ -314,12 +314,20 @@ impl WebsysDom {
}
}
if let Some(node) = node.dyn_ref::<HtmlInputElement>() {
if let Some(input) = node.dyn_ref::<HtmlInputElement>() {
if name == "value" {
node.set_value(value);
/*
if the attribute being set is the same as the value of the input, then don't bother setting it.
This is used in controlled components to keep the cursor in the right spot.
this logic should be moved into the virtualdom since we have the notion of "volatile"
*/
if input.value() != value {
input.set_value(value);
}
}
if name == "checked" {
node.set_checked(true);
input.set_checked(true);
}
}
+1
View File
@@ -156,6 +156,7 @@ pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T,
work_loop.wait_for_raf().await;
for mut edit in mutations {
log::debug!("edits are {:#?}", edit);
// actually apply our changes during the animation frame
websys_dom.process_edits(&mut edit.edits);
}
+16 -5
View File
@@ -4,7 +4,7 @@ use gloo_timers::future::TimeoutFuture;
use js_sys::Function;
use wasm_bindgen::JsCast;
use wasm_bindgen::{prelude::Closure, JsValue};
use web_sys::Window;
use web_sys::{window, Window};
pub struct RafLoop {
window: Window,
@@ -24,10 +24,21 @@ impl RafLoop {
let (ric_sender, ric_receiver) = async_channel::unbounded();
let ric_closure: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new(move |_v: JsValue| {
//
let deadline = _v.dyn_into::<web_sys::IdleDeadline>().unwrap();
let time_remaining = deadline.time_remaining() as u32;
let has_idle_callback = {
let bo = window().unwrap().dyn_into::<js_sys::Object>().unwrap();
bo.has_own_property(&JsValue::from_str("requestIdleCallback"))
};
let ric_closure: Closure<dyn Fn(JsValue)> = Closure::wrap(Box::new(move |v: JsValue| {
let time_remaining = if has_idle_callback {
if let Ok(deadline) = v.dyn_into::<web_sys::IdleDeadline>() {
deadline.time_remaining() as u32
} else {
10
}
} else {
10
};
ric_sender.try_send(time_remaining).unwrap()
}));