diff --git a/examples/assets/todomvc.css b/examples/assets/todomvc.css index f9076525c..c928424af 100644 --- a/examples/assets/todomvc.css +++ b/examples/assets/todomvc.css @@ -1,5 +1,5 @@ html, -body { +body, pre { margin: 0; padding: 0; } diff --git a/examples/todomvc.rs b/examples/todomvc.rs index b41adc5f0..8adb01d34 100644 --- a/examples/todomvc.rs +++ b/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), + _ => {} + } + }, + } + }) }) } diff --git a/packages/desktop/src/events.rs b/packages/desktop/src/events.rs index 026b543c8..760bf7662 100644 --- a/packages/desktop/src/events.rs +++ b/packages/desktop/src/events.rs @@ -52,7 +52,7 @@ fn make_synthetic_event(name: &str, val: serde_json::Value) -> Arc(val).unwrap(); Arc::new(evt) } - "focus" | "blur" => { + "focus" | "blur" | "focusout" | "focusin" => { // Arc::new(FocusData {}) } @@ -117,6 +117,8 @@ fn event_name_from_typ(typ: &str) -> &'static str { "keypress" => "keypress", "keyup" => "keyup", "focus" => "focus", + "focusout" => "focusout", + "focusin" => "focusin", "blur" => "blur", "change" => "change", "input" => "input", diff --git a/packages/html/src/events.rs b/packages/html/src/events.rs index 7e5e95372..b9bcecd4f 100644 --- a/packages/html/src/events.rs +++ b/packages/html/src/events.rs @@ -91,6 +91,12 @@ pub mod on { /// onfocus onfocus + // onfocusout + onfocusout + + // onfocusin + onfocusin + /// onblur onblur ]; @@ -1092,7 +1098,7 @@ pub(crate) fn _event_meta(event: &UserEvent) -> (bool, EventPriority) { "keydown" | "keypress" | "keyup" => (true, High), // Focus - "focus" | "blur" => (true, Low), + "focus" | "blur" | "focusout" | "focusin" => (true, Low), // Form "change" | "input" | "invalid" | "reset" | "submit" => (true, Medium), diff --git a/packages/web/src/cache.rs b/packages/web/src/cache.rs index 8beb58f18..190b505c1 100644 --- a/packages/web/src/cache.rs +++ b/packages/web/src/cache.rs @@ -203,6 +203,8 @@ pub static BUILTIN_INTERNED_STRINGS: &[&'static str] = &[ "onended", "onerror", "onfocus", + "onfocusout", + "onfocusin", "onhashchange", "oninput", "oninvalid",