Browse Source

feat(example:todomvc): add editing support

- implement "onfocusout" handler
- set autofocus
- handle enter, escape and tab on a todo item
- make the `<pre>` element between todo list items of margin 0 to be unnoticable
Sven Assmann 3 năm trước cách đây
mục cha
commit
9849f68f25

+ 1 - 1
examples/assets/todomvc.css

@@ -1,5 +1,5 @@
 html,
-body {
+body, pre {
     margin: 0;
     padding: 0;
 }

+ 19 - 7
examples/todomvc.rs

@@ -116,8 +116,12 @@ pub fn todo_entry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
     let todo = &cx.props.todos[&cx.props.id];
     let is_editing = use_state(&cx, || false);
     let completed = if todo.checked { "completed" } else { "" };
+    let editing = if *is_editing.get() { "editing" } else { "" };
 
-    rsx!(cx, li { class: "{completed}",
+    rsx!(cx, li {
+        class: "{completed} {editing}",
+        onclick: move |_| is_editing.set(true),
+        onfocusout: move |_| is_editing.set(false),
         div { class: "view",
             input { class: "toggle", r#type: "checkbox", id: "cbg-{todo.id}", checked: "{todo.checked}",
                 onchange: move |evt| {
@@ -125,12 +129,20 @@ pub fn todo_entry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
                 }
             }
             label { r#for: "cbg-{todo.id}", pointer_events: "none", "{todo.contents}" }
-            is_editing.then(|| rsx!{
-                input {
-                    value: "{todo.contents}",
-                    oninput: move |evt| cx.props.todos.modify()[&cx.props.id].contents = evt.value.clone(),
-                }
-            })
         }
+        is_editing.then(|| rsx!{
+            input {
+                class: "edit",
+                value: "{todo.contents}",
+                oninput: move |evt| cx.props.todos.modify()[&cx.props.id].contents = evt.value.clone(),
+                autofocus: "true",
+                onkeydown: move |evt| {
+                    match evt.key.as_str() {
+                        "Enter" | "Escape" | "Tab" => is_editing.set(false),
+                        _ => {}
+                    }
+                },
+            }
+        })
     })
 }

+ 2 - 1
packages/desktop/src/events.rs

@@ -52,7 +52,7 @@ fn make_synthetic_event(name: &str, val: serde_json::Value) -> Arc<dyn Any + Sen
             let evt = serde_json::from_value::<KeyboardData>(val).unwrap();
             Arc::new(evt)
         }
-        "focus" | "blur" => {
+        "focus" | "blur" | "focusout" => {
             //
             Arc::new(FocusData {})
         }
@@ -117,6 +117,7 @@ fn event_name_from_typ(typ: &str) -> &'static str {
         "keypress" => "keypress",
         "keyup" => "keyup",
         "focus" => "focus",
+        "focusout" => "focusout",
         "blur" => "blur",
         "change" => "change",
         "input" => "input",

+ 4 - 1
packages/html/src/events.rs

@@ -91,6 +91,9 @@ pub mod on {
             /// onfocus
             onfocus
 
+            // onfocusout
+            onfocusout
+
             /// onblur
             onblur
         ];
@@ -1092,7 +1095,7 @@ pub(crate) fn _event_meta(event: &UserEvent) -> (bool, EventPriority) {
         "keydown" | "keypress" | "keyup" => (true, High),
 
         // Focus
-        "focus" | "blur" => (true, Low),
+        "focus" | "blur" | "focusout" => (true, Low),
 
         // Form
         "change" | "input" | "invalid" | "reset" | "submit" => (true, Medium),

+ 1 - 0
packages/web/src/cache.rs

@@ -203,6 +203,7 @@ pub static BUILTIN_INTERNED_STRINGS: &[&'static str] = &[
     "onended",
     "onerror",
     "onfocus",
+    "onfocusout",
     "onhashchange",
     "oninput",
     "oninvalid",