1
0
Эх сурвалжийг харах

improve ergonomics of custom drivers and add a counter example to rink

Evan Almloff 2 жил өмнө
parent
commit
ae1300b015

+ 4 - 4
packages/dioxus-tui/src/lib.rs

@@ -12,8 +12,8 @@ use dioxus_html::EventData;
 use dioxus_native_core::dioxus::{DioxusState, NodeImmutableDioxusExt};
 use dioxus_native_core::prelude::*;
 
-pub use rink::{query::Query, Config, Size, TuiContext, RenderingMode};
-use rink::{render, Renderer};
+pub use rink::{query::Query, Config, RenderingMode, Size, TuiContext};
+use rink::{render, Driver};
 
 pub fn launch(app: Component<()>) {
     launch_cfg(app, Config::default())
@@ -66,8 +66,8 @@ struct DioxusRenderer {
     hot_reload_rx: tokio::sync::mpsc::UnboundedReceiver<dioxus_hot_reload::HotReloadMsg>,
 }
 
-impl Renderer for DioxusRenderer {
-    fn render(&mut self, rdom: &Arc<RwLock<RealDom>>) {
+impl Driver for DioxusRenderer {
+    fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
         let muts = self.vdom.render_immediate();
         {
             let mut rdom = rdom.write().unwrap();

+ 48 - 0
packages/native-core/src/node.rs

@@ -62,6 +62,24 @@ pub struct OwnedAttributeDiscription {
     pub namespace: Option<String>,
 }
 
+impl From<String> for OwnedAttributeDiscription {
+    fn from(name: String) -> Self {
+        Self {
+            name,
+            namespace: None,
+        }
+    }
+}
+
+impl<S: Into<String>, N: Into<String>> From<(S, N)> for OwnedAttributeDiscription {
+    fn from(name: (S, N)) -> Self {
+        Self {
+            name: name.0.into(),
+            namespace: Some(name.1.into()),
+        }
+    }
+}
+
 /// An attribute on a DOM node, such as `id="my-thing"` or
 /// `href="https://example.com"`.
 #[derive(Clone, Copy, Debug)]
@@ -88,6 +106,36 @@ pub enum OwnedAttributeValue<V: FromAnyValue = ()> {
     Custom(V),
 }
 
+impl From<String> for OwnedAttributeValue {
+    fn from(value: String) -> Self {
+        Self::Text(value)
+    }
+}
+
+impl From<f64> for OwnedAttributeValue {
+    fn from(value: f64) -> Self {
+        Self::Float(value)
+    }
+}
+
+impl From<i64> for OwnedAttributeValue {
+    fn from(value: i64) -> Self {
+        Self::Int(value)
+    }
+}
+
+impl From<bool> for OwnedAttributeValue {
+    fn from(value: bool) -> Self {
+        Self::Bool(value)
+    }
+}
+
+impl<V: FromAnyValue> From<V> for OwnedAttributeValue<V> {
+    fn from(value: V) -> Self {
+        Self::Custom(value)
+    }
+}
+
 /// Something that can be converted from a borrowed [Any] value.
 pub trait FromAnyValue: Clone + 'static {
     /// Convert from an [Any] value.

+ 4 - 2
packages/native-core/src/real_dom.rs

@@ -933,9 +933,11 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
     /// Set an attribute in the element
     pub fn set_attribute(
         &mut self,
-        name: OwnedAttributeDiscription,
-        value: OwnedAttributeValue<V>,
+        name: impl Into<OwnedAttributeDiscription>,
+        value: impl Into<OwnedAttributeValue<V>>,
     ) -> Option<OwnedAttributeValue<V>> {
+        let name = name.into();
+        let value = value.into();
         self.dirty_nodes.mark_dirty(
             self.id,
             NodeMaskBuilder::new()

+ 104 - 0
packages/rink/examples/counter.rs

@@ -0,0 +1,104 @@
+use dioxus_html::EventData;
+use dioxus_native_core::{
+    node::TextNode,
+    prelude::*,
+    real_dom::{NodeImmutable, NodeTypeMut},
+    NodeId,
+};
+use rink::{render, Config, Driver};
+use std::rc::Rc;
+use std::sync::{Arc, RwLock};
+
+#[derive(Default)]
+struct Counter {
+    count: usize,
+    counter_id: NodeId,
+    button_id: NodeId,
+}
+
+impl Counter {
+    fn create(mut root: NodeMut) -> Self {
+        let mut myself = Self::default();
+
+        let root_id = root.id();
+        let rdom = root.real_dom_mut();
+
+        // create the counter
+        let count = myself.count;
+        myself.counter_id = rdom
+            .create_node(NodeType::Text(TextNode::new(count.to_string())))
+            .id();
+        let mut button = rdom.create_node(NodeType::Element(ElementNode {
+            tag: "div".to_string(),
+            attributes: [
+                ("display".to_string().into(), "flex".to_string().into()),
+                (
+                    ("background-color", "style").into(),
+                    format!("rgb({}, {}, {})", count * 10, 0, 0,).into(),
+                ),
+                (("width", "style").into(), "100%".to_string().into()),
+                (("height", "style").into(), "100%".to_string().into()),
+                (("flex-direction", "style").into(), "row".to_string().into()),
+                (
+                    ("justify-content", "style").into(),
+                    "center".to_string().into(),
+                ),
+                (("align-items", "style").into(), "center".to_string().into()),
+            ]
+            .into_iter()
+            .collect(),
+            ..Default::default()
+        }));
+        button.add_event_listener("click");
+        button.add_event_listener("wheel");
+        button.add_child(myself.counter_id);
+        myself.button_id = button.id();
+        rdom.get_mut(root_id).unwrap().add_child(myself.button_id);
+
+        myself
+    }
+}
+
+impl Driver for Counter {
+    fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
+        // update the counter
+        let mut rdom = rdom.write().unwrap();
+        let mut node = rdom.get_mut(self.button_id).unwrap();
+        if let NodeTypeMut::Element(mut el) = node.node_type_mut() {
+            el.set_attribute(
+                ("background-color", "style"),
+                format!("rgb({}, {}, {})", self.count * 10, 0, 0,),
+            );
+        }
+        let mut text = rdom.get_mut(self.counter_id).unwrap();
+        let type_mut = text.node_type_mut();
+        if let NodeTypeMut::Text(mut text) = type_mut {
+            *text = self.count.to_string();
+        }
+    }
+
+    fn handle_event(
+        &mut self,
+        _: &Arc<RwLock<RealDom>>,
+        _: NodeId,
+        _: &str,
+        _: Rc<EventData>,
+        _: bool,
+    ) {
+        // when a click or wheel event is fired, increment the counter
+        self.count += 1;
+    }
+
+    fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
+        Box::pin(async move { tokio::time::sleep(std::time::Duration::from_millis(1000)).await })
+    }
+}
+
+fn main() {
+    render(Config::new(), |rdom, _, _| {
+        let mut rdom = rdom.write().unwrap();
+        let root = rdom.root_id();
+        Counter::create(rdom.get_mut(root).unwrap())
+    })
+    .unwrap();
+}

+ 0 - 260
packages/rink/examples/driven.rs

@@ -1,260 +0,0 @@
-use dioxus_html::EventData;
-use dioxus_native_core::{
-    node::{OwnedAttributeDiscription, OwnedAttributeValue, TextNode},
-    prelude::*,
-    real_dom::{NodeImmutable, NodeTypeMut},
-    NodeId,
-};
-use dioxus_tui::{self, render, Config, Renderer};
-use rustc_hash::FxHashSet;
-use std::rc::Rc;
-use std::sync::{Arc, RwLock};
-
-const SIZE: usize = 10;
-
-struct Test {
-    node_states: [[usize; SIZE]; SIZE],
-    dirty: FxHashSet<(usize, usize)>,
-}
-
-impl Default for Test {
-    fn default() -> Self {
-        Self {
-            node_states: [[0; SIZE]; SIZE],
-            dirty: FxHashSet::default(),
-        }
-    }
-}
-
-impl Test {
-    fn create(mut root: NodeMut) -> Self {
-        let myself = Self::default();
-
-        // Set the root node to be a flexbox with a column direction.
-        if let NodeTypeMut::Element(mut el) = root.node_type_mut() {
-            el.set_attribute(
-                OwnedAttributeDiscription {
-                    name: "display".into(),
-                    namespace: None,
-                },
-                OwnedAttributeValue::Text("flex".into()),
-            );
-            el.set_attribute(
-                OwnedAttributeDiscription {
-                    name: "flex-direction".into(),
-                    namespace: None,
-                },
-                OwnedAttributeValue::Text("column".into()),
-            );
-            el.set_attribute(
-                OwnedAttributeDiscription {
-                    name: "width".into(),
-                    namespace: None,
-                },
-                OwnedAttributeValue::Text("100%".into()),
-            );
-            el.set_attribute(
-                OwnedAttributeDiscription {
-                    name: "height".into(),
-                    namespace: None,
-                },
-                OwnedAttributeValue::Text("100%".into()),
-            );
-        }
-
-        let root_id = root.id();
-        let rdom = root.real_dom_mut();
-
-        // create the grid
-        for (x, row) in myself.node_states.iter().copied().enumerate() {
-            let row_node = rdom
-                .create_node(NodeType::Element(ElementNode {
-                    tag: "div".to_string(),
-                    attributes: [
-                        (
-                            OwnedAttributeDiscription {
-                                name: "display".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("flex".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "flex-direction".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("row".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "width".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("100%".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "height".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("100%".into()),
-                        ),
-                    ]
-                    .into_iter()
-                    .collect(),
-                    ..Default::default()
-                }))
-                .id();
-            for (y, count) in row.iter().copied().enumerate() {
-                let node = rdom
-                    .create_node(NodeType::Text(TextNode::new(count.to_string())))
-                    .id();
-                let mut button = rdom.create_node(NodeType::Element(ElementNode {
-                    tag: "div".to_string(),
-                    attributes: [
-                        (
-                            OwnedAttributeDiscription {
-                                name: "background-color".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text(format!(
-                                "rgb({}, {}, {})",
-                                count * 10,
-                                0,
-                                (x + y) * 10,
-                            )),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "width".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("100%".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "height".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("100%".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "display".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("flex".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "flex-direction".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("row".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "justify-content".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("center".into()),
-                        ),
-                        (
-                            OwnedAttributeDiscription {
-                                name: "align-items".into(),
-                                namespace: None,
-                            },
-                            OwnedAttributeValue::Text("center".into()),
-                        ),
-                    ]
-                    .into_iter()
-                    .collect(),
-                    ..Default::default()
-                }));
-                button.add_event_listener("click");
-                button.add_event_listener("wheel");
-                button.add_child(node);
-                let button_id = button.id();
-                rdom.get_mut(row_node).unwrap().add_child(button_id);
-            }
-            rdom.get_mut(root_id).unwrap().add_child(row_node);
-        }
-        myself
-    }
-}
-
-impl Renderer for Test {
-    fn render(&mut self, rdom: &Arc<RwLock<RealDom>>) {
-        let mut rdom = rdom.write().unwrap();
-        let root_id = rdom.root_id();
-        let mut root = rdom.get_mut(root_id).unwrap();
-        for (x, y) in self.dirty.drain() {
-            let row_id = root.child_ids()[x];
-            let rdom = root.real_dom_mut();
-            let row = rdom.get(row_id).unwrap();
-            let node_id = row.child_ids()[y];
-            let mut node = rdom.get_mut(node_id).unwrap();
-            if let NodeTypeMut::Element(mut el) = node.node_type_mut() {
-                el.set_attribute(
-                    OwnedAttributeDiscription {
-                        name: "background-color".into(),
-                        namespace: None,
-                    },
-                    OwnedAttributeValue::Text(format!(
-                        "rgb({}, {}, {})",
-                        self.node_states[x][y] * 10,
-                        0,
-                        (x + y) * 10,
-                    )),
-                );
-            }
-            let text_id = *node.child_ids().first().unwrap();
-            let mut text = rdom.get_mut(text_id).unwrap();
-            let type_mut = text.node_type_mut();
-            if let NodeTypeMut::Text(mut text) = type_mut {
-                *text = self.node_states[x][y].to_string();
-            }
-        }
-    }
-
-    fn handle_event(
-        &mut self,
-        rdom: &Arc<RwLock<RealDom>>,
-        id: NodeId,
-        _: &str,
-        _: Rc<EventData>,
-        _: bool,
-    ) {
-        let rdom = rdom.read().unwrap();
-        let node = rdom.get(id).unwrap();
-        if let Some(parent) = node.parent() {
-            let child_number = parent
-                .child_ids()
-                .iter()
-                .position(|id| *id == node.id())
-                .unwrap();
-            if let Some(parents_parent) = parent.parent() {
-                let parents_child_number = parents_parent
-                    .child_ids()
-                    .iter()
-                    .position(|id| *id == parent.id())
-                    .unwrap();
-                self.node_states[parents_child_number][child_number] += 1;
-                self.dirty.insert((parents_child_number, child_number));
-            }
-        }
-    }
-
-    fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
-        Box::pin(async move { tokio::time::sleep(std::time::Duration::from_millis(1000)).await })
-    }
-}
-
-fn main() {
-    render(Config::new(), |rdom, _, _| {
-        let mut rdom = rdom.write().unwrap();
-        let root = rdom.root_id();
-        Test::create(rdom.get_mut(root).unwrap())
-    })
-    .unwrap();
-}

+ 173 - 0
packages/rink/examples/grid.rs

@@ -0,0 +1,173 @@
+use dioxus_html::EventData;
+use dioxus_native_core::{
+    node::TextNode,
+    prelude::*,
+    real_dom::{NodeImmutable, NodeTypeMut},
+    NodeId,
+};
+use rink::{render, Config, Driver};
+use rustc_hash::FxHashSet;
+use std::rc::Rc;
+use std::sync::{Arc, RwLock};
+
+const SIZE: usize = 20;
+
+#[derive(Default, Clone, Copy)]
+struct Node {
+    container_id: Option<NodeId>,
+    text_id: Option<NodeId>,
+    count: usize,
+}
+
+struct Test {
+    node_states: [[Node; SIZE]; SIZE],
+    dirty: FxHashSet<(usize, usize)>,
+}
+
+impl Default for Test {
+    fn default() -> Self {
+        Self {
+            node_states: [[Node {
+                container_id: None,
+                text_id: None,
+                count: 0,
+            }; SIZE]; SIZE],
+            dirty: FxHashSet::default(),
+        }
+    }
+}
+
+impl Test {
+    fn create(mut root: NodeMut) -> Self {
+        let mut myself = Self::default();
+
+        // Set the root node to be a flexbox with a column direction.
+        if let NodeTypeMut::Element(mut el) = root.node_type_mut() {
+            el.set_attribute("display".to_string(), "flex".to_string());
+            el.set_attribute(("flex-direction", "style"), "column".to_string());
+            el.set_attribute(("width", "style"), "100%".to_string());
+            el.set_attribute(("height", "style"), "100%".to_string());
+        }
+
+        let root_id = root.id();
+        let rdom = root.real_dom_mut();
+
+        // create the grid
+        for (x, row) in myself.node_states.iter_mut().enumerate() {
+            let row_node = rdom
+                .create_node(NodeType::Element(ElementNode {
+                    tag: "div".to_string(),
+                    attributes: [
+                        ("display".to_string().into(), "flex".to_string().into()),
+                        (("flex-direction", "style").into(), "row".to_string().into()),
+                        (("width", "style").into(), "100%".to_string().into()),
+                        (("height", "style").into(), "100%".to_string().into()),
+                    ]
+                    .into_iter()
+                    .collect(),
+                    ..Default::default()
+                }))
+                .id();
+            for (y, node) in row.iter_mut().enumerate() {
+                let count = node.count;
+                let id = rdom
+                    .create_node(NodeType::Text(TextNode::new(count.to_string())))
+                    .id();
+                let mut button = rdom.create_node(NodeType::Element(ElementNode {
+                    tag: "div".to_string(),
+                    attributes: [
+                        ("display".to_string().into(), "flex".to_string().into()),
+                        (
+                            ("background-color", "style").into(),
+                            format!("rgb({}, {}, {})", count * 10, 0, (x + y),).into(),
+                        ),
+                        (("width", "style").into(), "100%".to_string().into()),
+                        (("height", "style").into(), "100%".to_string().into()),
+                        (("flex-direction", "style").into(), "row".to_string().into()),
+                        (
+                            ("justify-content", "style").into(),
+                            "center".to_string().into(),
+                        ),
+                        (("align-items", "style").into(), "center".to_string().into()),
+                    ]
+                    .into_iter()
+                    .collect(),
+                    ..Default::default()
+                }));
+                button.add_event_listener("click");
+                button.add_event_listener("wheel");
+                button.add_child(id);
+                let button_id = button.id();
+                rdom.get_mut(row_node).unwrap().add_child(button_id);
+                node.container_id = Some(button_id);
+                node.text_id = Some(id);
+            }
+            rdom.get_mut(root_id).unwrap().add_child(row_node);
+        }
+        myself
+    }
+}
+
+impl Driver for Test {
+    fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
+        let mut rdom = rdom.write().unwrap();
+        for (x, y) in self.dirty.drain() {
+            let node = self.node_states[x][y];
+            let node_id = node.container_id.unwrap();
+            let mut container = rdom.get_mut(node_id).unwrap();
+            if let NodeTypeMut::Element(mut el) = container.node_type_mut() {
+                el.set_attribute(
+                    ("background-color", "style"),
+                    format!("rgb({}, {}, {})", node.count * 10, 0, (x + y),),
+                );
+            }
+            let text_id = node.text_id.unwrap();
+            let mut text = rdom.get_mut(text_id).unwrap();
+            let type_mut = text.node_type_mut();
+            if let NodeTypeMut::Text(mut text) = type_mut {
+                *text = node.count.to_string();
+            }
+        }
+    }
+
+    fn handle_event(
+        &mut self,
+        rdom: &Arc<RwLock<RealDom>>,
+        id: NodeId,
+        _: &str,
+        _: Rc<EventData>,
+        _: bool,
+    ) {
+        let rdom = rdom.read().unwrap();
+        let node = rdom.get(id).unwrap();
+        if let Some(parent) = node.parent() {
+            let child_number = parent
+                .child_ids()
+                .iter()
+                .position(|id| *id == node.id())
+                .unwrap();
+            if let Some(parents_parent) = parent.parent() {
+                let parents_child_number = parents_parent
+                    .child_ids()
+                    .iter()
+                    .position(|id| *id == parent.id())
+                    .unwrap();
+                self.node_states[parents_child_number][child_number].count += 1;
+                self.dirty.insert((parents_child_number, child_number));
+            }
+        }
+    }
+
+    fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
+        Box::pin(async move { tokio::time::sleep(std::time::Duration::from_millis(1000)).await })
+    }
+}
+
+fn main() {
+    render(Config::new(), |rdom, _, _| {
+        let mut rdom = rdom.write().unwrap();
+        let root = rdom.root_id();
+        Test::create(rdom.get_mut(root).unwrap())
+    })
+    .unwrap();
+}

+ 0 - 93
packages/rink/examples/widgets.rs

@@ -1,93 +0,0 @@
-use dioxus::prelude::*;
-use dioxus_html::FormData;
-use dioxus_tui::prelude::*;
-use dioxus_tui::Config;
-
-fn main() {
-    dioxus_tui::launch_cfg(app, Config::new());
-}
-
-fn app(cx: Scope) -> Element {
-    let bg_green = use_state(cx, || false);
-
-    let color = if *bg_green.get() { "green" } else { "red" };
-    cx.render(rsx! {
-        div{
-            width: "100%",
-            background_color: "{color}",
-            flex_direction: "column",
-            align_items: "center",
-            justify_content: "center",
-
-            Input{
-                oninput: |data: FormData| if &data.value == "good"{
-                    bg_green.set(true);
-                } else{
-                    bg_green.set(false);
-                },
-                r#type: "checkbox",
-                value: "good",
-                width: "50%",
-                height: "10%",
-                checked: "true",
-            }
-            Input{
-                oninput: |data: FormData| if &data.value == "hello world"{
-                    bg_green.set(true);
-                } else{
-                    bg_green.set(false);
-                },
-                width: "50%",
-                height: "10%",
-                maxlength: "11",
-            }
-            Input{
-                oninput: |data: FormData| {
-                    if (data.value.parse::<f32>().unwrap() - 40.0).abs() < 5.0 {
-                        bg_green.set(true);
-                    } else{
-                        bg_green.set(false);
-                    }
-                },
-                r#type: "range",
-                width: "50%",
-                height: "10%",
-                min: "20",
-                max: "80",
-            }
-            Input{
-                oninput: |data: FormData| {
-                    if data.value == "10"{
-                        bg_green.set(true);
-                    } else{
-                        bg_green.set(false);
-                    }
-                },
-                r#type: "number",
-                width: "50%",
-                height: "10%",
-                maxlength: "4",
-            }
-            Input{
-                oninput: |data: FormData| {
-                    if data.value == "hello world"{
-                        bg_green.set(true);
-                    } else{
-                        bg_green.set(false);
-                    }
-                },
-                r#type: "password",
-                width: "50%",
-                height: "10%",
-                maxlength: "11",
-            }
-            Input{
-                onclick: |_: FormData| bg_green.set(true),
-                r#type: "button",
-                value: "green",
-                width: "50%",
-                height: "10%",
-            }
-        }
-    })
-}

+ 5 - 5
packages/rink/src/lib.rs

@@ -76,7 +76,7 @@ impl TuiContext {
     }
 }
 
-pub fn render<R: Renderer>(
+pub fn render<R: Driver>(
     cfg: Config,
     create_renderer: impl FnOnce(
         &Arc<RwLock<RealDom>>,
@@ -115,7 +115,7 @@ pub fn render<R: Renderer>(
     let mut renderer = create_renderer(&rdom, &taffy, event_tx_clone);
 
     {
-        renderer.render(&rdom);
+        renderer.update(&rdom);
         let mut any_map = SendAnyMap::new();
         any_map.insert(taffy.clone());
         let mut rdom = rdom.write().unwrap();
@@ -261,7 +261,7 @@ pub fn render<R: Renderer>(
                         }
                     }
                     // updates the dom's nodes
-                    renderer.render(&rdom);
+                    renderer.update(&rdom);
                     // update the style and layout
                     let mut rdom = rdom.write().unwrap();
                     let mut any_map = SendAnyMap::new();
@@ -297,8 +297,8 @@ pub enum InputEvent {
     Close,
 }
 
-pub trait Renderer {
-    fn render(&mut self, rdom: &Arc<RwLock<RealDom>>);
+pub trait Driver {
+    fn update(&mut self, rdom: &Arc<RwLock<RealDom>>);
     fn handle_event(
         &mut self,
         rdom: &Arc<RwLock<RealDom>>,